From 9975dd9ebfefa0191d8a82df9b524cf6187e6872 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 3 Oct 2020 13:33:16 +0200 Subject: [PATCH 001/395] JAVA-2887: Handle composite profiles with more than one key and/or backed by only one profile Composite profiles with more than one key currently throw ClassCastException from CompositeDriverExecutionProfile.entrySet. Composite profiles backed by only one profile currently throw NullPointerException from CompositeDriverExecutionProfile.entrySet. --- changelog/README.md | 1 + .../CompositeDriverExecutionProfile.java | 41 ++++++++++++++----- .../composite/CompositeDriverConfigTest.java | 29 +++++++++++++ 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index ae4f025419d..f949a0e6201 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2887: Handle composite profiles with more than one key and/or backed by only one profile ### 4.9.0 diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverExecutionProfile.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverExecutionProfile.java index 5d7df7b417f..c9ce0205ccb 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverExecutionProfile.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverExecutionProfile.java @@ -21,6 +21,7 @@ import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSortedSet; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Duration; import java.util.List; import java.util.Map; @@ -35,8 +36,8 @@ public class CompositeDriverExecutionProfile implements DriverExecutionProfile { private final DriverConfig fallbackConfig; private final String profileName; - private volatile DriverExecutionProfile primaryProfile; - private volatile DriverExecutionProfile fallbackProfile; + @Nullable private volatile DriverExecutionProfile primaryProfile; + @Nullable private volatile DriverExecutionProfile fallbackProfile; public CompositeDriverExecutionProfile( @NonNull DriverConfig primaryConfig, @@ -89,8 +90,13 @@ public String getName() { @Override public boolean isDefined(@NonNull DriverOption option) { - return (primaryProfile != null && primaryProfile.isDefined(option)) - || (fallbackProfile != null && fallbackProfile.isDefined(option)); + DriverExecutionProfile primaryProfile = this.primaryProfile; + if (primaryProfile != null && primaryProfile.isDefined(option)) { + return true; + } else { + DriverExecutionProfile fallbackProfile = this.fallbackProfile; + return fallbackProfile != null && fallbackProfile.isDefined(option); + } } @Override @@ -181,21 +187,34 @@ public List getDurationList(@NonNull DriverOption option) { private ValueT get( @NonNull DriverOption option, BiFunction getter) { + DriverExecutionProfile primaryProfile = this.primaryProfile; if (primaryProfile != null && primaryProfile.isDefined(option)) { return getter.apply(primaryProfile, option); - } else if (fallbackProfile != null && fallbackProfile.isDefined(option)) { - return getter.apply(fallbackProfile, option); } else { - throw new IllegalArgumentException("Unknown option: " + option); + DriverExecutionProfile fallbackProfile = this.fallbackProfile; + if (fallbackProfile != null && fallbackProfile.isDefined(option)) { + return getter.apply(fallbackProfile, option); + } else { + throw new IllegalArgumentException("Unknown option: " + option); + } } } @NonNull @Override public SortedSet> entrySet() { - SortedSet> result = new TreeSet<>(Map.Entry.comparingByKey()); - result.addAll(fallbackProfile.entrySet()); - result.addAll(primaryProfile.entrySet()); - return ImmutableSortedSet.copyOf(result); + DriverExecutionProfile primaryProfile = this.primaryProfile; + DriverExecutionProfile fallbackProfile = this.fallbackProfile; + if (primaryProfile != null && fallbackProfile != null) { + SortedSet> result = new TreeSet<>(Map.Entry.comparingByKey()); + result.addAll(fallbackProfile.entrySet()); + result.addAll(primaryProfile.entrySet()); + return ImmutableSortedSet.copyOf(Map.Entry.comparingByKey(), result); + } else if (primaryProfile != null) { + return primaryProfile.entrySet(); + } else { + assert fallbackProfile != null; + return fallbackProfile.entrySet(); + } } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigTest.java index 1c6121b1121..0c456e5e1bb 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigTest.java @@ -16,7 +16,9 @@ package com.datastax.oss.driver.internal.core.config.composite; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; @@ -59,6 +61,10 @@ public void should_use_value_from_primary_config() { .isTrue(); assertThat(compositeDefaultProfile.getInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE)) .isEqualTo(1); + assertThat(compositeDefaultProfile.entrySet()) + .containsExactly( + entry(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE.getPath(), 1), + entry(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES.getPath(), 1)); } @Test @@ -70,6 +76,10 @@ public void should_ignore_value_from_fallback_config_if_defined_in_both() { .isTrue(); assertThat(compositeDefaultProfile.getInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE)) .isEqualTo(1); + assertThat(compositeDefaultProfile.entrySet()) + .containsExactly( + entry(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE.getPath(), 1), + entry(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES.getPath(), 1)); } @Test @@ -80,6 +90,10 @@ public void should_use_value_from_fallback_config_if_not_defined_in_primary() { .isTrue(); assertThat(compositeDefaultProfile.getInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE)) .isEqualTo(1); + assertThat(compositeDefaultProfile.entrySet()) + .containsExactly( + entry(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE.getPath(), 1), + entry(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES.getPath(), 1)); } @Test @@ -112,5 +126,20 @@ public void should_merge_profiles() { .getProfile("onlyInFallback") .getInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE)) .isEqualTo(4); + + assertThat(compositeConfig.getProfile("onlyInPrimary").entrySet()) + .containsExactly( + entry(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE.getPath(), 1), + entry(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES.getPath(), 1)); + + assertThat(compositeConfig.getProfile("inBoth").entrySet()) + .containsExactly( + entry(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE.getPath(), 2), + entry(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES.getPath(), 1)); + + assertThat(compositeConfig.getProfile("onlyInFallback").entrySet()) + .containsExactly( + entry(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE.getPath(), 4), + entry(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES.getPath(), 1)); } } From c8e7fc8e402a75c6d437b3b030555121b2092918 Mon Sep 17 00:00:00 2001 From: Olivier Michallat Date: Tue, 13 Oct 2020 03:32:10 -0700 Subject: [PATCH 002/395] JAVA-2647: Handle token types in QueryBuilder.literal() (#1501) --- changelog/README.md | 1 + .../driver/api/querybuilder/QueryBuilder.java | 15 +++++ .../api/querybuilder/TokenLiteralTest.java | 58 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/TokenLiteralTest.java diff --git a/changelog/README.md b/changelog/README.md index f949a0e6201..197588a2056 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2647: Handle token types in QueryBuilder.literal() - [bug] JAVA-2887: Handle composite profiles with more than one key and/or backed by only one profile ### 4.9.0 diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/QueryBuilder.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/QueryBuilder.java index 6a42f1d0369..73f466e0637 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/QueryBuilder.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/QueryBuilder.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.metadata.token.Token; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.UserDefinedType; @@ -32,6 +33,9 @@ import com.datastax.oss.driver.api.querybuilder.truncate.Truncate; import com.datastax.oss.driver.api.querybuilder.update.UpdateStart; import com.datastax.oss.driver.internal.core.metadata.schema.ShallowUserDefinedType; +import com.datastax.oss.driver.internal.core.metadata.token.ByteOrderedToken; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; import com.datastax.oss.driver.internal.querybuilder.ArithmeticOperator; import com.datastax.oss.driver.internal.querybuilder.DefaultLiteral; import com.datastax.oss.driver.internal.querybuilder.DefaultRaw; @@ -402,6 +406,15 @@ public static Literal literal(@Nullable Object value) { */ @NonNull public static Literal literal(@Nullable Object value, @NonNull CodecRegistry codecRegistry) { + if (value instanceof Murmur3Token) { + value = ((Murmur3Token) value).getValue(); + } else if (value instanceof ByteOrderedToken) { + value = ((ByteOrderedToken) value).getValue(); + } else if (value instanceof RandomToken) { + value = ((RandomToken) value).getValue(); + } else if (value instanceof Token) { + throw new IllegalArgumentException("Unsupported token type: " + value.getClass().getName()); + } try { return literal(value, (value == null) ? null : codecRegistry.codecFor(value)); } catch (CodecNotFoundException e) { @@ -424,6 +437,8 @@ public static Literal literal(@Nullable Object value, @NonNull CodecRegistry cod */ @NonNull public static Literal literal(@Nullable T value, @Nullable TypeCodec codec) { + // Don't handle Token here, if the user calls this directly we assume they passed a codec that + // can handle the value return new DefaultLiteral<>(value, codec); } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/TokenLiteralTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/TokenLiteralTest.java new file mode 100644 index 00000000000..ff14dcffe7b --- /dev/null +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/TokenLiteralTest.java @@ -0,0 +1,58 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.querybuilder; + +import static com.datastax.oss.driver.api.querybuilder.Assertions.assertThat; +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom; + +import com.datastax.oss.driver.internal.core.metadata.token.ByteOrderedTokenFactory; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3TokenFactory; +import com.datastax.oss.driver.internal.core.metadata.token.RandomTokenFactory; +import org.junit.Test; + +public class TokenLiteralTest { + + @Test + public void should_inline_murmur3_token_literal() { + assertThat( + selectFrom("test") + .all() + .whereToken("pk") + .isEqualTo(literal(Murmur3TokenFactory.MIN_TOKEN))) + .hasCql("SELECT * FROM test WHERE token(pk)=-9223372036854775808"); + } + + @Test + public void should_inline_byte_ordered_token_literal() { + assertThat( + selectFrom("test") + .all() + .whereToken("pk") + .isEqualTo(literal(ByteOrderedTokenFactory.MIN_TOKEN))) + .hasCql("SELECT * FROM test WHERE token(pk)=0x"); + } + + @Test + public void should_inline_random_token_literal() { + assertThat( + selectFrom("test") + .all() + .whereToken("pk") + .isEqualTo(literal(RandomTokenFactory.MIN_TOKEN))) + .hasCql("SELECT * FROM test WHERE token(pk)=-1"); + } +} From cefb914b6f78712da6bc88e0d0bcd2ead5281830 Mon Sep 17 00:00:00 2001 From: Sarvesh Kaushal Date: Tue, 13 Oct 2020 03:33:05 -0700 Subject: [PATCH 003/395] Removing unnecessary cast to String (#1503) --- .../oss/driver/internal/core/type/codec/BigIntCodecTest.java | 2 +- .../oss/driver/internal/core/type/codec/CounterCodecTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodecTest.java index a2d7fd91ee0..1dfefbdebdd 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodecTest.java @@ -67,7 +67,7 @@ public void should_fail_to_parse_invalid_input() { @Test(expected = IllegalArgumentException.class) public void should_fail_to_parse_if_out_of_range() { - parse(Long.toString(Long.MAX_VALUE) + "0"); + parse(Long.MAX_VALUE + "0"); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CounterCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CounterCodecTest.java index 70dbd91c305..bd74fec9c72 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CounterCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CounterCodecTest.java @@ -67,7 +67,7 @@ public void should_fail_to_parse_invalid_input() { @Test(expected = IllegalArgumentException.class) public void should_fail_to_parse_if_out_of_range() { - parse(Long.toString(Long.MAX_VALUE) + "0"); + parse(Long.MAX_VALUE + "0"); } @Test From bf89221cbbcbf828378a43e21187f0ac1476a9fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Nov 2020 16:31:02 +0100 Subject: [PATCH 004/395] Bump junit from 4.12 to 4.13.1 (#1506) Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 823d979fbab..437ef30d7d2 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 3.13.1 1.3 - 4.12 + 4.13.1 1.2.3 6.0.0 6.0.3 From d68e0f85d2b7e102d52dae42da2e17e72c024f33 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 19 Nov 2020 23:26:27 +0100 Subject: [PATCH 005/395] Make LazyReference.lock final --- .../oss/driver/internal/core/util/concurrent/LazyReference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/LazyReference.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/LazyReference.java index b1d34dda6ea..ffa0a16fcb6 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/LazyReference.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/LazyReference.java @@ -27,7 +27,7 @@ public class LazyReference { private final Supplier supplier; private final CycleDetector checker; private volatile T value; - private ReentrantLock lock = new ReentrantLock(); + private final ReentrantLock lock = new ReentrantLock(); public LazyReference(String name, Supplier supplier, CycleDetector cycleDetector) { this.name = name; From d585dad986ec9d6c849a665d47e2e0fffd1f6cd1 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 26 Nov 2020 12:10:48 +0100 Subject: [PATCH 006/395] JAVA-2905: Prevent new connections from using a protocol version higher than the negotiated one --- changelog/README.md | 1 + .../oss/driver/internal/core/session/DefaultSession.java | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 197588a2056..9ddce319d39 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [improvement] JAVA-2905: Prevent new connections from using a protocol version higher than the negotiated one - [bug] JAVA-2647: Handle token types in QueryBuilder.literal() - [bug] JAVA-2887: Handle composite profiles with more than one key and/or backed by only one profile diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java index 67b203b3724..b12c287ca60 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java @@ -403,7 +403,7 @@ private void afterInitialNodeListRefresh(CqlIdentifier keyspace) { context .getProtocolVersionRegistry() .highestCommon(metadataManager.getMetadata().getNodes().values()); - if (!currentVersion.equals(bestVersion)) { + if (bestVersion.getCode() < currentVersion.getCode()) { LOG.info( "[{}] Negotiated protocol version {} for the initial contact point, " + "but other nodes only support {}, downgrading", @@ -417,6 +417,13 @@ private void afterInitialNodeListRefresh(CqlIdentifier keyspace) { // of the control queries use any protocol-dependent feature. // Keep going as-is, the control connection might switch to the "correct" version later // if it reconnects to another node. + } else if (bestVersion.getCode() > currentVersion.getCode()) { + LOG.info( + "[{}] Negotiated protocol version {} for the initial contact point, " + + "but cluster seems to support {}, keeping the negotiated version", + logPrefix, + currentVersion, + bestVersion); } } metadataManager From a0e4cced158538a4a444792a2e1e5cd5c3df68b9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 26 Nov 2020 15:07:11 +0100 Subject: [PATCH 007/395] Remove occurrences of org.junit.rules.ExpectedException --- .../TinkerpopBufferPrimitiveCodecTest.java | 33 ++++------ .../typesafe/TypesafeDriverConfigTest.java | 4 -- ...cInferringLoadBalancingPolicyInitTest.java | 37 ++++++++---- .../DefaultLoadBalancingPolicyInitTest.java | 11 ++-- .../DefaultLoadBalancingPolicyTestBase.java | 4 -- .../core/metadata/DefaultEndPointTest.java | 12 ++-- .../protocol/ByteBufPrimitiveCodecTest.java | 33 ++++------ .../datastax/oss/driver/core/ConnectIT.java | 24 ++++---- .../core/ProtocolVersionMixedClusterIT.java | 34 ++++++----- .../core/config/DriverConfigValidationIT.java | 4 -- .../DriverExecutionProfileReloadIT.java | 22 +++---- .../DriverExecutionProfileSimulacronIT.java | 22 ++++--- .../driver/core/cql/BoundStatementCcmIT.java | 3 - .../core/cql/BoundStatementSimulacronIT.java | 21 +++---- .../oss/driver/core/cql/PagingStateIT.java | 22 +++---- .../driver/core/cql/PerRequestKeyspaceIT.java | 10 ++-- .../driver/core/cql/PreparedStatementIT.java | 12 ++-- .../oss/driver/core/cql/QueryTraceIT.java | 13 ++-- .../core/cql/SimpleStatementSimulacronIT.java | 12 ++-- .../core/session/RequestProcessorIT.java | 18 +++--- .../driver/core/throttling/ThrottlingIT.java | 16 ++--- .../type/codec/registry/CodecRegistryIT.java | 21 ++++--- .../oss/driver/mapper/ComputedIT.java | 13 ++-- .../oss/driver/mapper/PrimitivesIT.java | 4 -- .../mapper/QueryKeyspaceAndTableIT.java | 46 +++++++------- .../oss/driver/mapper/QueryReturnTypesIT.java | 16 +++-- .../driver/mapper/StatementAttributesIT.java | 10 +--- .../insert/RegularInsertTest.java | 60 ++++++++++--------- .../querybuilder/update/UpdateUsingTest.java | 58 +++++++++--------- 29 files changed, 293 insertions(+), 302 deletions(-) diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/protocol/TinkerpopBufferPrimitiveCodecTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/protocol/TinkerpopBufferPrimitiveCodecTest.java index 7dd240baf99..78e9aceeea3 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/protocol/TinkerpopBufferPrimitiveCodecTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/protocol/TinkerpopBufferPrimitiveCodecTest.java @@ -16,6 +16,7 @@ package com.datastax.dse.driver.internal.core.protocol; import static com.datastax.dse.driver.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.datastax.dse.driver.Assertions; import com.datastax.dse.driver.internal.core.graph.binary.buffer.DseNettyBufferFactory; @@ -29,9 +30,7 @@ import java.nio.ByteBuffer; import java.util.function.Supplier; import org.apache.tinkerpop.gremlin.structure.io.Buffer; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; /** @@ -45,8 +44,6 @@ public class TinkerpopBufferPrimitiveCodecTest { private static final DseNettyBufferFactory factory = new DseNettyBufferFactory(); private final TinkerpopBufferPrimitiveCodec codec = new TinkerpopBufferPrimitiveCodec(factory); - @Rule public ExpectedException expectedException = ExpectedException.none(); - @Test public void should_concatenate() { Buffer left = factory.withBytes(0xca, 0xfe); @@ -93,8 +90,6 @@ public void should_read_inet_v6() { @Test public void should_fail_to_read_inet_if_length_invalid() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid address length: 3 ([127, 0, 1])"); Buffer source = factory.withBytes( // length (as a byte) @@ -108,7 +103,9 @@ public void should_fail_to_read_inet_if_length_invalid() { 0x00, 0x23, 0x52); - codec.readInet(source); + assertThatThrownBy(() -> codec.readInet(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid address length: 3 ([127, 0, 1])"); } @Test @@ -138,9 +135,6 @@ public void should_read_inetaddr_v6() { @Test public void should_fail_to_read_inetaddr_if_length_invalid() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid address length: 3 ([127, 0, 1])"); - Buffer source = factory.withBytes( // length (as a byte) @@ -149,7 +143,9 @@ public void should_fail_to_read_inetaddr_if_length_invalid() { 0x7f, 0x00, 0x01); - codec.readInetAddr(source); + assertThatThrownBy(() -> codec.readInetAddr(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid address length: 3 ([127, 0, 1])"); } @Test @@ -220,14 +216,12 @@ public void should_read_string(Supplier supplier) { @Test public void should_fail_to_read_string_if_not_enough_characters() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage( - "Not enough bytes to read an UTF-8 serialized string of size 4"); - Buffer source = factory.heap(); source.writeShort(4); - codec.readString(source); + assertThatThrownBy(() -> codec.readString(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Not enough bytes to read an UTF-8 serialized string of size 4"); } @Test @@ -250,13 +244,12 @@ public void should_read_long_string() { @Test public void should_fail_to_read_long_string_if_not_enough_characters() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage( - "Not enough bytes to read an UTF-8 serialized string of size 4"); Buffer source = factory.heap(4, 4); source.writeInt(4); - codec.readLongString(source); + assertThatThrownBy(() -> codec.readLongString(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Not enough bytes to read an UTF-8 serialized string of size 4"); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java index b268df322de..019d50ab2a0 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java @@ -24,14 +24,10 @@ import com.typesafe.config.ConfigFactory; import java.util.HashMap; import java.util.Map; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class TypesafeDriverConfigTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); - @Test public void should_load_minimal_config_with_no_profiles() { TypesafeDriverConfig config = parse("int1 = 42"); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java index 71d1ef154c8..c0355ea5198 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.loadbalancing; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.filter; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeast; @@ -102,13 +103,19 @@ public void should_require_local_dc_if_contact_points_from_different_dcs() { when(node2.getDatacenter()).thenReturn("dc2"); BasicLoadBalancingPolicy policy = createPolicy(); - thrown.expect(IllegalStateException.class); - thrown.expectMessage( - "No local DC was provided, but the contact points are from different DCs: node1=dc1, node2=dc2"); - // When - policy.init( - ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), distanceReporter); + Throwable t = + catchThrowable( + () -> + policy.init( + ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), + distanceReporter)); + + // Then + assertThat(t) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining( + "No local DC was provided, but the contact points are from different DCs: node1=dc1, node2=dc2"); } @Test @@ -121,13 +128,19 @@ public void should_require_local_dc_if_contact_points_have_null_dcs() { when(node2.getDatacenter()).thenReturn(null); BasicLoadBalancingPolicy policy = createPolicy(); - thrown.expect(IllegalStateException.class); - thrown.expectMessage( - "The local DC could not be inferred from contact points, please set it explicitly"); - // When - policy.init( - ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), distanceReporter); + Throwable t = + catchThrowable( + () -> + policy.init( + ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), + distanceReporter)); + + // Then + assertThat(t) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining( + "The local DC could not be inferred from contact points, please set it explicitly"); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java index 2372e3de92d..2c5cd8eb0fe 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.loadbalancing; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.filter; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeast; @@ -102,12 +103,12 @@ public void should_require_local_dc_if_explicit_contact_points() { when(metadataManager.wasImplicitContactPoint()).thenReturn(false); DefaultLoadBalancingPolicy policy = createPolicy(); - thrown.expect(IllegalStateException.class); - thrown.expectMessage( - "Since you provided explicit contact points, the local DC must be explicitly set"); - // When - policy.init(ImmutableMap.of(UUID.randomUUID(), node2), distanceReporter); + assertThatThrownBy( + () -> policy.init(ImmutableMap.of(UUID.randomUUID(), node2), distanceReporter)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining( + "Since you provided explicit contact points, the local DC must be explicitly set"); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java index f5ac866e4ef..c98ee523d02 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java @@ -32,8 +32,6 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import org.junit.After; import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; @@ -44,8 +42,6 @@ @RunWith(MockitoJUnitRunner.class) public abstract class DefaultLoadBalancingPolicyTestBase { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Mock protected DefaultNode node1; @Mock protected DefaultNode node2; @Mock protected DefaultNode node3; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultEndPointTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultEndPointTest.java index 5c3689920c1..28e91b26606 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultEndPointTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultEndPointTest.java @@ -16,16 +16,13 @@ package com.datastax.oss.driver.internal.core.metadata; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.net.InetSocketAddress; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class DefaultEndPointTest { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void should_create_from_host_name() { DefaultEndPoint endPoint = new DefaultEndPoint(new InetSocketAddress("localhost", 9042)); @@ -54,9 +51,8 @@ public void should_create_from_unresolved_address() { @Test public void should_reject_null_address() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("address can't be null"); - - new DefaultEndPoint(null); + assertThatThrownBy(() -> new DefaultEndPoint(null)) + .isInstanceOf(NullPointerException.class) + .hasMessage("address can't be null"); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java index fadb80f871b..18ebb79ea59 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.protocol; import static com.datastax.oss.driver.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.datastax.oss.driver.internal.core.util.ByteBufs; import com.datastax.oss.protocol.internal.util.Bytes; @@ -24,9 +25,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; /** * Note: we don't test trivial methods that simply delegate to ByteBuf, nor default implementations @@ -35,8 +34,6 @@ public class ByteBufPrimitiveCodecTest { private ByteBufPrimitiveCodec codec = new ByteBufPrimitiveCodec(ByteBufAllocator.DEFAULT); - @Rule public ExpectedException expectedException = ExpectedException.none(); - @Test public void should_concatenate() { ByteBuf left = ByteBufs.wrap(0xca, 0xfe); @@ -91,8 +88,6 @@ public void should_read_inet_v6() { @Test public void should_fail_to_read_inet_if_length_invalid() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid address length: 3 ([127, 0, 1])"); ByteBuf source = ByteBufs.wrap( // length (as a byte) @@ -106,7 +101,9 @@ public void should_fail_to_read_inet_if_length_invalid() { 0x00, 0x23, 0x52); - codec.readInet(source); + assertThatThrownBy(() -> codec.readInet(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid address length: 3 ([127, 0, 1])"); } @Test @@ -136,9 +133,6 @@ public void should_read_inetaddr_v6() { @Test public void should_fail_to_read_inetaddr_if_length_invalid() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid address length: 3 ([127, 0, 1])"); - ByteBuf source = ByteBufs.wrap( // length (as a byte) @@ -147,7 +141,9 @@ public void should_fail_to_read_inetaddr_if_length_invalid() { 0x7f, 0x00, 0x01); - codec.readInetAddr(source); + assertThatThrownBy(() -> codec.readInetAddr(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid address length: 3 ([127, 0, 1])"); } @Test @@ -207,14 +203,12 @@ public void should_read_string() { @Test public void should_fail_to_read_string_if_not_enough_characters() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage( - "Not enough bytes to read an UTF-8 serialized string of size 4"); - ByteBuf source = codec.allocate(2); source.writeShort(4); - codec.readString(source); + assertThatThrownBy(() -> codec.readString(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Not enough bytes to read an UTF-8 serialized string of size 4"); } @Test @@ -237,13 +231,12 @@ public void should_read_long_string() { @Test public void should_fail_to_read_long_string_if_not_enough_characters() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage( - "Not enough bytes to read an UTF-8 serialized string of size 4"); ByteBuf source = codec.allocate(4); source.writeInt(4); - codec.readLongString(source); + assertThatThrownBy(() -> codec.readLongString(source)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Not enough bytes to read an UTF-8 serialized string of size 4"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java index 4f899151d29..d933643e647 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java @@ -19,6 +19,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.awaitility.Awaitility.await; import com.datastax.oss.driver.api.core.AllNodesFailedException; @@ -47,10 +48,8 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; @Category(ParallelizableTests.class) public class ConnectIT { @@ -59,8 +58,6 @@ public class ConnectIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(2)); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void setup() { SIMULACRON_RULE.cluster().acceptConnections(); @@ -78,14 +75,14 @@ public void should_fail_fast_if_contact_points_unreachable_and_reconnection_disa // Given SIMULACRON_RULE.cluster().rejectConnections(0, RejectScope.STOP); - thrown.expect(AllNodesFailedException.class); - thrown.expectMessage( - "Could not reach any contact point, make sure you've provided valid addresses"); - // When - SessionUtils.newSession(SIMULACRON_RULE); + Throwable t = catchThrowable(() -> SessionUtils.newSession(SIMULACRON_RULE)); - // Then the exception is thrown + // Then + assertThat(t) + .isInstanceOf(AllNodesFailedException.class) + .hasMessageContaining( + "Could not reach any contact point, make sure you've provided valid addresses"); } @Test @@ -103,7 +100,7 @@ public void should_wait_for_contact_points_if_reconnection_enabled() throws Exce .withDuration(DefaultDriverOption.RECONNECTION_BASE_DELAY, Duration.ofMillis(500)) .build(); CompletableFuture sessionFuture = - newSessionAsync(SIMULACRON_RULE, loader).toCompletableFuture(); + newSessionAsync(loader).toCompletableFuture(); // wait a bit to ensure we have a couple of reconnections, otherwise we might race and allow // reconnections before the initial attempt TimeUnit.SECONDS.sleep(2); @@ -182,10 +179,9 @@ public void should_mark_unreachable_contact_points_as_local_and_schedule_reconne } @SuppressWarnings("unchecked") - private CompletionStage newSessionAsync( - SimulacronRule serverRule, DriverConfigLoader loader) { + private CompletionStage newSessionAsync(DriverConfigLoader loader) { return SessionUtils.baseBuilder() - .addContactEndPoints(serverRule.getContactPoints()) + .addContactEndPoints(ConnectIT.SIMULACRON_RULE.getContactPoints()) .withConfigLoader(loader) .buildAsync(); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionMixedClusterIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionMixedClusterIT.java index 2dba7ae4ba9..3bd25b8c61d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionMixedClusterIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionMixedClusterIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core; import static com.datastax.oss.driver.assertions.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.fail; import com.datastax.oss.driver.api.core.CqlSession; @@ -35,10 +36,8 @@ import com.datastax.oss.simulacron.server.BoundNode; import com.datastax.oss.simulacron.server.BoundTopic; import java.util.stream.Stream; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; /** * Covers protocol re-negotiation with a mixed cluster: if, after the initial connection and the @@ -47,7 +46,6 @@ */ @Category(ParallelizableTests.class) public class ProtocolVersionMixedClusterIT { - @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void should_downgrade_if_peer_does_not_support_negotiated_version() { @@ -113,19 +111,25 @@ public void should_keep_current_if_supported_by_all_peers() { @Test public void should_fail_if_peer_does_not_support_v3() { - thrown.expect(UnsupportedProtocolVersionException.class); - thrown.expectMessage( - "reports Cassandra version 2.0.9, but the driver only supports 2.1.0 and above"); - try (BoundCluster simulacron = mixedVersions("3.0.0", "2.0.9", "3.11"); - BoundNode contactPoint = simulacron.node(0); - CqlSession ignored = - (CqlSession) - SessionUtils.baseBuilder() - .addContactPoint(contactPoint.inetSocketAddress()) - .build()) { - fail("Cluster init should have failed"); - } + Throwable t = + catchThrowable( + () -> { + try (BoundCluster simulacron = mixedVersions("3.0.0", "2.0.9", "3.11"); + BoundNode contactPoint = simulacron.node(0); + CqlSession ignored = + (CqlSession) + SessionUtils.baseBuilder() + .addContactPoint(contactPoint.inetSocketAddress()) + .build()) { + fail("Cluster init should have failed"); + } + }); + + assertThat(t) + .isInstanceOf(UnsupportedProtocolVersionException.class) + .hasMessageContaining( + "reports Cassandra version 2.0.9, but the driver only supports 2.1.0 and above"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java index 5e208eed657..db3c56bceac 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java @@ -25,10 +25,8 @@ import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; @Category(ParallelizableTests.class) public class DriverConfigValidationIT { @@ -37,8 +35,6 @@ public class DriverConfigValidationIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(1)); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void should_fail_to_init_with_invalid_policy() { should_fail_to_init_with_invalid_policy(DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileReloadIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileReloadIT.java index c2f0971cedd..43105a0d6e2 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileReloadIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileReloadIT.java @@ -19,6 +19,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.noRows; import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.junit.Assert.fail; import com.datastax.oss.driver.api.core.CqlSession; @@ -36,9 +37,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class DriverExecutionProfileReloadIT { @@ -46,8 +45,6 @@ public class DriverExecutionProfileReloadIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(3)); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void clearPrimes() { SIMULACRON_RULE.cluster().clearLogs(); @@ -55,7 +52,7 @@ public void clearPrimes() { } @Test - public void should_periodically_reload_configuration() throws Exception { + public void should_periodically_reload_configuration() { String query = "mockquery"; // Define a loader which configures a reload interval of 2s and current value of configSource. AtomicReference configSource = new AtomicReference<>(""); @@ -93,7 +90,7 @@ public void should_periodically_reload_configuration() throws Exception { } @Test - public void should_reload_configuration_when_event_fired() throws Exception { + public void should_reload_configuration_when_event_fired() { String query = "mockquery"; // Define a loader which configures no automatic reloads and current value of configSource. AtomicReference configSource = new AtomicReference<>(""); @@ -132,7 +129,7 @@ public void should_reload_configuration_when_event_fired() throws Exception { } @Test - public void should_not_allow_dynamically_adding_profile() throws Exception { + public void should_not_allow_dynamically_adding_profile() { String query = "mockquery"; // Define a loader which configures a reload interval of 2s and current value of configSource. AtomicReference configSource = new AtomicReference<>(""); @@ -164,13 +161,18 @@ public void should_not_allow_dynamically_adding_profile() throws Exception { // Execute again, should expect to fail again because doesn't allow to dynamically define // profile. - thrown.expect(IllegalArgumentException.class); - session.execute(SimpleStatement.builder(query).setExecutionProfileName("slow").build()); + Throwable t = + catchThrowable( + () -> + session.execute( + SimpleStatement.builder(query).setExecutionProfileName("slow").build())); + + assertThat(t).isInstanceOf(IllegalArgumentException.class); } } @Test - public void should_reload_profile_config_when_reloading_config() throws Exception { + public void should_reload_profile_config_when_reloading_config() { String query = "mockquery"; // Define a loader which configures a reload interval of 2s and current value of configSource. // Define initial profile settings so it initially exists. diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileSimulacronIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileSimulacronIT.java index 763e816b746..8fe6d9fd573 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileSimulacronIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverExecutionProfileSimulacronIT.java @@ -19,6 +19,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.serverError; import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.junit.Assert.fail; import com.datastax.oss.driver.api.core.AllNodesFailedException; @@ -38,10 +39,8 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; @Category(ParallelizableTests.class) public class DriverExecutionProfileSimulacronIT { @@ -50,8 +49,6 @@ public class DriverExecutionProfileSimulacronIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(3)); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void clearPrimes() { SIMULACRON_RULE.cluster().clearLogs(); @@ -66,9 +63,11 @@ public void should_fail_if_config_profile_specified_doesnt_exist() { .setExecutionProfileName("IDONTEXIST") .build(); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Unknown profile 'IDONTEXIST'. Check your configuration"); - session.execute(statement); + Throwable t = catchThrowable(() -> session.execute(statement)); + + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Unknown profile 'IDONTEXIST'. Check your configuration."); } } @@ -119,8 +118,13 @@ public void should_use_profile_default_idempotence() { } // Execute query with profile, should retry on all hosts since query is idempotent. - thrown.expect(AllNodesFailedException.class); - session.execute(SimpleStatement.builder(query).setExecutionProfileName("idem").build()); + Throwable t = + catchThrowable( + () -> + session.execute( + SimpleStatement.builder(query).setExecutionProfileName("idem").build())); + + assertThat(t).isInstanceOf(AllNodesFailedException.class); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java index 09e27f657ec..75748d37a6c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java @@ -60,7 +60,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestName; import org.junit.rules.TestRule; @@ -84,8 +83,6 @@ public class BoundStatementCcmIT { @Rule public TestName name = new TestName(); - @Rule public ExpectedException thrown = ExpectedException.none(); - private static final String KEY = "test"; private static final int VALUE = 7; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java index 54b3333dbdf..4f31dff1717 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java @@ -19,6 +19,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.query; import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; @@ -40,10 +41,8 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; @Category(ParallelizableTests.class) public class BoundStatementSimulacronIT { @@ -52,8 +51,6 @@ public class BoundStatementSimulacronIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(1)); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void clearPrimes() { SIMULACRON_RULE.cluster().clearLogs(); @@ -148,10 +145,11 @@ public void should_use_timeout_from_simple_statement() { .build(); PreparedStatement prepared = session.prepare(st); - thrown.expect(DriverTimeoutException.class); - thrown.expectMessage("Query timed out after PT1S"); + Throwable t = catchThrowable(() -> session.execute(prepared.bind(0))); - session.execute(prepared.bind(0)); + assertThat(t) + .isInstanceOf(DriverTimeoutException.class) + .hasMessage("Query timed out after PT1S"); } } @@ -179,10 +177,13 @@ public void should_use_timeout() { .build(); PreparedStatement prepared = session.prepare(st); - thrown.expect(DriverTimeoutException.class); - thrown.expectMessage("Query timed out after PT0.15S"); + Throwable t = + catchThrowable( + () -> session.execute(prepared.bind(0).setTimeout(Duration.ofMillis(150)))); - session.execute(prepared.bind(0).setTimeout(Duration.ofMillis(150))); + assertThat(t) + .isInstanceOf(DriverTimeoutException.class) + .hasMessage("Query timed out after PT0.15S"); } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java index ca0b8c34bc0..689c2390db7 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.cql; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.fail; import com.datastax.oss.driver.api.core.CqlSession; @@ -35,10 +36,8 @@ import java.util.function.UnaryOperator; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -51,8 +50,6 @@ public class PagingStateIT { @ClassRule public static TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void setupSchema() { CqlSession session = SESSION_RULE.session(); @@ -158,13 +155,16 @@ private void should_fail(String query1, int value1, String query2, int value2) { ResultSet resultSet = session.execute(boundStatement1); PagingState pagingState = resultSet.getExecutionInfo().getSafePagingState(); - thrown.expect(IllegalArgumentException.class); - @SuppressWarnings("unused") - BoundStatement ignored = - session - .prepare(SimpleStatement.newInstance(query2).setPageSize(15)) - .bind(value2) - .setPagingState(pagingState); + @SuppressWarnings("ResultOfMethodCallIgnored") + Throwable t = + catchThrowable( + () -> + session + .prepare(SimpleStatement.newInstance(query2).setPageSize(15)) + .bind(value2) + .setPagingState(pagingState)); + + assertThat(t).isInstanceOf(IllegalArgumentException.class); } static class IntWrapper { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java index 32e9e331c52..de6be0afe61 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.cql; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; @@ -38,7 +39,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestName; import org.junit.rules.TestRule; @@ -60,7 +60,6 @@ public class PerRequestKeyspaceIT { @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); - @Rule public ExpectedException thrown = ExpectedException.none(); @Rule public TestName nameRule = new TestName(); @Before @@ -113,9 +112,10 @@ private void should_reject_statement_with_keyspace_in_protocol_v4(Statement stat .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") .build(); try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Can't use per-request keyspace with protocol V4"); - session.execute(statement); + Throwable t = catchThrowable(() -> session.execute(statement)); + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Can't use per-request keyspace with protocol V4"); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index 2e25f600f03..1e7e91084ba 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.catchThrowable; import com.codahale.metrics.Gauge; import com.datastax.oss.driver.api.core.CqlSession; @@ -51,7 +52,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -79,8 +79,6 @@ public class PreparedStatementIT { @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void setupSchema() { for (String query : @@ -277,11 +275,11 @@ public void should_fail_to_reprepare_if_query_becomes_invalid() { session.prepare("SELECT a, b, c, d FROM prepared_statement_test WHERE a = ?"); session.execute("ALTER TABLE prepared_statement_test DROP d"); - thrown.expect(InvalidQueryException.class); - thrown.expectMessage("Undefined column name d"); - // When - session.execute(ps.bind()); + Throwable t = catchThrowable(() -> session.execute(ps.bind())); + + // Then + assertThat(t).isInstanceOf(InvalidQueryException.class).hasMessage("Undefined column name d"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java index 33eddb2afa2..567a1263310 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.cql; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.Version; @@ -29,10 +30,8 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -46,8 +45,6 @@ public class QueryTraceIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void should_not_have_tracing_id_when_tracing_disabled() { ExecutionInfo executionInfo = @@ -58,9 +55,11 @@ public void should_not_have_tracing_id_when_tracing_disabled() { assertThat(executionInfo.getTracingId()).isNull(); - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Tracing was disabled for this request"); - executionInfo.getQueryTrace(); + Throwable t = catchThrowable(executionInfo::getQueryTrace); + + assertThat(t) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Tracing was disabled for this request"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/SimpleStatementSimulacronIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/SimpleStatementSimulacronIT.java index 1c6fa8f2737..e3daeaf0a03 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/SimpleStatementSimulacronIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/SimpleStatementSimulacronIT.java @@ -18,6 +18,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.noRows; import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; @@ -35,10 +36,8 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -54,8 +53,6 @@ public class SimpleStatementSimulacronIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(SIMULACRON_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void clearPrimes() { SIMULACRON_RULE.cluster().clearLogs(); @@ -95,9 +92,10 @@ public void should_use_timeout() { .setConsistencyLevel(DefaultConsistencyLevel.ONE) .build(); - thrown.expect(DriverTimeoutException.class); - thrown.expectMessage("Query timed out after PT1S"); + Throwable t = catchThrowable(() -> SESSION_RULE.session().execute(st)); - SESSION_RULE.session().execute(st); + assertThat(t) + .isInstanceOf(DriverTimeoutException.class) + .hasMessage("Query timed out after PT1S"); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/RequestProcessorIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/RequestProcessorIT.java index 7fe18e3044f..ef6b83f57dc 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/RequestProcessorIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/RequestProcessorIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.session; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; @@ -37,10 +38,8 @@ import com.google.common.util.concurrent.Uninterruptibles; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -72,8 +71,6 @@ public class RequestProcessorIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - public static final String KEY = "test"; @BeforeClass @@ -150,9 +147,14 @@ public void should_throw_illegal_argument_exception_if_no_matching_processor_fou // Since cluster does not have a processor registered for returning ListenableFuture, an // IllegalArgumentException // should be thrown. - thrown.expect(IllegalArgumentException.class); - SESSION_RULE - .session() - .execute(SimpleStatement.newInstance("select * from test"), GuavaSession.ASYNC); + Throwable t = + catchThrowable( + () -> + SESSION_RULE + .session() + .execute( + SimpleStatement.newInstance("select * from test"), GuavaSession.ASYNC)); + + assertThat(t).isInstanceOf(IllegalArgumentException.class); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java index 12d21dce299..ef90cac4e2e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java @@ -15,6 +15,9 @@ */ package com.datastax.oss.driver.core.throttling; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; @@ -27,14 +30,12 @@ import java.util.concurrent.TimeUnit; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class ThrottlingIT { private static final String QUERY = "select * from foo"; @Rule public SimulacronRule simulacron = new SimulacronRule(ClusterSpec.builder().withNodes(1)); - @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void should_reject_request_when_throttling_by_concurrency() { @@ -66,12 +67,13 @@ public void should_reject_request_when_throttling_by_concurrency() { } // The next query should be rejected - thrown.expect(RequestThrottlingException.class); - thrown.expectMessage( - "The session has reached its maximum capacity " - + "(concurrent requests: 10, queue size: 10)"); + Throwable t = catchThrowable(() -> session.execute(QUERY)); - session.execute(QUERY); + assertThat(t) + .isInstanceOf(RequestThrottlingException.class) + .hasMessage( + "The session has reached its maximum capacity " + + "(concurrent requests: 10, queue size: 10)"); } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java index d8482681e84..9988e0c18e0 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.type.codec.registry; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.ProtocolVersion; @@ -57,7 +58,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestName; import org.junit.rules.TestRule; @@ -74,8 +74,6 @@ public class CodecRegistryIT { @Rule public TestName name = new TestName(); - @Rule public ExpectedException thrown = ExpectedException.none(); - @BeforeClass public static void createSchema() { // table with simple primary key, single cell. @@ -153,10 +151,17 @@ public void should_throw_exception_if_no_codec_registered_for_type_set() { PreparedStatement prepared = SESSION_RULE.session().prepare("INSERT INTO test (k, v) values (?, ?)"); - thrown.expect(CodecNotFoundException.class); - // float value for int column should not work since no applicable codec. - prepared.boundStatementBuilder().setString(0, name.getMethodName()).setFloat(1, 3.14f).build(); + Throwable t = + catchThrowable( + () -> + prepared + .boundStatementBuilder() + .setString(0, name.getMethodName()) + .setFloat(1, 3.14f) + .build()); + + assertThat(t).isInstanceOf(CodecNotFoundException.class); } @Test @@ -182,9 +187,9 @@ public void should_throw_exception_if_no_codec_registered_for_type_get() { // should not be able to access int column as float as no codec is registered to handle that. Row row = rows.iterator().next(); - thrown.expect(CodecNotFoundException.class); + Throwable t = catchThrowable(() -> assertThat(row.getFloat("v")).isEqualTo(3.0f)); - assertThat(row.getFloat("v")).isEqualTo(3.0f); + assertThat(t).isInstanceOf(CodecNotFoundException.class); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ComputedIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ComputedIT.java index 48952b0c823..2ca7ecef743 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ComputedIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ComputedIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.mapper; import static com.datastax.oss.driver.assertions.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.data.Offset.offset; import com.datastax.oss.driver.api.core.CqlIdentifier; @@ -50,10 +51,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -67,8 +66,6 @@ public class ComputedIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - private static TestMapper mapper; private static AtomicInteger keyProvider = new AtomicInteger(); @@ -225,9 +222,11 @@ public void should_fail_if_alias_does_not_match_cqlName() { 1)); // should raise an exception as 'writetime' is not found in result set. - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("writetime is not a column in this row"); - computedDao.get(result.one()); + Throwable t = catchThrowable(() -> computedDao.get(result.one())); + + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("writetime is not a column in this row"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java index 73896740ca1..9cc4004690d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java @@ -36,10 +36,8 @@ import java.util.Objects; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -54,8 +52,6 @@ public class PrimitivesIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - private static TestMapper mapper; @BeforeClass diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryKeyspaceAndTableIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryKeyspaceAndTableIT.java index 571852f09d5..f3ad91c1c30 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryKeyspaceAndTableIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryKeyspaceAndTableIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; @@ -35,10 +36,8 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -56,8 +55,6 @@ public class QueryKeyspaceAndTableIT { private static final CqlIdentifier OTHER_KEYSPACE = CqlIdentifier.fromCql(QueryKeyspaceAndTableIT.class.getSimpleName() + "_alt"); - @Rule public ExpectedException thrown = ExpectedException.none(); - private static TestMapper mapper; @BeforeClass @@ -93,22 +90,25 @@ public void should_substitute_keyspaceId_and_tableId() { @Test public void should_fail_to_substitute_keyspaceId_if_dao_has_no_keyspace() { - thrown.expect(MapperException.class); - thrown.expectMessage( - "Cannot substitute ${keyspaceId} in query " - + "'SELECT count(*) FROM ${keyspaceId}.${tableId}': " - + "the DAO wasn't built with a keyspace"); - mapper.daoWithKeyspaceAndTableId(null, FOO_TABLE_ID); + Throwable t = catchThrowable(() -> mapper.daoWithKeyspaceAndTableId(null, FOO_TABLE_ID)); + assertThat(t) + .isInstanceOf(MapperException.class) + .hasMessage( + "Cannot substitute ${keyspaceId} in query " + + "'SELECT count(*) FROM ${keyspaceId}.${tableId}': " + + "the DAO wasn't built with a keyspace"); } @Test public void should_fail_to_substitute_tableId_if_dao_has_no_table() { - thrown.expect(MapperException.class); - thrown.expectMessage( - "Cannot substitute ${tableId} in query " - + "'SELECT count(*) FROM ${keyspaceId}.${tableId}': " - + "the DAO wasn't built with a table"); - mapper.daoWithKeyspaceAndTableId(SESSION_RULE.keyspace(), null); + Throwable t = + catchThrowable(() -> mapper.daoWithKeyspaceAndTableId(SESSION_RULE.keyspace(), null)); + assertThat(t) + .isInstanceOf(MapperException.class) + .hasMessage( + "Cannot substitute ${tableId} in query " + + "'SELECT count(*) FROM ${keyspaceId}.${tableId}': " + + "the DAO wasn't built with a table"); } @Test @@ -125,12 +125,14 @@ public void should_not_use_keyspace_in_qualifiedTableId_when_dao_has_no_keyspace @Test public void should_fail_to_substitute_qualifiedTableId_if_dao_has_no_table() { - thrown.expect(MapperException.class); - thrown.expectMessage( - "Cannot substitute ${qualifiedTableId} in query " - + "'SELECT count(*) FROM ${qualifiedTableId}': " - + "the DAO wasn't built with a table"); - mapper.daoWithQualifiedTableId(SESSION_RULE.keyspace(), null); + Throwable t = + catchThrowable(() -> mapper.daoWithQualifiedTableId(SESSION_RULE.keyspace(), null)); + assertThat(t) + .isInstanceOf(MapperException.class) + .hasMessage( + "Cannot substitute ${qualifiedTableId} in query " + + "'SELECT count(*) FROM ${qualifiedTableId}': " + + "the DAO wasn't built with a table"); } @Dao diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java index bf2091ef56e..716b35faebc 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; @@ -49,10 +50,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -66,8 +65,6 @@ public class QueryReturnTypesIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - private static TestDao dao; @BeforeClass @@ -122,11 +119,12 @@ public void should_execute_count_query_and_map_to_long() { @Test public void should_fail_to_map_to_long_if_query_returns_other_type() { - thrown.expect(MapperException.class); - thrown.expectMessage( - "Expected the query to return a column with CQL type BIGINT in first position " - + "(return type long is intended for COUNT queries)"); - dao.wrongCount(); + Throwable t = catchThrowable(() -> dao.wrongCount()); + assertThat(t) + .isInstanceOf(MapperException.class) + .hasMessage( + "Expected the query to return a column with CQL type BIGINT in first position " + + "(return type long is intended for COUNT queries)"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java index 61f0fbf6c7a..d32fd1f9517 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java @@ -20,6 +20,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; @@ -54,9 +55,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; @@ -70,8 +69,6 @@ public class StatementAttributesIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(SIMULACRON_RULE).around(SESSION_RULE); - @Rule public ExpectedException thrown = ExpectedException.none(); - private static String PAGING_STATE = "paging_state"; private static int PAGE_SIZE = 13; @@ -192,9 +189,8 @@ public void should_honor_annotation_attributes_on_update() { @Test public void should_fail_runtime_attributes_bad() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("mock error"); - dao.save(simple, badStatementFunction); + Throwable t = catchThrowable(() -> dao.save(simple, badStatementFunction)); + assertThat(t).isInstanceOf(IllegalStateException.class).hasMessage("mock error"); } private static void primeInsertQuery() { diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java index 30e39c4836a..0873cec6da1 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java @@ -19,19 +19,16 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.bindMarker; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.insertInto; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.querybuilder.term.Term; import com.datastax.oss.driver.internal.querybuilder.insert.DefaultInsert; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.util.Map; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class RegularInsertTest { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void should_generate_column_assignments() { assertThat(insertInto("foo").value("a", literal(1)).value("b", literal(2))) @@ -123,18 +120,22 @@ public void should_throw_exception_with_invalid_ttl() { DefaultInsert defaultInsert = (DefaultInsert) insertInto("foo").value("a", bindMarker()).usingTtl(10); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("TTL value must be a BindMarker or an Integer"); - - new DefaultInsert( - defaultInsert.getKeyspace(), - defaultInsert.getTable(), - (Term) defaultInsert.getJson(), - defaultInsert.getMissingJsonBehavior(), - defaultInsert.getAssignments(), - defaultInsert.getTimestamp(), - new Object(), // invalid TTL object - defaultInsert.isIfNotExists()); + Throwable t = + catchThrowable( + () -> + new DefaultInsert( + defaultInsert.getKeyspace(), + defaultInsert.getTable(), + (Term) defaultInsert.getJson(), + defaultInsert.getMissingJsonBehavior(), + defaultInsert.getAssignments(), + defaultInsert.getTimestamp(), + new Object(), // invalid TTL object + defaultInsert.isIfNotExists())); + + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TTL value must be a BindMarker or an Integer"); } @Test @@ -142,17 +143,20 @@ public void should_throw_exception_with_invalid_timestamp() { DefaultInsert defaultInsert = (DefaultInsert) insertInto("foo").value("a", bindMarker()).usingTimestamp(1); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("TIMESTAMP value must be a BindMarker or a Long"); - - new DefaultInsert( - defaultInsert.getKeyspace(), - defaultInsert.getTable(), - (Term) defaultInsert.getJson(), - defaultInsert.getMissingJsonBehavior(), - defaultInsert.getAssignments(), - new Object(), // invalid timestamp object) - defaultInsert.getTtlInSeconds(), - defaultInsert.isIfNotExists()); + Throwable t = + catchThrowable( + () -> + new DefaultInsert( + defaultInsert.getKeyspace(), + defaultInsert.getTable(), + (Term) defaultInsert.getJson(), + defaultInsert.getMissingJsonBehavior(), + defaultInsert.getAssignments(), + new Object(), // invalid timestamp object) + defaultInsert.getTtlInSeconds(), + defaultInsert.isIfNotExists())); + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TIMESTAMP value must be a BindMarker or a Long"); } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateUsingTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateUsingTest.java index 591a53f2200..1a96b05e4f8 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateUsingTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateUsingTest.java @@ -18,16 +18,13 @@ import static com.datastax.oss.driver.api.querybuilder.Assertions.assertThat; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.bindMarker; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.update; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.internal.querybuilder.update.DefaultUpdate; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class UpdateUsingTest { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void should_generate_using_timestamp_clause() { assertThat( @@ -129,18 +126,22 @@ public void should_throw_exception_with_invalid_ttl() { .whereColumn("k") .isEqualTo(bindMarker()); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("TTL value must be a BindMarker or an Integer"); + Throwable t = + catchThrowable( + () -> + new DefaultUpdate( + defaultUpdate.getKeyspace(), + defaultUpdate.getTable(), + defaultUpdate.getTimestamp(), + new Object(), // invalid TTL object + defaultUpdate.getAssignments(), + defaultUpdate.getRelations(), + defaultUpdate.isIfExists(), + defaultUpdate.getConditions())); - new DefaultUpdate( - defaultUpdate.getKeyspace(), - defaultUpdate.getTable(), - defaultUpdate.getTimestamp(), - new Object(), // invalid TTL object - defaultUpdate.getAssignments(), - defaultUpdate.getRelations(), - defaultUpdate.isIfExists(), - defaultUpdate.getConditions()); + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TTL value must be a BindMarker or an Integer"); } @Test @@ -153,17 +154,20 @@ public void should_throw_exception_with_invalid_timestamp() { .whereColumn("k") .isEqualTo(bindMarker()); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("TIMESTAMP value must be a BindMarker or a Long"); - - new DefaultUpdate( - defaultUpdate.getKeyspace(), - defaultUpdate.getTable(), - new Object(), // invalid timestamp object - defaultUpdate.getTtl(), - defaultUpdate.getAssignments(), - defaultUpdate.getRelations(), - defaultUpdate.isIfExists(), - defaultUpdate.getConditions()); + Throwable t = + catchThrowable( + () -> + new DefaultUpdate( + defaultUpdate.getKeyspace(), + defaultUpdate.getTable(), + new Object(), // invalid timestamp object + defaultUpdate.getTtl(), + defaultUpdate.getAssignments(), + defaultUpdate.getRelations(), + defaultUpdate.isIfExists(), + defaultUpdate.getConditions())); + assertThat(t) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TIMESTAMP value must be a BindMarker or a Long"); } } From d86ba858b8b0bd58f1f9609acc7582b36dc85dc1 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 26 Nov 2020 18:23:06 +0100 Subject: [PATCH 008/395] Convert field to local variable --- .../driver/internal/core/session/DefaultSessionPoolsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/DefaultSessionPoolsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/DefaultSessionPoolsTest.java index b42f281a02a..88818f6929b 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/session/DefaultSessionPoolsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/DefaultSessionPoolsTest.java @@ -105,14 +105,13 @@ public class DefaultSessionPoolsTest { private DefaultNode node1; private DefaultNode node2; private DefaultNode node3; - private DefaultEventLoopGroup adminEventLoopGroup; private EventBus eventBus; @Before public void setup() { MockitoAnnotations.initMocks(this); - adminEventLoopGroup = new DefaultEventLoopGroup(1); + DefaultEventLoopGroup adminEventLoopGroup = new DefaultEventLoopGroup(1); when(nettyOptions.adminEventExecutorGroup()).thenReturn(adminEventLoopGroup); when(context.getNettyOptions()).thenReturn(nettyOptions); @@ -153,6 +152,7 @@ public void setup() { node1 = mockLocalNode(1); node2 = mockLocalNode(2); node3 = mockLocalNode(3); + @SuppressWarnings("ConstantConditions") ImmutableMap nodes = ImmutableMap.of( node1.getHostId(), node1, From bc0f569574a631387e37935cfc1b013fd9cb2510 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 26 Nov 2020 18:23:49 +0100 Subject: [PATCH 009/395] Replace occurrences of Constellation by Astra --- .../driver/api/core/session/SessionBuilder.java | 14 +++++++------- .../examples/mapper/KillrVideoMapperExample.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index f4bab46022e..2ee551a2bf6 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -497,10 +497,10 @@ public SelfT withClassLoader(@Nullable ClassLoader classLoader) { * the provided {@link Path}. * *

To connect to a Cloud database, you must first download the secure database bundle from the - * DataStax Constellation console that contains the connection information, then instruct the + * DataStax Astra console that contains the connection information, then instruct the * driver to read its contents using either this method or one if its variants. * - *

For more information, please refer to the DataStax Constellation documentation. + *

For more information, please refer to the DataStax Astra documentation. * * @param cloudConfigPath Path to the secure connect bundle zip file. * @see #withCloudSecureConnectBundle(URL) @@ -534,10 +534,10 @@ public SelfT withCodecRegistry(@Nullable MutableCodecRegistry codecRegistry) { * the provided {@link URL}. * *

To connect to a Cloud database, you must first download the secure database bundle from the - * DataStax Constellation console that contains the connection information, then instruct the + * DataStax Astra console that contains the connection information, then instruct the * driver to read its contents using either this method or one if its variants. * - *

For more information, please refer to the DataStax Constellation documentation. + *

For more information, please refer to the DataStax Astra documentation. * * @param cloudConfigUrl URL to the secure connect bundle zip file. * @see #withCloudSecureConnectBundle(Path) @@ -554,10 +554,10 @@ public SelfT withCloudSecureConnectBundle(@NonNull URL cloudConfigUrl) { * the provided {@link InputStream}. * *

To connect to a Cloud database, you must first download the secure database bundle from the - * DataStax Constellation console that contains the connection information, then instruct the + * DataStax Astra console that contains the connection information, then instruct the * driver to read its contents using either this method or one if its variants. * - *

For more information, please refer to the DataStax Constellation documentation. + *

For more information, please refer to the DataStax Astra documentation. * *

Note that the provided stream will be consumed and closed when either {@link * #build()} or {@link #buildAsync()} are called; attempting to reuse it afterwards will result in @@ -584,7 +584,7 @@ public SelfT withCloudSecureConnectBundle(@NonNull InputStream cloudConfigInputS * monitor tailored for Cloud deployments. This topology monitor assumes that the target cluster * should be contacted through the proxy specified here, using SNI routing. * - *

For more information, please refer to the DataStax Constellation documentation. + *

For more information, please refer to the DataStax Astra documentation. * * @param cloudProxyAddress The address of the Cloud proxy to use. * @see Server Name Indication diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java index 4c845ba89e9..4ad547767c8 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java @@ -112,7 +112,7 @@ public static void main(String[] args) { Video video = new Video(); video.setUserid(user.getUserid()); video.setName( - "Getting Started with DataStax Apache Cassandra as a Service on DataStax Constellation"); + "Getting Started with DataStax Apache Cassandra as a Service on DataStax Astra"); video.setLocation("https://www.youtube.com/watch?v=68xzKpcZURA"); Set tags = new HashSet<>(); tags.add("apachecassandra"); @@ -146,7 +146,7 @@ public static void main(String[] args) { Video template = new Video(); template.setVideoid(video.getVideoid()); template.setName( - "Getting Started with DataStax Apache Cassandra® as a Service on DataStax Constellation"); + "Getting Started with DataStax Apache Cassandra® as a Service on DataStax Astra"); videoDao.update(template); // Reload the whole entity and check the fields video = videoDao.get(video.getVideoid()); From 0e134a493b1adf8f35a23fe68c766add180cbb54 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 26 Nov 2020 18:24:41 +0100 Subject: [PATCH 010/395] Make fields final --- .../internal/core/metadata/LoadBalancingPolicyWrapper.java | 2 +- .../session/throttling/ConcurrencyLimitingRequestThrottler.java | 2 +- .../internal/core/util/concurrent/ReplayingEventFilter.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java index bdf0c392e0c..d4446418f4a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java @@ -84,7 +84,7 @@ private enum State { private final String logPrefix; private final ReplayingEventFilter eventFilter = new ReplayingEventFilter<>(this::processNodeStateEvent); - private AtomicReference stateRef = new AtomicReference<>(State.BEFORE_INIT); + private final AtomicReference stateRef = new AtomicReference<>(State.BEFORE_INIT); public LoadBalancingPolicyWrapper( @NonNull InternalDriverContext context, diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java index ebfc838f4ac..ec71bde30b2 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java @@ -65,7 +65,7 @@ public class ConcurrencyLimitingRequestThrottler implements RequestThrottler { private int concurrentRequests; @GuardedBy("lock") - private Deque queue = new ArrayDeque<>(); + private final Deque queue = new ArrayDeque<>(); @GuardedBy("lock") private boolean closed; diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java index 5d6fd62918a..f0e42b6b240 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java @@ -55,7 +55,7 @@ private enum State { private State state; @GuardedBy("stateLock") - private List recordedEvents; + private final List recordedEvents; public ReplayingEventFilter(Consumer consumer) { this.consumer = consumer; From 334915ba5cccd2e46ecbe74d736f3eeee92a2e9c Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 26 Nov 2020 20:43:42 +0100 Subject: [PATCH 011/395] Fix formatting issuess --- .../oss/driver/api/core/session/SessionBuilder.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index 2ee551a2bf6..af4eb467a95 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -497,8 +497,8 @@ public SelfT withClassLoader(@Nullable ClassLoader classLoader) { * the provided {@link Path}. * *

To connect to a Cloud database, you must first download the secure database bundle from the - * DataStax Astra console that contains the connection information, then instruct the - * driver to read its contents using either this method or one if its variants. + * DataStax Astra console that contains the connection information, then instruct the driver to + * read its contents using either this method or one if its variants. * *

For more information, please refer to the DataStax Astra documentation. * @@ -534,8 +534,8 @@ public SelfT withCodecRegistry(@Nullable MutableCodecRegistry codecRegistry) { * the provided {@link URL}. * *

To connect to a Cloud database, you must first download the secure database bundle from the - * DataStax Astra console that contains the connection information, then instruct the - * driver to read its contents using either this method or one if its variants. + * DataStax Astra console that contains the connection information, then instruct the driver to + * read its contents using either this method or one if its variants. * *

For more information, please refer to the DataStax Astra documentation. * @@ -554,8 +554,8 @@ public SelfT withCloudSecureConnectBundle(@NonNull URL cloudConfigUrl) { * the provided {@link InputStream}. * *

To connect to a Cloud database, you must first download the secure database bundle from the - * DataStax Astra console that contains the connection information, then instruct the - * driver to read its contents using either this method or one if its variants. + * DataStax Astra console that contains the connection information, then instruct the driver to + * read its contents using either this method or one if its variants. * *

For more information, please refer to the DataStax Astra documentation. * From d44a61a163f892216da13e54bea8eb2ed5943358 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 27 Nov 2020 16:16:59 +0100 Subject: [PATCH 012/395] Make field final --- .../oss/driver/internal/core/channel/ProtocolInitHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java index 9d4969040d6..1f9c0e2c689 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java @@ -79,7 +79,7 @@ class ProtocolInitHandler extends ConnectInitHandler { private final HeartbeatHandler heartbeatHandler; private String logPrefix; private ChannelHandlerContext ctx; - private boolean querySupportedOptions; + private final boolean querySupportedOptions; /** * @param querySupportedOptions whether to send OPTIONS as the first message, to request which From 55c03928ea074df20cae1ed4ed032e0adfed49dc Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 30 Nov 2020 15:22:06 +0100 Subject: [PATCH 013/395] Fix typo in javadocs of ConnectionInitException --- .../oss/driver/api/core/connection/ConnectionInitException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/connection/ConnectionInitException.java b/core/src/main/java/com/datastax/oss/driver/api/core/connection/ConnectionInitException.java index 4112bdcd6f8..77717bbae63 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/connection/ConnectionInitException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/connection/ConnectionInitException.java @@ -26,7 +26,7 @@ * *

The only time when this is returned directly to the client (wrapped in a {@link * AllNodesFailedException}) is at initialization. If it happens later when the driver is already - * connected, it is just logged an the connection is reattempted. + * connected, it is just logged and the connection is reattempted. */ public class ConnectionInitException extends DriverException { public ConnectionInitException(@NonNull String message, @Nullable Throwable cause) { From e8d2fe65cebf118b0d837e90380fc49d13a19fe2 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 30 Nov 2020 15:22:41 +0100 Subject: [PATCH 014/395] Mention that DriverException#getExecutionInfo returns null for low-level exceptions --- .../com/datastax/oss/driver/api/core/DriverException.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/DriverException.java b/core/src/main/java/com/datastax/oss/driver/api/core/DriverException.java index 9497ef15cf5..73e23712444 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/DriverException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/DriverException.java @@ -77,6 +77,10 @@ protected DriverException( * AllNodesFailedException#getAllErrors()} or {@link ExecutionInfo#getErrors()} do not contain * their own execution info, and therefore return null from this method. * + *

This method will also return null for low-level exceptions thrown directly from a driver + * channel, such as {@link com.datastax.oss.driver.api.core.connection.ConnectionInitException} or + * {@link com.datastax.oss.driver.api.core.connection.ClosedConnectionException}. + * *

It will also be null if you serialize and deserialize an exception. */ public ExecutionInfo getExecutionInfo() { From edeeaa0324251fb667dd4998304342ed36c12661 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 30 Nov 2020 15:23:09 +0100 Subject: [PATCH 015/395] Mention effect of idempotence on ClosedConnectionException --- .../api/core/connection/ClosedConnectionException.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.java b/core/src/main/java/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.java index 9daee547a46..9d0f7709004 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.java @@ -26,8 +26,9 @@ *

For example, this can happen if the node is unresponsive and a heartbeat query failed, or if * the node was forced down. * - *

The driver will always retry these requests on the next node transparently. Therefore, the - * only way to observe this exception is as part of an {@link AllNodesFailedException}. + *

The driver will retry these requests on the next node transparently, unless the request is not + * idempotent. Therefore, this exception is usually observed as part of an {@link + * AllNodesFailedException}. */ public class ClosedConnectionException extends DriverException { From 587a9149a7e5756fb40d40ab73a03b2bb2b91445 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 16:31:07 +0100 Subject: [PATCH 016/395] JAVA-2890: Fix off-by-one error in UdtCodec (#1508) --- changelog/README.md | 1 + .../driver/internal/core/type/codec/UdtCodec.java | 2 +- .../internal/core/type/codec/UdtCodecTest.java | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 9ddce319d39..6129e4f0155 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2890: Fix off-by-one error in UdtCodec - [improvement] JAVA-2905: Prevent new connections from using a protocol version higher than the negotiated one - [bug] JAVA-2647: Handle token types in QueryBuilder.literal() - [bug] JAVA-2887: Handle composite profiles with more than one key and/or backed by only one profile diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java index 15c993d76c3..d9b02d7ce3d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java @@ -104,7 +104,7 @@ public UdtValue decode(@Nullable ByteBuffer bytes, @NonNull ProtocolVersion prot UdtValue value = cqlType.newValue(); int i = 0; while (input.hasRemaining()) { - if (i > cqlType.getFieldTypes().size()) { + if (i == cqlType.getFieldTypes().size()) { throw new IllegalArgumentException( String.format( "Too many fields in encoded UDT value, expected %d", diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java index 1bbaaf0a2d5..383fd5a144f 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java @@ -133,6 +133,21 @@ public void should_decode_udt() { verify(textCodec).decode(Bytes.fromHexString("0x61"), ProtocolVersion.DEFAULT); } + @Test + public void should_fail_to_decode_udt_when_too_many_fields() { + assertThatThrownBy( + () -> + decode( + "0x" + + ("00000004" + "00000001") + + "ffffffff" + + ("00000001" + "61") + // extra contents + + "ffffffff")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Too many fields in encoded UDT value, expected 3"); + } + /** Test for JAVA-2557. Ensures that the codec can decode null fields with any negative length. */ @Test public void should_decode_negative_element_length_as_null_field() { From a7dc7b70d0b2f29302dab440aaa4d4117a560688 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 16:38:31 +0100 Subject: [PATCH 017/395] JAVA-2883: Use root locale explicitly when changing string case (#1509) This commit changes all occurrences of String.toLowerCase() in production code to use String.toLowerCase(Locale.ROOT) instead. No occurrences of String.toUpperCase() were found in production code. --- changelog/README.md | 1 + .../oss/driver/api/core/CqlIdentifier.java | 3 +- .../oss/driver/api/core/data/CqlDuration.java | 3 +- .../internal/core/data/IdentifierIndex.java | 5 +- .../schema/parsing/DataTypeCqlNameParser.java | 3 +- .../core/protocol/BuiltInCompressors.java | 3 +- .../protocol/CompressorSubstitutions.java | 5 +- .../internal/core/type/PrimitiveType.java | 3 +- .../driver/internal/core/util/Strings.java | 7 +- .../oss/driver/TestDataProviders.java | 21 ++ .../driver/api/core/CqlIdentifierTest.java | 30 +- .../driver/api/core/data/CqlDurationTest.java | 171 +++++++----- .../core/data/IdentifierIndexTest.java | 58 +++- .../parsing/DataTypeClassNameParserTest.java | 260 ++++++++++-------- .../core/protocol/BuiltInCompressorsTest.java | 70 +++++ .../internal/core/type/PrimitiveTypeTest.java | 118 ++++++++ .../internal/core/util/StringsTest.java | 168 +++++++++++ 17 files changed, 721 insertions(+), 208 deletions(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressorsTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/type/PrimitiveTypeTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/util/StringsTest.java diff --git a/changelog/README.md b/changelog/README.md index 6129e4f0155..886f96a7252 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2883: Use root locale explicitly when changing string case - [bug] JAVA-2890: Fix off-by-one error in UdtCodec - [improvement] JAVA-2905: Prevent new connections from using a protocol version higher than the negotiated one - [bug] JAVA-2647: Handle token types in QueryBuilder.literal() diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/CqlIdentifier.java b/core/src/main/java/com/datastax/oss/driver/api/core/CqlIdentifier.java index 89211d75382..922f4f2e5e5 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/CqlIdentifier.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/CqlIdentifier.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; +import java.util.Locale; import net.jcip.annotations.Immutable; /** @@ -75,7 +76,7 @@ public static CqlIdentifier fromCql(@NonNull String cql) { if (Strings.isDoubleQuoted(cql)) { internal = Strings.unDoubleQuote(cql); } else { - internal = cql.toLowerCase(); + internal = cql.toLowerCase(Locale.ROOT); Preconditions.checkArgument( !Strings.needsDoubleQuotes(internal), "Invalid CQL form [%s]: needs double quotes", cql); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java index 40b6b41ee60..8ec509ea7f6 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java @@ -28,6 +28,7 @@ import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.util.List; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.jcip.annotations.Immutable; @@ -232,7 +233,7 @@ private static long groupAsLong(@NonNull Matcher matcher, int group) { } private static Builder add(@NonNull Builder builder, long number, @NonNull String symbol) { - String s = symbol.toLowerCase(); + String s = symbol.toLowerCase(Locale.ROOT); if (s.equals("y")) { return builder.addYears(number); } else if (s.equals("mo")) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java index 17411c4e6d8..29396f08440 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java @@ -23,6 +23,7 @@ import com.datastax.oss.driver.shaded.guava.common.collect.LinkedListMultimap; import com.datastax.oss.driver.shaded.guava.common.collect.ListMultimap; import java.util.List; +import java.util.Locale; import net.jcip.annotations.Immutable; /** @@ -47,7 +48,7 @@ public IdentifierIndex(List ids) { for (CqlIdentifier id : ids) { byId.put(id, i); byCaseSensitiveName.put(id.asInternal(), i); - byCaseInsensitiveName.put(id.asInternal().toLowerCase(), i); + byCaseInsensitiveName.put(id.asInternal().toLowerCase(Locale.ROOT), i); i += 1; } } @@ -59,7 +60,7 @@ public IdentifierIndex(List ids) { public List allIndicesOf(String name) { return Strings.isDoubleQuoted(name) ? byCaseSensitiveName.get(Strings.unDoubleQuote(name)) - : byCaseInsensitiveName.get(name.toLowerCase()); + : byCaseInsensitiveName.get(name.toLowerCase(Locale.ROOT)); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java index b511c8cadc1..3523aa5c459 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java @@ -28,6 +28,7 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import net.jcip.annotations.ThreadSafe; @@ -68,7 +69,7 @@ private DataType parse( return DataTypes.custom(type); } - DataType nativeType = NATIVE_TYPES_BY_NAME.get(type.toLowerCase()); + DataType nativeType = NATIVE_TYPES_BY_NAME.get(type.toLowerCase(Locale.ROOT)); if (nativeType != null) { return nativeType; } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressors.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressors.java index 5f6ad6ec270..56fe96d0b83 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressors.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressors.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.protocol.internal.Compressor; import io.netty.buffer.ByteBuf; +import java.util.Locale; /** * Provides a single entry point to create compressor instances in the driver. @@ -29,7 +30,7 @@ public class BuiltInCompressors { public static Compressor newInstance(String name, DriverContext context) { - switch (name.toLowerCase()) { + switch (name.toLowerCase(Locale.ROOT)) { case "lz4": return new Lz4Compressor(context); case "snappy": diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java index e632a07a0ab..fe43bea0863 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java @@ -22,6 +22,7 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import io.netty.buffer.ByteBuf; +import java.util.Locale; import java.util.function.BooleanSupplier; /** @@ -38,7 +39,7 @@ public class CompressorSubstitutions { public static final class BuiltInCompressorsLz4Only { @Substitute public static Compressor newInstance(String name, DriverContext context) { - switch (name.toLowerCase()) { + switch (name.toLowerCase(Locale.ROOT)) { case "lz4": return new Lz4Compressor(context); case "snappy": @@ -59,7 +60,7 @@ public static Compressor newInstance(String name, DriverContext context public static final class NoBuiltInCompressors { @Substitute public static Compressor newInstance(String name, DriverContext context) { - switch (name.toLowerCase()) { + switch (name.toLowerCase(Locale.ROOT)) { case "lz4": throw new UnsupportedOperationException( "This native image was not built with support for LZ4 compression"); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/PrimitiveType.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/PrimitiveType.java index 909a58d053a..2eca544d07c 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/PrimitiveType.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/PrimitiveType.java @@ -20,6 +20,7 @@ import com.datastax.oss.protocol.internal.ProtocolConstants; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.Serializable; +import java.util.Locale; import net.jcip.annotations.Immutable; @Immutable @@ -67,7 +68,7 @@ public int hashCode() { @NonNull @Override public String asCql(boolean includeFrozen, boolean pretty) { - return codeName(protocolCode).toLowerCase(); + return codeName(protocolCode).toLowerCase(Locale.ROOT); } @Override diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java index eb95d2cbc18..b0aa9128c76 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java @@ -15,7 +15,9 @@ */ package com.datastax.oss.driver.internal.core.util; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import java.util.Locale; public class Strings { @@ -230,8 +232,9 @@ private static String unquote(String text, char quoteChar) { return new String(result); } - private static boolean isReservedCqlKeyword(String id) { - return id != null && RESERVED_KEYWORDS.contains(id.toLowerCase()); + @VisibleForTesting + static boolean isReservedCqlKeyword(String id) { + return id != null && RESERVED_KEYWORDS.contains(id.toLowerCase(Locale.ROOT)); } /** diff --git a/core/src/test/java/com/datastax/oss/driver/TestDataProviders.java b/core/src/test/java/com/datastax/oss/driver/TestDataProviders.java index 866a4bc9f75..734370996f7 100644 --- a/core/src/test/java/com/datastax/oss/driver/TestDataProviders.java +++ b/core/src/test/java/com/datastax/oss/driver/TestDataProviders.java @@ -17,6 +17,7 @@ import com.tngtech.java.junit.dataprovider.DataProvider; import java.util.Arrays; +import java.util.Locale; public class TestDataProviders { @@ -83,4 +84,24 @@ public static Object[][] combine(Object[][]... providers) { public static Object[][] booleans() { return fromList(true, false); } + + /** An arbitrary set of locales to use when testing locale-sensitive operations. */ + @DataProvider + public static Object[][] locales() { + return new Object[][] { + new Object[] {Locale.US}, + // non-latin alphabets + new Object[] {Locale.CHINA}, + new Object[] {Locale.JAPAN}, + new Object[] {Locale.KOREA}, + new Object[] {new Locale("gr") /* greek */}, + new Object[] {new Locale("ar") /* arabic */}, + // latin-based alphabets with extended character sets + new Object[] {new Locale("vi") /* vietnamese */}, + // JAVA-2883: Turkish is the most problematic locale as String.toLowerCase("TITLE") + // wouldn't return "title" but rather "tıtle", where 'ı' is the 'LATIN SMALL LETTER + // DOTLESS I' character specific to the Turkish language. + new Object[] {new Locale("tr") /* turkish*/}, + }; + } } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/CqlIdentifierTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/CqlIdentifierTest.java index db440007e92..4a0a692c7d7 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/CqlIdentifierTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/CqlIdentifierTest.java @@ -17,9 +17,16 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.datastax.oss.driver.TestDataProviders; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Locale; import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(DataProviderRunner.class) public class CqlIdentifierTest { + @Test public void should_build_from_internal() { assertThat(CqlIdentifier.fromInternal("foo").asInternal()).isEqualTo("foo"); @@ -30,13 +37,22 @@ public void should_build_from_internal() { } @Test - public void should_build_from_valid_cql() { - assertThat(CqlIdentifier.fromCql("foo").asInternal()).isEqualTo("foo"); - assertThat(CqlIdentifier.fromCql("Foo").asInternal()).isEqualTo("foo"); - assertThat(CqlIdentifier.fromCql("\"Foo\"").asInternal()).isEqualTo("Foo"); - assertThat(CqlIdentifier.fromCql("\"foo bar\"").asInternal()).isEqualTo("foo bar"); - assertThat(CqlIdentifier.fromCql("\"foo\"\"bar\"").asInternal()).isEqualTo("foo\"bar"); - assertThat(CqlIdentifier.fromCql("\"create\"").asInternal()).isEqualTo("create"); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_build_from_valid_cql(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(CqlIdentifier.fromCql("foo").asInternal()).isEqualTo("foo"); + assertThat(CqlIdentifier.fromCql("Foo").asInternal()).isEqualTo("foo"); + assertThat(CqlIdentifier.fromCql("\"Foo\"").asInternal()).isEqualTo("Foo"); + assertThat(CqlIdentifier.fromCql("\"foo bar\"").asInternal()).isEqualTo("foo bar"); + assertThat(CqlIdentifier.fromCql("\"foo\"\"bar\"").asInternal()).isEqualTo("foo\"bar"); + assertThat(CqlIdentifier.fromCql("\"create\"").asInternal()).isEqualTo("create"); + // JAVA-2883: this would fail under turkish locale if it was used internally + assertThat(CqlIdentifier.fromCql("TITLE").asInternal()).isEqualTo("title"); + } finally { + Locale.setDefault(def); + } } @Test(expected = IllegalArgumentException.class) diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java index a880f4a8579..56c0b00b5e3 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java @@ -19,92 +19,119 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.fail; +import com.datastax.oss.driver.TestDataProviders; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.time.temporal.UnsupportedTemporalTypeException; +import java.util.Locale; import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(DataProviderRunner.class) public class CqlDurationTest { @Test - public void should_parse_from_string_with_standard_pattern() { - assertThat(CqlDuration.from("1y2mo")).isEqualTo(CqlDuration.newInstance(14, 0, 0)); - assertThat(CqlDuration.from("-1y2mo")).isEqualTo(CqlDuration.newInstance(-14, 0, 0)); - assertThat(CqlDuration.from("1Y2MO")).isEqualTo(CqlDuration.newInstance(14, 0, 0)); - assertThat(CqlDuration.from("2w")).isEqualTo(CqlDuration.newInstance(0, 14, 0)); - assertThat(CqlDuration.from("2d10h")) - .isEqualTo(CqlDuration.newInstance(0, 2, 10 * CqlDuration.NANOS_PER_HOUR)); - assertThat(CqlDuration.from("2d")).isEqualTo(CqlDuration.newInstance(0, 2, 0)); - assertThat(CqlDuration.from("30h")) - .isEqualTo(CqlDuration.newInstance(0, 0, 30 * CqlDuration.NANOS_PER_HOUR)); - assertThat(CqlDuration.from("30h20m")) - .isEqualTo( - CqlDuration.newInstance( - 0, 0, 30 * CqlDuration.NANOS_PER_HOUR + 20 * CqlDuration.NANOS_PER_MINUTE)); - assertThat(CqlDuration.from("20m")) - .isEqualTo(CqlDuration.newInstance(0, 0, 20 * CqlDuration.NANOS_PER_MINUTE)); - assertThat(CqlDuration.from("56s")) - .isEqualTo(CqlDuration.newInstance(0, 0, 56 * CqlDuration.NANOS_PER_SECOND)); - assertThat(CqlDuration.from("567ms")) - .isEqualTo(CqlDuration.newInstance(0, 0, 567 * CqlDuration.NANOS_PER_MILLI)); - assertThat(CqlDuration.from("1950us")) - .isEqualTo(CqlDuration.newInstance(0, 0, 1950 * CqlDuration.NANOS_PER_MICRO)); - assertThat(CqlDuration.from("1950µs")) - .isEqualTo(CqlDuration.newInstance(0, 0, 1950 * CqlDuration.NANOS_PER_MICRO)); - assertThat(CqlDuration.from("1950000ns")).isEqualTo(CqlDuration.newInstance(0, 0, 1950000)); - assertThat(CqlDuration.from("1950000NS")).isEqualTo(CqlDuration.newInstance(0, 0, 1950000)); - assertThat(CqlDuration.from("-1950000ns")).isEqualTo(CqlDuration.newInstance(0, 0, -1950000)); - assertThat(CqlDuration.from("1y3mo2h10m")) - .isEqualTo(CqlDuration.newInstance(15, 0, 130 * CqlDuration.NANOS_PER_MINUTE)); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_from_string_with_standard_pattern(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(CqlDuration.from("1y2mo")).isEqualTo(CqlDuration.newInstance(14, 0, 0)); + assertThat(CqlDuration.from("-1y2mo")).isEqualTo(CqlDuration.newInstance(-14, 0, 0)); + assertThat(CqlDuration.from("1Y2MO")).isEqualTo(CqlDuration.newInstance(14, 0, 0)); + assertThat(CqlDuration.from("2w")).isEqualTo(CqlDuration.newInstance(0, 14, 0)); + assertThat(CqlDuration.from("2d10h")) + .isEqualTo(CqlDuration.newInstance(0, 2, 10 * CqlDuration.NANOS_PER_HOUR)); + assertThat(CqlDuration.from("2d")).isEqualTo(CqlDuration.newInstance(0, 2, 0)); + assertThat(CqlDuration.from("30h")) + .isEqualTo(CqlDuration.newInstance(0, 0, 30 * CqlDuration.NANOS_PER_HOUR)); + assertThat(CqlDuration.from("30h20m")) + .isEqualTo( + CqlDuration.newInstance( + 0, 0, 30 * CqlDuration.NANOS_PER_HOUR + 20 * CqlDuration.NANOS_PER_MINUTE)); + assertThat(CqlDuration.from("20m")) + .isEqualTo(CqlDuration.newInstance(0, 0, 20 * CqlDuration.NANOS_PER_MINUTE)); + assertThat(CqlDuration.from("56s")) + .isEqualTo(CqlDuration.newInstance(0, 0, 56 * CqlDuration.NANOS_PER_SECOND)); + assertThat(CqlDuration.from("567ms")) + .isEqualTo(CqlDuration.newInstance(0, 0, 567 * CqlDuration.NANOS_PER_MILLI)); + assertThat(CqlDuration.from("1950us")) + .isEqualTo(CqlDuration.newInstance(0, 0, 1950 * CqlDuration.NANOS_PER_MICRO)); + assertThat(CqlDuration.from("1950µs")) + .isEqualTo(CqlDuration.newInstance(0, 0, 1950 * CqlDuration.NANOS_PER_MICRO)); + assertThat(CqlDuration.from("1950000ns")).isEqualTo(CqlDuration.newInstance(0, 0, 1950000)); + assertThat(CqlDuration.from("1950000NS")).isEqualTo(CqlDuration.newInstance(0, 0, 1950000)); + assertThat(CqlDuration.from("-1950000ns")).isEqualTo(CqlDuration.newInstance(0, 0, -1950000)); + assertThat(CqlDuration.from("1y3mo2h10m")) + .isEqualTo(CqlDuration.newInstance(15, 0, 130 * CqlDuration.NANOS_PER_MINUTE)); + } finally { + Locale.setDefault(def); + } } @Test - public void should_parse_from_string_with_iso8601_pattern() { - assertThat(CqlDuration.from("P1Y2D")).isEqualTo(CqlDuration.newInstance(12, 2, 0)); - assertThat(CqlDuration.from("P1Y2M")).isEqualTo(CqlDuration.newInstance(14, 0, 0)); - assertThat(CqlDuration.from("P2W")).isEqualTo(CqlDuration.newInstance(0, 14, 0)); - assertThat(CqlDuration.from("P1YT2H")) - .isEqualTo(CqlDuration.newInstance(12, 0, 2 * CqlDuration.NANOS_PER_HOUR)); - assertThat(CqlDuration.from("-P1Y2M")).isEqualTo(CqlDuration.newInstance(-14, 0, 0)); - assertThat(CqlDuration.from("P2D")).isEqualTo(CqlDuration.newInstance(0, 2, 0)); - assertThat(CqlDuration.from("PT30H")) - .isEqualTo(CqlDuration.newInstance(0, 0, 30 * CqlDuration.NANOS_PER_HOUR)); - assertThat(CqlDuration.from("PT30H20M")) - .isEqualTo( - CqlDuration.newInstance( - 0, 0, 30 * CqlDuration.NANOS_PER_HOUR + 20 * CqlDuration.NANOS_PER_MINUTE)); - assertThat(CqlDuration.from("PT20M")) - .isEqualTo(CqlDuration.newInstance(0, 0, 20 * CqlDuration.NANOS_PER_MINUTE)); - assertThat(CqlDuration.from("PT56S")) - .isEqualTo(CqlDuration.newInstance(0, 0, 56 * CqlDuration.NANOS_PER_SECOND)); - assertThat(CqlDuration.from("P1Y3MT2H10M")) - .isEqualTo(CqlDuration.newInstance(15, 0, 130 * CqlDuration.NANOS_PER_MINUTE)); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_from_string_with_iso8601_pattern(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(CqlDuration.from("P1Y2D")).isEqualTo(CqlDuration.newInstance(12, 2, 0)); + assertThat(CqlDuration.from("P1Y2M")).isEqualTo(CqlDuration.newInstance(14, 0, 0)); + assertThat(CqlDuration.from("P2W")).isEqualTo(CqlDuration.newInstance(0, 14, 0)); + assertThat(CqlDuration.from("P1YT2H")) + .isEqualTo(CqlDuration.newInstance(12, 0, 2 * CqlDuration.NANOS_PER_HOUR)); + assertThat(CqlDuration.from("-P1Y2M")).isEqualTo(CqlDuration.newInstance(-14, 0, 0)); + assertThat(CqlDuration.from("P2D")).isEqualTo(CqlDuration.newInstance(0, 2, 0)); + assertThat(CqlDuration.from("PT30H")) + .isEqualTo(CqlDuration.newInstance(0, 0, 30 * CqlDuration.NANOS_PER_HOUR)); + assertThat(CqlDuration.from("PT30H20M")) + .isEqualTo( + CqlDuration.newInstance( + 0, 0, 30 * CqlDuration.NANOS_PER_HOUR + 20 * CqlDuration.NANOS_PER_MINUTE)); + assertThat(CqlDuration.from("PT20M")) + .isEqualTo(CqlDuration.newInstance(0, 0, 20 * CqlDuration.NANOS_PER_MINUTE)); + assertThat(CqlDuration.from("PT56S")) + .isEqualTo(CqlDuration.newInstance(0, 0, 56 * CqlDuration.NANOS_PER_SECOND)); + assertThat(CqlDuration.from("P1Y3MT2H10M")) + .isEqualTo(CqlDuration.newInstance(15, 0, 130 * CqlDuration.NANOS_PER_MINUTE)); + } finally { + Locale.setDefault(def); + } } @Test - public void should_parse_from_string_with_iso8601_alternative_pattern() { - assertThat(CqlDuration.from("P0001-00-02T00:00:00")) - .isEqualTo(CqlDuration.newInstance(12, 2, 0)); - assertThat(CqlDuration.from("P0001-02-00T00:00:00")) - .isEqualTo(CqlDuration.newInstance(14, 0, 0)); - assertThat(CqlDuration.from("P0001-00-00T02:00:00")) - .isEqualTo(CqlDuration.newInstance(12, 0, 2 * CqlDuration.NANOS_PER_HOUR)); - assertThat(CqlDuration.from("-P0001-02-00T00:00:00")) - .isEqualTo(CqlDuration.newInstance(-14, 0, 0)); - assertThat(CqlDuration.from("P0000-00-02T00:00:00")) - .isEqualTo(CqlDuration.newInstance(0, 2, 0)); - assertThat(CqlDuration.from("P0000-00-00T30:00:00")) - .isEqualTo(CqlDuration.newInstance(0, 0, 30 * CqlDuration.NANOS_PER_HOUR)); - assertThat(CqlDuration.from("P0000-00-00T30:20:00")) - .isEqualTo( - CqlDuration.newInstance( - 0, 0, 30 * CqlDuration.NANOS_PER_HOUR + 20 * CqlDuration.NANOS_PER_MINUTE)); - assertThat(CqlDuration.from("P0000-00-00T00:20:00")) - .isEqualTo(CqlDuration.newInstance(0, 0, 20 * CqlDuration.NANOS_PER_MINUTE)); - assertThat(CqlDuration.from("P0000-00-00T00:00:56")) - .isEqualTo(CqlDuration.newInstance(0, 0, 56 * CqlDuration.NANOS_PER_SECOND)); - assertThat(CqlDuration.from("P0001-03-00T02:10:00")) - .isEqualTo(CqlDuration.newInstance(15, 0, 130 * CqlDuration.NANOS_PER_MINUTE)); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_from_string_with_iso8601_alternative_pattern(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(CqlDuration.from("P0001-00-02T00:00:00")) + .isEqualTo(CqlDuration.newInstance(12, 2, 0)); + assertThat(CqlDuration.from("P0001-02-00T00:00:00")) + .isEqualTo(CqlDuration.newInstance(14, 0, 0)); + assertThat(CqlDuration.from("P0001-00-00T02:00:00")) + .isEqualTo(CqlDuration.newInstance(12, 0, 2 * CqlDuration.NANOS_PER_HOUR)); + assertThat(CqlDuration.from("-P0001-02-00T00:00:00")) + .isEqualTo(CqlDuration.newInstance(-14, 0, 0)); + assertThat(CqlDuration.from("P0000-00-02T00:00:00")) + .isEqualTo(CqlDuration.newInstance(0, 2, 0)); + assertThat(CqlDuration.from("P0000-00-00T30:00:00")) + .isEqualTo(CqlDuration.newInstance(0, 0, 30 * CqlDuration.NANOS_PER_HOUR)); + assertThat(CqlDuration.from("P0000-00-00T30:20:00")) + .isEqualTo( + CqlDuration.newInstance( + 0, 0, 30 * CqlDuration.NANOS_PER_HOUR + 20 * CqlDuration.NANOS_PER_MINUTE)); + assertThat(CqlDuration.from("P0000-00-00T00:20:00")) + .isEqualTo(CqlDuration.newInstance(0, 0, 20 * CqlDuration.NANOS_PER_MINUTE)); + assertThat(CqlDuration.from("P0000-00-00T00:00:56")) + .isEqualTo(CqlDuration.newInstance(0, 0, 56 * CqlDuration.NANOS_PER_SECOND)); + assertThat(CqlDuration.from("P0001-03-00T02:10:00")) + .isEqualTo(CqlDuration.newInstance(15, 0, 130 * CqlDuration.NANOS_PER_MINUTE)); + } finally { + Locale.setDefault(def); + } } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/data/IdentifierIndexTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/data/IdentifierIndexTest.java index 183e4c17fab..ee41fe0bdf0 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/data/IdentifierIndexTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/data/IdentifierIndexTest.java @@ -17,10 +17,16 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.datastax.oss.driver.TestDataProviders; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Locale; import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(DataProviderRunner.class) public class IdentifierIndexTest { private static final CqlIdentifier Foo = CqlIdentifier.fromInternal("Foo"); private static final CqlIdentifier foo = CqlIdentifier.fromInternal("foo"); @@ -41,13 +47,31 @@ public void should_not_find_index_of_nonexistent_identifier() { } @Test - public void should_find_first_index_of_case_insensitive_name() { - assertThat(index.firstIndexOf("foo")).isEqualTo(0); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_find_first_index_of_case_insensitive_name(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(index.firstIndexOf("foo")).isEqualTo(0); + assertThat(index.firstIndexOf("FOO")).isEqualTo(0); + assertThat(index.firstIndexOf("fOO")).isEqualTo(0); + } finally { + Locale.setDefault(def); + } } @Test - public void should_not_find_first_index_of_nonexistent_case_insensitive_name() { - assertThat(index.firstIndexOf("bar")).isEqualTo(-1); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_not_find_first_index_of_nonexistent_case_insensitive_name(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(index.firstIndexOf("bar")).isEqualTo(-1); + assertThat(index.firstIndexOf("BAR")).isEqualTo(-1); + assertThat(index.firstIndexOf("bAR")).isEqualTo(-1); + } finally { + Locale.setDefault(def); + } } @Test @@ -75,13 +99,31 @@ public void should_not_find_indices_of_nonexistent_identifier() { } @Test - public void should_all_indices_of_case_insensitive_name() { - assertThat(index.allIndicesOf("foo")).containsExactly(0, 1, 2, 3, 4, 5); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_find_all_indices_of_case_insensitive_name(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(index.allIndicesOf("foo")).containsExactly(0, 1, 2, 3, 4, 5); + assertThat(index.allIndicesOf("FOO")).containsExactly(0, 1, 2, 3, 4, 5); + assertThat(index.allIndicesOf("fOO")).containsExactly(0, 1, 2, 3, 4, 5); + } finally { + Locale.setDefault(def); + } } @Test - public void should_not_find_indices_of_nonexistent_case_insensitive_name() { - assertThat(index.allIndicesOf("bar")).isEmpty(); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_not_find_indices_of_nonexistent_case_insensitive_name(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(index.allIndicesOf("bar")).isEmpty(); + assertThat(index.allIndicesOf("BAR")).isEmpty(); + assertThat(index.allIndicesOf("bAR")).isEmpty(); + } finally { + Locale.setDefault(def); + } } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParserTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParserTest.java index 21ff579464d..9a0d3034821 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParserTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParserTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import com.datastax.oss.driver.TestDataProviders; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; @@ -27,14 +28,17 @@ import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Locale; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; -@RunWith(MockitoJUnitRunner.class) +@RunWith(DataProviderRunner.class) public class DataTypeClassNameParserTest { private static final CqlIdentifier KEYSPACE_ID = CqlIdentifier.fromInternal("ks"); @@ -44,131 +48,167 @@ public class DataTypeClassNameParserTest { @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); parser = new DataTypeClassNameParser(); } @Test - public void should_parse_native_types() { - for (Map.Entry entry : - DataTypeClassNameParser.NATIVE_TYPES_BY_CLASS_NAME.entrySet()) { - - String className = entry.getKey(); - DataType expectedType = entry.getValue(); - - assertThat(parse(className)).isEqualTo(expectedType); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_native_types(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + for (Map.Entry entry : + DataTypeClassNameParser.NATIVE_TYPES_BY_CLASS_NAME.entrySet()) { + + String className = entry.getKey(); + DataType expectedType = entry.getValue(); + + assertThat(parse(className)).isEqualTo(expectedType); + } + } finally { + Locale.setDefault(def); } } @Test - public void should_parse_collection_types() { - assertThat( - parse( - "org.apache.cassandra.db.marshal.ListType(" - + "org.apache.cassandra.db.marshal.UTF8Type)")) - .isEqualTo(DataTypes.listOf(DataTypes.TEXT)); - - assertThat( - parse( - "org.apache.cassandra.db.marshal.FrozenType(" - + ("org.apache.cassandra.db.marshal.ListType(" - + "org.apache.cassandra.db.marshal.UTF8Type))"))) - .isEqualTo(DataTypes.frozenListOf(DataTypes.TEXT)); - - assertThat( - parse( - "org.apache.cassandra.db.marshal.SetType(" - + "org.apache.cassandra.db.marshal.UTF8Type)")) - .isEqualTo(DataTypes.setOf(DataTypes.TEXT)); - - assertThat( - parse( - "org.apache.cassandra.db.marshal.MapType(" - + "org.apache.cassandra.db.marshal.UTF8Type," - + "org.apache.cassandra.db.marshal.UTF8Type)")) - .isEqualTo(DataTypes.mapOf(DataTypes.TEXT, DataTypes.TEXT)); - - assertThat( - parse( - "org.apache.cassandra.db.marshal.MapType(" - + "org.apache.cassandra.db.marshal.UTF8Type," - + "org.apache.cassandra.db.marshal.FrozenType(" - + ("org.apache.cassandra.db.marshal.MapType(" - + "org.apache.cassandra.db.marshal.Int32Type," - + "org.apache.cassandra.db.marshal.Int32Type)))"))) - .isEqualTo( - DataTypes.mapOf(DataTypes.TEXT, DataTypes.frozenMapOf(DataTypes.INT, DataTypes.INT))); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_collection_types(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat( + parse( + "org.apache.cassandra.db.marshal.ListType(" + + "org.apache.cassandra.db.marshal.UTF8Type)")) + .isEqualTo(DataTypes.listOf(DataTypes.TEXT)); + + assertThat( + parse( + "org.apache.cassandra.db.marshal.FrozenType(" + + ("org.apache.cassandra.db.marshal.ListType(" + + "org.apache.cassandra.db.marshal.UTF8Type))"))) + .isEqualTo(DataTypes.frozenListOf(DataTypes.TEXT)); + + assertThat( + parse( + "org.apache.cassandra.db.marshal.SetType(" + + "org.apache.cassandra.db.marshal.UTF8Type)")) + .isEqualTo(DataTypes.setOf(DataTypes.TEXT)); + + assertThat( + parse( + "org.apache.cassandra.db.marshal.MapType(" + + "org.apache.cassandra.db.marshal.UTF8Type," + + "org.apache.cassandra.db.marshal.UTF8Type)")) + .isEqualTo(DataTypes.mapOf(DataTypes.TEXT, DataTypes.TEXT)); + + assertThat( + parse( + "org.apache.cassandra.db.marshal.MapType(" + + "org.apache.cassandra.db.marshal.UTF8Type," + + "org.apache.cassandra.db.marshal.FrozenType(" + + ("org.apache.cassandra.db.marshal.MapType(" + + "org.apache.cassandra.db.marshal.Int32Type," + + "org.apache.cassandra.db.marshal.Int32Type)))"))) + .isEqualTo( + DataTypes.mapOf(DataTypes.TEXT, DataTypes.frozenMapOf(DataTypes.INT, DataTypes.INT))); + } finally { + Locale.setDefault(def); + } } @Test - public void should_parse_user_type_when_definition_not_already_available() { - UserDefinedType addressType = - (UserDefinedType) - parse( - "org.apache.cassandra.db.marshal.UserType(" - + "foo,61646472657373," - + ("737472656574:org.apache.cassandra.db.marshal.UTF8Type," - + "7a6970636f6465:org.apache.cassandra.db.marshal.Int32Type," - + ("70686f6e6573:org.apache.cassandra.db.marshal.SetType(" - + "org.apache.cassandra.db.marshal.UserType(foo,70686f6e65," - + "6e616d65:org.apache.cassandra.db.marshal.UTF8Type," - + "6e756d626572:org.apache.cassandra.db.marshal.UTF8Type)") - + "))")); - - assertThat(addressType.getKeyspace().asInternal()).isEqualTo("foo"); - assertThat(addressType.getName().asInternal()).isEqualTo("address"); - assertThat(addressType.isFrozen()).isTrue(); - assertThat(addressType.getFieldNames().size()).isEqualTo(3); - - assertThat(addressType.getFieldNames().get(0).asInternal()).isEqualTo("street"); - assertThat(addressType.getFieldTypes().get(0)).isEqualTo(DataTypes.TEXT); - - assertThat(addressType.getFieldNames().get(1).asInternal()).isEqualTo("zipcode"); - assertThat(addressType.getFieldTypes().get(1)).isEqualTo(DataTypes.INT); - - assertThat(addressType.getFieldNames().get(2).asInternal()).isEqualTo("phones"); - DataType phonesType = addressType.getFieldTypes().get(2); - assertThat(phonesType).isInstanceOf(SetType.class); - UserDefinedType phoneType = ((UserDefinedType) ((SetType) phonesType).getElementType()); - - assertThat(phoneType.getKeyspace().asInternal()).isEqualTo("foo"); - assertThat(phoneType.getName().asInternal()).isEqualTo("phone"); - assertThat(phoneType.isFrozen()).isTrue(); - assertThat(phoneType.getFieldNames().size()).isEqualTo(2); - - assertThat(phoneType.getFieldNames().get(0).asInternal()).isEqualTo("name"); - assertThat(phoneType.getFieldTypes().get(0)).isEqualTo(DataTypes.TEXT); - - assertThat(phoneType.getFieldNames().get(1).asInternal()).isEqualTo("number"); - assertThat(phoneType.getFieldTypes().get(1)).isEqualTo(DataTypes.TEXT); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_user_type_when_definition_not_already_available(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + UserDefinedType addressType = + (UserDefinedType) + parse( + "org.apache.cassandra.db.marshal.UserType(" + + "foo,61646472657373," + + ("737472656574:org.apache.cassandra.db.marshal.UTF8Type," + + "7a6970636f6465:org.apache.cassandra.db.marshal.Int32Type," + + ("70686f6e6573:org.apache.cassandra.db.marshal.SetType(" + + "org.apache.cassandra.db.marshal.UserType(foo,70686f6e65," + + "6e616d65:org.apache.cassandra.db.marshal.UTF8Type," + + "6e756d626572:org.apache.cassandra.db.marshal.UTF8Type)") + + "))")); + + assertThat(addressType.getKeyspace().asInternal()).isEqualTo("foo"); + assertThat(addressType.getName().asInternal()).isEqualTo("address"); + assertThat(addressType.isFrozen()).isTrue(); + assertThat(addressType.getFieldNames().size()).isEqualTo(3); + + assertThat(addressType.getFieldNames().get(0).asInternal()).isEqualTo("street"); + assertThat(addressType.getFieldTypes().get(0)).isEqualTo(DataTypes.TEXT); + + assertThat(addressType.getFieldNames().get(1).asInternal()).isEqualTo("zipcode"); + assertThat(addressType.getFieldTypes().get(1)).isEqualTo(DataTypes.INT); + + assertThat(addressType.getFieldNames().get(2).asInternal()).isEqualTo("phones"); + DataType phonesType = addressType.getFieldTypes().get(2); + assertThat(phonesType).isInstanceOf(SetType.class); + UserDefinedType phoneType = ((UserDefinedType) ((SetType) phonesType).getElementType()); + + assertThat(phoneType.getKeyspace().asInternal()).isEqualTo("foo"); + assertThat(phoneType.getName().asInternal()).isEqualTo("phone"); + assertThat(phoneType.isFrozen()).isTrue(); + assertThat(phoneType.getFieldNames().size()).isEqualTo(2); + + assertThat(phoneType.getFieldNames().get(0).asInternal()).isEqualTo("name"); + assertThat(phoneType.getFieldTypes().get(0)).isEqualTo(DataTypes.TEXT); + + assertThat(phoneType.getFieldNames().get(1).asInternal()).isEqualTo("number"); + assertThat(phoneType.getFieldTypes().get(1)).isEqualTo(DataTypes.TEXT); + } finally { + Locale.setDefault(def); + } } @Test - public void should_make_a_frozen_copy_user_type_when_definition_already_available() { - UserDefinedType existing = mock(UserDefinedType.class); - - parse( - "org.apache.cassandra.db.marshal.UserType(foo,70686f6e65," - + "6e616d65:org.apache.cassandra.db.marshal.UTF8Type," - + "6e756d626572:org.apache.cassandra.db.marshal.UTF8Type)", - ImmutableMap.of(CqlIdentifier.fromInternal("phone"), existing)); - - verify(existing).copy(true); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_make_a_frozen_copy_user_type_when_definition_already_available(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + UserDefinedType existing = mock(UserDefinedType.class); + + parse( + "org.apache.cassandra.db.marshal.UserType(foo,70686f6e65," + + "6e616d65:org.apache.cassandra.db.marshal.UTF8Type," + + "6e756d626572:org.apache.cassandra.db.marshal.UTF8Type)", + ImmutableMap.of(CqlIdentifier.fromInternal("phone"), existing)); + + verify(existing).copy(true); + } finally { + Locale.setDefault(def); + } } @Test - public void should_parse_tuple() { - TupleType tupleType = - (TupleType) - parse( - "org.apache.cassandra.db.marshal.TupleType(" - + "org.apache.cassandra.db.marshal.Int32Type," - + "org.apache.cassandra.db.marshal.UTF8Type," - + "org.apache.cassandra.db.marshal.FloatType)"); - - assertThat(tupleType.getComponentTypes().size()).isEqualTo(3); - assertThat(tupleType.getComponentTypes().get(0)).isEqualTo(DataTypes.INT); - assertThat(tupleType.getComponentTypes().get(1)).isEqualTo(DataTypes.TEXT); - assertThat(tupleType.getComponentTypes().get(2)).isEqualTo(DataTypes.FLOAT); + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_parse_tuple(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + TupleType tupleType = + (TupleType) + parse( + "org.apache.cassandra.db.marshal.TupleType(" + + "org.apache.cassandra.db.marshal.Int32Type," + + "org.apache.cassandra.db.marshal.UTF8Type," + + "org.apache.cassandra.db.marshal.FloatType)"); + + assertThat(tupleType.getComponentTypes().size()).isEqualTo(3); + assertThat(tupleType.getComponentTypes().get(0)).isEqualTo(DataTypes.INT); + assertThat(tupleType.getComponentTypes().get(1)).isEqualTo(DataTypes.TEXT); + assertThat(tupleType.getComponentTypes().get(2)).isEqualTo(DataTypes.FLOAT); + } finally { + Locale.setDefault(def); + } } private DataType parse(String toParse) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressorsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressorsTest.java new file mode 100644 index 00000000000..7680292ce32 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/BuiltInCompressorsTest.java @@ -0,0 +1,70 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.protocol; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.datastax.oss.driver.TestDataProviders; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.protocol.internal.NoopCompressor; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Locale; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(DataProviderRunner.class) +public class BuiltInCompressorsTest { + + @Mock private DriverContext context; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_create_instance_for_supported_algorithms(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(BuiltInCompressors.newInstance("lz4", context)).isInstanceOf(Lz4Compressor.class); + assertThat(BuiltInCompressors.newInstance("snappy", context)) + .isInstanceOf(SnappyCompressor.class); + assertThat(BuiltInCompressors.newInstance("none", context)) + .isInstanceOf(NoopCompressor.class); + assertThat(BuiltInCompressors.newInstance("LZ4", context)).isInstanceOf(Lz4Compressor.class); + assertThat(BuiltInCompressors.newInstance("SNAPPY", context)) + .isInstanceOf(SnappyCompressor.class); + assertThat(BuiltInCompressors.newInstance("NONE", context)) + .isInstanceOf(NoopCompressor.class); + } finally { + Locale.setDefault(def); + } + } + + @Test + public void should_throw_when_unsupported_algorithm() { + assertThatThrownBy(() -> BuiltInCompressors.newInstance("GZIP", context)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unsupported compression algorithm 'GZIP'"); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/PrimitiveTypeTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/PrimitiveTypeTest.java new file mode 100644 index 00000000000..a382a896571 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/PrimitiveTypeTest.java @@ -0,0 +1,118 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.TestDataProviders; +import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.protocol.internal.ProtocolConstants; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Locale; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class PrimitiveTypeTest { + + @Test + public void should_report_protocol_code() { + assertThat(DataTypes.ASCII.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.ASCII); + assertThat(DataTypes.BIGINT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.BIGINT); + assertThat(DataTypes.BLOB.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.BLOB); + assertThat(DataTypes.BOOLEAN.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.BOOLEAN); + assertThat(DataTypes.COUNTER.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.COUNTER); + assertThat(DataTypes.DECIMAL.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.DECIMAL); + assertThat(DataTypes.DOUBLE.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.DOUBLE); + assertThat(DataTypes.FLOAT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.FLOAT); + assertThat(DataTypes.INT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.INT); + assertThat(DataTypes.TIMESTAMP.getProtocolCode()) + .isEqualTo(ProtocolConstants.DataType.TIMESTAMP); + assertThat(DataTypes.UUID.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.UUID); + assertThat(DataTypes.VARINT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.VARINT); + assertThat(DataTypes.TIMEUUID.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.TIMEUUID); + assertThat(DataTypes.INET.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.INET); + assertThat(DataTypes.DATE.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.DATE); + assertThat(DataTypes.TEXT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.VARCHAR); + assertThat(DataTypes.TIME.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.TIME); + assertThat(DataTypes.SMALLINT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.SMALLINT); + assertThat(DataTypes.TINYINT.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.TINYINT); + assertThat(DataTypes.DURATION.getProtocolCode()).isEqualTo(ProtocolConstants.DataType.DURATION); + } + + @Test + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_format_as_cql(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(DataTypes.ASCII.asCql(true, true)).isEqualTo("ascii"); + assertThat(DataTypes.BIGINT.asCql(true, true)).isEqualTo("bigint"); + assertThat(DataTypes.BLOB.asCql(true, true)).isEqualTo("blob"); + assertThat(DataTypes.BOOLEAN.asCql(true, true)).isEqualTo("boolean"); + assertThat(DataTypes.COUNTER.asCql(true, true)).isEqualTo("counter"); + assertThat(DataTypes.DECIMAL.asCql(true, true)).isEqualTo("decimal"); + assertThat(DataTypes.DOUBLE.asCql(true, true)).isEqualTo("double"); + assertThat(DataTypes.FLOAT.asCql(true, true)).isEqualTo("float"); + assertThat(DataTypes.INT.asCql(true, true)).isEqualTo("int"); + assertThat(DataTypes.TIMESTAMP.asCql(true, true)).isEqualTo("timestamp"); + assertThat(DataTypes.UUID.asCql(true, true)).isEqualTo("uuid"); + assertThat(DataTypes.VARINT.asCql(true, true)).isEqualTo("varint"); + assertThat(DataTypes.TIMEUUID.asCql(true, true)).isEqualTo("timeuuid"); + assertThat(DataTypes.INET.asCql(true, true)).isEqualTo("inet"); + assertThat(DataTypes.DATE.asCql(true, true)).isEqualTo("date"); + assertThat(DataTypes.TEXT.asCql(true, true)).isEqualTo("text"); + assertThat(DataTypes.TIME.asCql(true, true)).isEqualTo("time"); + assertThat(DataTypes.SMALLINT.asCql(true, true)).isEqualTo("smallint"); + assertThat(DataTypes.TINYINT.asCql(true, true)).isEqualTo("tinyint"); + assertThat(DataTypes.DURATION.asCql(true, true)).isEqualTo("duration"); + } finally { + Locale.setDefault(def); + } + } + + @Test + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_format_as_string(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + assertThat(DataTypes.ASCII.toString()).isEqualTo("ASCII"); + assertThat(DataTypes.BIGINT.toString()).isEqualTo("BIGINT"); + assertThat(DataTypes.BLOB.toString()).isEqualTo("BLOB"); + assertThat(DataTypes.BOOLEAN.toString()).isEqualTo("BOOLEAN"); + assertThat(DataTypes.COUNTER.toString()).isEqualTo("COUNTER"); + assertThat(DataTypes.DECIMAL.toString()).isEqualTo("DECIMAL"); + assertThat(DataTypes.DOUBLE.toString()).isEqualTo("DOUBLE"); + assertThat(DataTypes.FLOAT.toString()).isEqualTo("FLOAT"); + assertThat(DataTypes.INT.toString()).isEqualTo("INT"); + assertThat(DataTypes.TIMESTAMP.toString()).isEqualTo("TIMESTAMP"); + assertThat(DataTypes.UUID.toString()).isEqualTo("UUID"); + assertThat(DataTypes.VARINT.toString()).isEqualTo("VARINT"); + assertThat(DataTypes.TIMEUUID.toString()).isEqualTo("TIMEUUID"); + assertThat(DataTypes.INET.toString()).isEqualTo("INET"); + assertThat(DataTypes.DATE.toString()).isEqualTo("DATE"); + assertThat(DataTypes.TEXT.toString()).isEqualTo("TEXT"); + assertThat(DataTypes.TIME.toString()).isEqualTo("TIME"); + assertThat(DataTypes.SMALLINT.toString()).isEqualTo("SMALLINT"); + assertThat(DataTypes.TINYINT.toString()).isEqualTo("TINYINT"); + assertThat(DataTypes.DURATION.toString()).isEqualTo("DURATION"); + } finally { + Locale.setDefault(def); + } + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/StringsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/StringsTest.java new file mode 100644 index 00000000000..2066a08ab84 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/StringsTest.java @@ -0,0 +1,168 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.TestDataProviders; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Locale; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class StringsTest { + + @Test + @UseDataProvider(location = TestDataProviders.class, value = "locales") + public void should_report_cql_keyword(Locale locale) { + Locale def = Locale.getDefault(); + try { + Locale.setDefault(locale); + + assertThat(Strings.isReservedCqlKeyword(null)).isFalse(); + assertThat(Strings.isReservedCqlKeyword("NOT A RESERVED KEYWORD")).isFalse(); + + assertThat(Strings.isReservedCqlKeyword("add")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("allow")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("alter")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("and")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("apply")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("asc")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("authorize")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("batch")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("begin")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("by")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("columnfamily")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("create")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("default")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("delete")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("desc")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("describe")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("drop")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("entries")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("execute")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("from")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("full")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("grant")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("if")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("in")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("index")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("infinity")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("insert")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("into")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("is")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("keyspace")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("limit")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("materialized")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("mbean")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("mbeans")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("modify")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("nan")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("norecursive")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("not")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("null")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("of")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("on")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("or")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("order")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("primary")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("rename")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("replace")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("revoke")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("schema")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("select")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("set")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("table")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("to")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("token")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("truncate")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("unlogged")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("unset")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("update")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("use")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("using")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("view")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("where")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("with")).isTrue(); + + assertThat(Strings.isReservedCqlKeyword("ALLOW")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("ALTER")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("AND")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("APPLY")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("ASC")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("AUTHORIZE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("BATCH")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("BEGIN")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("BY")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("COLUMNFAMILY")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("CREATE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("DEFAULT")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("DELETE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("DESC")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("DESCRIBE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("DROP")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("ENTRIES")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("EXECUTE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("FROM")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("FULL")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("GRANT")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("IF")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("IN")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("INDEX")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("INFINITY")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("INSERT")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("INTO")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("IS")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("KEYSPACE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("LIMIT")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("MATERIALIZED")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("MBEAN")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("MBEANS")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("MODIFY")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("NAN")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("NORECURSIVE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("NOT")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("NULL")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("OF")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("ON")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("OR")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("ORDER")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("PRIMARY")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("RENAME")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("REPLACE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("REVOKE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("SCHEMA")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("SELECT")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("SET")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("TABLE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("TO")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("TOKEN")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("TRUNCATE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("UNLOGGED")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("UNSET")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("UPDATE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("USE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("USING")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("VIEW")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("WHERE")).isTrue(); + assertThat(Strings.isReservedCqlKeyword("WITH")).isTrue(); + } finally { + Locale.setDefault(def); + } + } +} From 1a828416a8eb566522b84950c65a931101c3ff76 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 16:39:46 +0100 Subject: [PATCH 018/395] JAVA-2889: Remove TypeSafe imports from DriverConfigLoader (#1510) --- changelog/README.md | 1 + .../api/core/config/DriverConfigLoader.java | 52 ++------------- .../typesafe/DefaultDriverConfigLoader.java | 64 +++++++++++++++++++ manual/core/configuration/README.md | 25 +++++++- 4 files changed, 91 insertions(+), 51 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 886f96a7252..1743e46cb41 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2889: Remove TypeSafe imports from DriverConfigLoader - [bug] JAVA-2883: Use root locale explicitly when changing string case - [bug] JAVA-2890: Fix off-by-one error in UdtCodec - [improvement] JAVA-2905: Prevent new connections from using a protocol version higher than the negotiated one diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java index f4242592e06..fcc7ea41689 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java @@ -15,16 +15,12 @@ */ package com.datastax.oss.driver.api.core.config; -import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.internal.core.config.composite.CompositeDriverConfigLoader; import com.datastax.oss.driver.internal.core.config.map.MapBasedDriverConfigLoader; import com.datastax.oss.driver.internal.core.config.typesafe.DefaultDriverConfigLoader; import com.datastax.oss.driver.internal.core.config.typesafe.DefaultProgrammaticDriverConfigLoaderBuilder; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; -import com.typesafe.config.ConfigParseOptions; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.File; import java.net.URL; @@ -92,19 +88,7 @@ static DriverConfigLoader fromClasspath(@NonNull String resourceBaseName) { @NonNull static DriverConfigLoader fromClasspath( @NonNull String resourceBaseName, @NonNull ClassLoader appClassLoader) { - return new DefaultDriverConfigLoader( - () -> { - ConfigFactory.invalidateCaches(); - Config config = - ConfigFactory.defaultOverrides() - .withFallback( - ConfigFactory.parseResourcesAnySyntax( - resourceBaseName, - ConfigParseOptions.defaults().setClassLoader(appClassLoader))) - .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) - .resolve(); - return config.getConfig(DefaultDriverConfigLoader.DEFAULT_ROOT_PATH); - }); + return DefaultDriverConfigLoader.fromClasspath(resourceBaseName, appClassLoader); } /** @@ -154,16 +138,7 @@ static DriverConfigLoader fromPath(@NonNull Path file) { */ @NonNull static DriverConfigLoader fromFile(@NonNull File file) { - return new DefaultDriverConfigLoader( - () -> { - ConfigFactory.invalidateCaches(); - Config config = - ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseFileAnySyntax(file)) - .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) - .resolve(); - return config.getConfig(DefaultDriverConfigLoader.DEFAULT_ROOT_PATH); - }); + return DefaultDriverConfigLoader.fromFile(file); } /** @@ -188,16 +163,7 @@ static DriverConfigLoader fromFile(@NonNull File file) { */ @NonNull static DriverConfigLoader fromUrl(@NonNull URL url) { - return new DefaultDriverConfigLoader( - () -> { - ConfigFactory.invalidateCaches(); - Config config = - ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseURL(url)) - .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) - .resolve(); - return config.getConfig(DefaultDriverConfigLoader.DEFAULT_ROOT_PATH); - }); + return DefaultDriverConfigLoader.fromUrl(url); } /** @@ -227,17 +193,7 @@ static DriverConfigLoader fromUrl(@NonNull URL url) { */ @NonNull static DriverConfigLoader fromString(@NonNull String contents) { - return new DefaultDriverConfigLoader( - () -> { - ConfigFactory.invalidateCaches(); - Config config = - ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseString(contents)) - .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) - .resolve(); - return config.getConfig(DefaultDriverConfigLoader.DEFAULT_ROOT_PATH); - }, - false); + return DefaultDriverConfigLoader.fromString(contents); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java index 9b068443874..9f87960adc6 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java @@ -30,9 +30,12 @@ import com.datastax.oss.driver.internal.core.util.concurrent.RunOrSchedule; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigParseOptions; import edu.umd.cs.findbugs.annotations.NonNull; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.ScheduledFuture; +import java.io.File; +import java.net.URL; import java.time.Duration; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -65,6 +68,67 @@ public class DefaultDriverConfigLoader implements DriverConfigLoader { .getConfig(DEFAULT_ROOT_PATH); }; + @NonNull + public static DefaultDriverConfigLoader fromClasspath( + @NonNull String resourceBaseName, @NonNull ClassLoader appClassLoader) { + return new DefaultDriverConfigLoader( + () -> { + ConfigFactory.invalidateCaches(); + Config config = + ConfigFactory.defaultOverrides() + .withFallback( + ConfigFactory.parseResourcesAnySyntax( + resourceBaseName, + ConfigParseOptions.defaults().setClassLoader(appClassLoader))) + .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) + .resolve(); + return config.getConfig(DEFAULT_ROOT_PATH); + }); + } + + @NonNull + public static DriverConfigLoader fromFile(@NonNull File file) { + return new DefaultDriverConfigLoader( + () -> { + ConfigFactory.invalidateCaches(); + Config config = + ConfigFactory.defaultOverrides() + .withFallback(ConfigFactory.parseFileAnySyntax(file)) + .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) + .resolve(); + return config.getConfig(DEFAULT_ROOT_PATH); + }); + } + + @NonNull + public static DriverConfigLoader fromUrl(@NonNull URL url) { + return new DefaultDriverConfigLoader( + () -> { + ConfigFactory.invalidateCaches(); + Config config = + ConfigFactory.defaultOverrides() + .withFallback(ConfigFactory.parseURL(url)) + .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) + .resolve(); + return config.getConfig(DEFAULT_ROOT_PATH); + }); + } + + @NonNull + public static DefaultDriverConfigLoader fromString(@NonNull String contents) { + return new DefaultDriverConfigLoader( + () -> { + ConfigFactory.invalidateCaches(); + Config config = + ConfigFactory.defaultOverrides() + .withFallback(ConfigFactory.parseString(contents)) + .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())) + .resolve(); + return config.getConfig(DEFAULT_ROOT_PATH); + }, + false); + } + private final Supplier configSupplier; private final TypesafeDriverConfig driverConfig; private final boolean supportsReloading; diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index c99f7c29963..50432c499cf 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -351,9 +351,28 @@ CqlSession session = CqlSession.builder().withConfigLoader(loader).build(); If Typesafe Config doesn't work for you, it is possible to get rid of it entirely. -You will need to provide your own implementations of [DriverConfig] and [DriverExecutionProfile]. -Then write a [DriverConfigLoader] and pass it to the session at initialization, as shown in the -previous sections. Study the built-in implementation (package +Start by excluding Typesafe Config from the list of dependencies required by the driver; if you are +using Maven, this can be achieved as follows: + +```xml + + + com.datastax.oss + java-driver-core + ... + + + com.typesafe + config + + + + + +``` +Next, you will need to provide your own implementations of [DriverConfig] and +[DriverExecutionProfile]. Then write a [DriverConfigLoader] and pass it to the session at +initialization, as shown in the previous sections. Study the built-in implementation (package `com.datastax.oss.driver.internal.core.config.typesafe`) for reference. Reloading is not mandatory: you can choose not to implement it, and the driver will simply keep From a3fff9a6bce4ecb42ba7df90f6f454234facb782 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 16:41:42 +0100 Subject: [PATCH 019/395] JAVA-2894: Clarify usage of Statement.setQueryTimestamp (#1511) --- changelog/README.md | 1 + .../oss/driver/api/core/cql/Statement.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 1743e46cb41..f122a8c89c5 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [documentation] JAVA-2894: Clarify usage of Statement.setQueryTimestamp - [bug] JAVA-2889: Remove TypeSafe imports from DriverConfigLoader - [bug] JAVA-2883: Use root locale explicitly when changing string case - [bug] JAVA-2890: Fix off-by-one error in UdtCodec diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java b/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java index 52023d3a6b7..dcfd1420b53 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java @@ -255,7 +255,8 @@ default SelfT disableTracing() { } /** - * Returns the query timestamp, in microseconds, to send with the statement. + * Returns the query timestamp, in microseconds, to send with the statement. See {@link + * #setQueryTimestamp(long)} for details. * *

If this is equal to {@link #NO_DEFAULT_TIMESTAMP}, the {@link TimestampGenerator} configured * for this driver instance will be used to generate a timestamp. @@ -277,6 +278,19 @@ default long getDefaultTimestamp() { /** * Sets the query timestamp, in microseconds, to send with the statement. * + *

This is an alternative to appending a {@code USING TIMESTAMP} clause in the statement's + * query string, and has the advantage of sending the timestamp separately from the query string + * itself, which doesn't have to be modified when executing the same statement with different + * timestamps. Note that, if both a {@code USING TIMESTAMP} clause and a query timestamp are set + * for a given statement, the timestamp from the {@code USING TIMESTAMP} clause wins. + * + *

This method can be used on any instance of {@link SimpleStatement}, {@link BoundStatement} + * or {@link BatchStatement}. For a {@link BatchStatement}, the timestamp will apply to all its + * child statements; it is not possible to define per-child timestamps using this method, and + * consequently, if this method is called on a batch child statement, the provided timestamp will + * be silently ignored. If different timestamps are required for individual child statements, this + * can only be achieved with a custom {@code USING TIMESTAMP} clause in each child query. + * *

If this is equal to {@link #NO_DEFAULT_TIMESTAMP}, the {@link TimestampGenerator} configured * for this driver instance will be used to generate a timestamp. * From 1c580e2efdbbf05151a30d82c014cb5c3dfe415a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 16:54:49 +0100 Subject: [PATCH 020/395] JAVA-2893: Allow duplicate keys in DefaultProgrammaticDriverConfigLoaderBuilder (#1512) --- changelog/README.md | 1 + ...ultProgrammaticDriverConfigLoaderBuilder.java | 7 +++---- ...rogrammaticDriverConfigLoaderBuilderTest.java | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index f122a8c89c5..c05d8d6f5b6 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [improvement] JAVA-2893: Allow duplicate keys in DefaultProgrammaticDriverConfigLoaderBuilder - [documentation] JAVA-2894: Clarify usage of Statement.setQueryTimestamp - [bug] JAVA-2889: Remove TypeSafe imports from DriverConfigLoader - [bug] JAVA-2883: Use root locale explicitly when changing string case diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilder.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilder.java index 69f71b61643..3ec2f0d7500 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilder.java @@ -20,13 +20,13 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.config.DriverOption; import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder; -import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigValueFactory; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Duration; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -43,8 +43,7 @@ public class DefaultProgrammaticDriverConfigLoaderBuilder // Do not remove root path here, it must be done after merging configs .withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())); - private final NullAllowingImmutableMap.Builder values = - NullAllowingImmutableMap.builder(); + private final Map values = new HashMap<>(); private final Supplier fallbackSupplier; private final String rootPath; @@ -260,7 +259,7 @@ public DriverConfigLoader build() { private Config buildConfig() { Config config = ConfigFactory.empty(); - for (Map.Entry entry : values.build().entrySet()) { + for (Map.Entry entry : values.entrySet()) { config = config.withValue(entry.getKey(), ConfigValueFactory.fromAnyRef(entry.getValue())); } return config; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilderTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilderTest.java index 7e2b6041ff8..6159db508e7 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilderTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultProgrammaticDriverConfigLoaderBuilderTest.java @@ -29,6 +29,22 @@ public class DefaultProgrammaticDriverConfigLoaderBuilderTest { private static final String FALLBACK_CONFIG = "int1 = 1\nint2 = 2\nprofiles.profile1 { int1 = 11 }"; + @Test + public void should_override_option() { + DriverConfigLoader loader = + new DefaultProgrammaticDriverConfigLoaderBuilder( + () -> ConfigFactory.parseString(FALLBACK_CONFIG), "") + .withInt(MockOptions.INT1, 2) + .withInt(MockOptions.INT1, 3) + .withInt(MockOptions.INT1, 4) + .withInt(MockOptions.INT2, 3) + .withInt(MockOptions.INT2, 4) + .build(); + DriverConfig config = loader.getInitialConfig(); + assertThat(config.getDefaultProfile().getInt(MockOptions.INT1)).isEqualTo(4); + assertThat(config.getDefaultProfile().getInt(MockOptions.INT2)).isEqualTo(4); + } + @Test public void should_override_option_in_default_profile() { DriverConfigLoader loader = From 3059c89437473a652ffb216984557eb9ca64b1b8 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 19 Nov 2020 23:59:59 +0100 Subject: [PATCH 021/395] JAVA-2449: Use non-cryptographic random number generation in Uuids.random() --- changelog/README.md | 1 + .../core/insights/InsightsClient.java | 4 +- .../oss/driver/api/core/uuid/Uuids.java | 69 ++++++- .../oss/driver/api/core/uuid/UuidsTest.java | 168 +++++++++++++++--- .../concurrent/LimitConcurrencyCustom.java | 4 +- .../LimitConcurrencyCustomAsync.java | 4 +- .../LimitConcurrencyRequestThrottler.java | 4 +- .../mapper/KillrVideoMapperExample.java | 7 +- .../video/CreateVideoQueryProvider.java | 4 +- upgrade_guide/README.md | 24 +++ 10 files changed, 240 insertions(+), 49 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index c05d8d6f5b6..00845e97b3d 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [improvement] JAVA-2449: Use non-cryptographic random number generation in Uuids.random() - [improvement] JAVA-2893: Allow duplicate keys in DefaultProgrammaticDriverConfigLoaderBuilder - [documentation] JAVA-2894: Clarify usage of Statement.setQueryTimestamp - [bug] JAVA-2889: Remove TypeSafe imports from DriverConfigLoader diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/insights/InsightsClient.java b/core/src/main/java/com/datastax/dse/driver/internal/core/insights/InsightsClient.java index 3f02e2368a3..b3bbaed8b34 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/insights/InsightsClient.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/insights/InsightsClient.java @@ -41,6 +41,7 @@ import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.internal.core.adminrequest.AdminRequestHandler; import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; @@ -65,7 +66,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ScheduledExecutorService; @@ -90,7 +90,7 @@ public class InsightsClient { static final String DEFAULT_JAVA_APPLICATION = "Default Java Application"; private final ControlConnection controlConnection; - private final String id = UUID.randomUUID().toString(); + private final String id = Uuids.random().toString(); private final InsightsConfiguration insightsConfiguration; private final AtomicInteger numberOfStatusEventErrors = new AtomicInteger(); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java b/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java index 35cc37e8e7a..39ca0c48d5d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java @@ -36,6 +36,7 @@ import java.util.Properties; import java.util.Random; import java.util.Set; +import java.util.SplittableRandom; import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; @@ -263,11 +264,61 @@ private static long makeClockSeqAndNode() { /** * Creates a new random (version 4) UUID. * - *

This method is just a convenience for {@link UUID#randomUUID()}. + *

This method has received a new implementation as of driver 4.10. Unlike the JDK's + * {@link UUID#randomUUID()} method, it does not use anymore the cryptographic {@link + * java.security.SecureRandom} number generator. Instead, it uses the non-cryptographic {@link + * Random} class, with a different seed at every invocation. + * + *

Using a non-cryptographic generator has two advantages: + * + *

    + *
  1. UUID generation is much faster than with {@link UUID#randomUUID()}; + *
  2. Contrary to {@link UUID#randomUUID()}, UUID generation with this method does not require + * I/O and is not a blocking call, which makes this method better suited for non-blocking + * applications. + *
+ * + * Of course, this method is intended for usage where cryptographic strength is not required, such + * as when generating row identifiers for insertion in the database. If you still need + * cryptographic strength, consider using {@link Uuids#random(Random)} instead, and pass an + * instance of {@link java.security.SecureRandom}. */ @NonNull public static UUID random() { - return UUID.randomUUID(); + return random(new Random()); + } + + /** + * Creates a new random (version 4) UUID using the provided {@link Random} instance. + * + *

This method offers more flexibility than {@link #random()} as it allows to customize the + * {@link Random} instance to use, and also offers the possibility to reuse instances across + * successive calls. Reusing Random instances is the norm when using {@link + * java.util.concurrent.ThreadLocalRandom}, for instance; however other Random implementations may + * perform poorly under heavy thread contention. + * + *

Note: some Random implementations, such as {@link java.security.SecureRandom}, may trigger + * I/O activity during random number generation; these instances should not be used in + * non-blocking contexts. + */ + @NonNull + public static UUID random(@NonNull Random random) { + byte[] data = new byte[16]; + random.nextBytes(data); + return buildUuid(data, 4); + } + + /** + * Creates a new random (version 4) UUID using the provided {@link SplittableRandom} instance. + * + *

This method should be preferred to {@link #random()} when UUID generation happens in massive + * parallel computations, such as when using the ForkJoin framework. Note that {@link + * SplittableRandom} instances are not thread-safe. + */ + @NonNull + public static UUID random(@NonNull SplittableRandom random) { + byte[] data = toBytes(random.nextLong(), random.nextLong()); + return buildUuid(data, 4); } /** @@ -344,7 +395,7 @@ public static UUID nameBased(@NonNull UUID namespace, @NonNull byte[] name, int MessageDigest md = newMessageDigest(version); md.update(toBytes(namespace)); md.update(name); - return buildNamedUuid(md.digest(), version); + return buildUuid(md.digest(), version); } /** @@ -390,7 +441,7 @@ public static UUID nameBased(@NonNull byte[] namespaceAndName, int version) { } MessageDigest md = newMessageDigest(version); md.update(namespaceAndName); - return buildNamedUuid(md.digest(), version); + return buildUuid(md.digest(), version); } @NonNull @@ -408,7 +459,7 @@ private static MessageDigest newMessageDigest(int version) { } @NonNull - private static UUID buildNamedUuid(@NonNull byte[] data, int version) { + private static UUID buildUuid(@NonNull byte[] data, int version) { // clear and set version data[6] &= (byte) 0x0f; data[6] |= (byte) (version << 4); @@ -433,12 +484,16 @@ private static UUID fromBytes(byte[] data) { } private static byte[] toBytes(UUID uuid) { - byte[] out = new byte[16]; long msb = uuid.getMostSignificantBits(); + long lsb = uuid.getLeastSignificantBits(); + return toBytes(msb, lsb); + } + + private static byte[] toBytes(long msb, long lsb) { + byte[] out = new byte[16]; for (int i = 0; i < 8; i++) { out[i] = (byte) (msb >> ((7 - i) * 8)); } - long lsb = uuid.getLeastSignificantBits(); for (int i = 8; i < 16; i++) { out[i] = (byte) (lsb >> ((15 - i) * 8)); } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/uuid/UuidsTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/uuid/UuidsTest.java index 848aebc7f7a..7396c633f72 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/uuid/UuidsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/uuid/UuidsTest.java @@ -27,18 +27,122 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Arrays; import java.util.HashSet; import java.util.Random; import java.util.Set; +import java.util.SplittableRandom; import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(DataProviderRunner.class) public class UuidsTest { + @Test + public void should_generate_unique_random_uuids_Random() { + Set generated = serialGeneration(1_000_000, Uuids::random); + assertThat(generated).hasSize(1_000_000); + } + + @Test + public void should_generate_unique_random_uuids_shared_Random2() { + Random random = new Random(); + Set generated = serialGeneration(1_000_000, () -> Uuids.random(random)); + assertThat(generated).hasSize(1_000_000); + } + + @Test + public void should_generate_unique_random_uuids_across_threads_shared_Random() throws Exception { + Random random = new Random(); + Set generated = parallelGeneration(10, 10_000, () -> () -> Uuids.random(random)); + assertThat(generated).hasSize(10 * 10_000); + } + + @Test + public void should_generate_unique_random_uuids_shared_SecureRandom() { + SecureRandom random = new SecureRandom(); + Set generated = serialGeneration(1_000_000, () -> Uuids.random(random)); + assertThat(generated).hasSize(1_000_000); + } + + @Test + public void should_generate_unique_random_uuids_across_threads_shared_SecureRandom() + throws Exception { + SecureRandom random = new SecureRandom(); + Set generated = parallelGeneration(10, 10_000, () -> () -> Uuids.random(random)); + assertThat(generated).hasSize(10 * 10_000); + } + + @Test + public void should_generate_unique_random_uuids_ThreadLocalRandom() { + ThreadLocalRandom random = ThreadLocalRandom.current(); + Set generated = serialGeneration(1_000_000, () -> Uuids.random(random)); + assertThat(generated).hasSize(1_000_000); + } + + @Test + public void should_generate_unique_random_uuids_across_threads_ThreadLocalRandom() + throws Exception { + Set generated = + parallelGeneration( + 10, + 10_000, + () -> { + ThreadLocalRandom random = ThreadLocalRandom.current(); + return () -> Uuids.random(random); + }); + assertThat(generated).hasSize(10 * 10_000); + } + + @Test + public void should_generate_unique_random_uuids_Netty_ThreadLocalRandom() { + io.netty.util.internal.ThreadLocalRandom random = + io.netty.util.internal.ThreadLocalRandom.current(); + Set generated = serialGeneration(1_000_000, () -> Uuids.random(random)); + assertThat(generated).hasSize(1_000_000); + } + + @Test + public void should_generate_unique_random_uuids_across_threads_Netty_ThreadLocalRandom() + throws Exception { + Set generated = + parallelGeneration( + 10, + 10_000, + () -> { + io.netty.util.internal.ThreadLocalRandom random = + io.netty.util.internal.ThreadLocalRandom.current(); + return () -> Uuids.random(random); + }); + assertThat(generated).hasSize(10 * 10_000); + } + + @Test + public void should_generate_unique_random_uuids_SplittableRandom() { + SplittableRandom random = new SplittableRandom(); + Set generated = serialGeneration(1_000_000, () -> Uuids.random(random)); + assertThat(generated).hasSize(1_000_000); + } + + @Test + public void should_generate_unique_random_uuids_across_threads_SplittableRandom() + throws Exception { + Set generated = + parallelGeneration( + 10, + 10_000, + () -> { + SplittableRandom random = new SplittableRandom(); + return () -> Uuids.random(random); + }); + assertThat(generated).hasSize(10 * 10_000); + } + @Test @UseDataProvider("byteArrayNames") public void should_generate_name_based_uuid_from_namespace_and_byte_array( @@ -186,7 +290,7 @@ public void should_generate_timestamp_within_10_ms() { // The Uuids class does some computation at class initialization, which may screw up our // assumption below that Uuids.timeBased() takes less than 10ms, so force class loading now. - Uuids.random(); + Uuids.timeBased(); long start = System.currentTimeMillis(); UUID uuid = Uuids.timeBased(); @@ -203,34 +307,14 @@ public void should_generate_timestamp_within_10_ms() { @Test public void should_generate_unique_time_based_uuids() { - int count = 1_000_000; - Set generated = new HashSet<>(count); - - for (int i = 0; i < count; ++i) { - generated.add(Uuids.timeBased()); - } - - assertThat(generated).hasSize(count); + Set generated = serialGeneration(1_000_000, Uuids::timeBased); + assertThat(generated).hasSize(1_000_000); } @Test public void should_generate_unique_time_based_uuids_across_threads() throws Exception { - int threadCount = 10; - int uuidsPerThread = 10_000; - Set generated = new ConcurrentSkipListSet<>(); - - UUIDGenerator[] generators = new UUIDGenerator[threadCount]; - for (int i = 0; i < threadCount; i++) { - generators[i] = new UUIDGenerator(uuidsPerThread, generated); - } - for (int i = 0; i < threadCount; i++) { - generators[i].start(); - } - for (int i = 0; i < threadCount; i++) { - generators[i].join(); - } - - assertThat(generated).hasSize(threadCount * uuidsPerThread); + Set generated = parallelGeneration(10, 10_000, () -> Uuids::timeBased); + assertThat(generated).hasSize(10 * 10_000); } @Test @@ -362,20 +446,48 @@ private static byte[] longToBytes(long x) { return ByteBuffer.allocate(Long.BYTES).putLong(x).array(); } - private static class UUIDGenerator extends Thread { + private Set serialGeneration(int count, Supplier uuidSupplier) { + Set generated = new HashSet<>(count); + for (int i = 0; i < count; ++i) { + generated.add(uuidSupplier.get()); + } + return generated; + } + + public Set parallelGeneration( + int threadCount, int uuidsPerThread, Supplier> uuidSupplier) + throws InterruptedException { + Set generated = new ConcurrentSkipListSet<>(); + UuidGenerator[] generators = new UuidGenerator[threadCount]; + for (int i = 0; i < threadCount; i++) { + generators[i] = new UuidGenerator(uuidsPerThread, uuidSupplier, generated); + } + for (int i = 0; i < threadCount; i++) { + generators[i].start(); + } + for (int i = 0; i < threadCount; i++) { + generators[i].join(); + } + return generated; + } + + private static class UuidGenerator extends Thread { private final int toGenerate; private final Set generated; + private final Supplier> uuidSupplier; - UUIDGenerator(int toGenerate, Set generated) { + UuidGenerator(int toGenerate, Supplier> uuidSupplier, Set generated) { this.toGenerate = toGenerate; this.generated = generated; + this.uuidSupplier = uuidSupplier; } @Override public void run() { + Supplier uuidSupplier = this.uuidSupplier.get(); for (int i = 0; i < toGenerate; ++i) { - generated.add(Uuids.timeBased()); + generated.add(uuidSupplier.get()); } } } diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustom.java b/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustom.java index 9962d414044..64dca3cfcd0 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustom.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustom.java @@ -21,7 +21,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.CqlSessionBuilder; import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import java.util.UUID; +import com.datastax.oss.driver.api.core.uuid.Uuids; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -103,7 +103,7 @@ private static void insertConcurrent(CqlSession session) throws InterruptedExcep executor.submit( () -> { try { - session.execute(pst.bind().setUuid("id", UUID.randomUUID()).setInt("value", counter)); + session.execute(pst.bind().setUuid("id", Uuids.random()).setInt("value", counter)); insertsCounter.incrementAndGet(); } catch (Throwable t) { // On production you should leverage logger and use logger.error() method. diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustomAsync.java b/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustomAsync.java index 45287098e5d..73fd223c386 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustomAsync.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyCustomAsync.java @@ -22,9 +22,9 @@ import com.datastax.oss.driver.api.core.CqlSessionBuilder; import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.uuid.Uuids; import java.util.ArrayList; import java.util.List; -import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; @@ -124,7 +124,7 @@ private static CompletableFuture executeInsert( CqlSession session, PreparedStatement pst, int counter) { return session - .executeAsync(pst.bind().setUuid("id", UUID.randomUUID()).setInt("value", counter)) + .executeAsync(pst.bind().setUuid("id", Uuids.random()).setInt("value", counter)) .toCompletableFuture() .whenComplete( (BiConsumer) diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyRequestThrottler.java b/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyRequestThrottler.java index 995054f2c52..71ec8b24ccb 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyRequestThrottler.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/concurrent/LimitConcurrencyRequestThrottler.java @@ -21,10 +21,10 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; import java.util.ArrayList; import java.util.List; -import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -86,7 +86,7 @@ private static void insertConcurrent(CqlSession session) for (int i = 0; i < TOTAL_NUMBER_OF_INSERTS; i++) { pending.add( session - .executeAsync(pst.bind().setUuid("id", UUID.randomUUID()).setInt("value", i)) + .executeAsync(pst.bind().setUuid("id", Uuids.random()).setInt("value", i)) // Transform CompletionState toCompletableFuture to be able to wait for execution of // all using CompletableFuture.allOf .toCompletableFuture()); diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java index 4ad547767c8..790ed09ef07 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/KillrVideoMapperExample.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.PagingIterable; import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.examples.mapper.killrvideo.KillrVideoMapper; import com.datastax.oss.driver.examples.mapper.killrvideo.user.User; import com.datastax.oss.driver.examples.mapper.killrvideo.user.UserDao; @@ -39,7 +40,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.UUID; import java.util.stream.Collectors; /** @@ -87,8 +87,7 @@ public static void main(String[] args) { // Create a new user UserDao userDao = mapper.userDao(); - User user = - new User(UUID.randomUUID(), "test", "user", "testuser@example.com", Instant.now()); + User user = new User(Uuids.random(), "test", "user", "testuser@example.com", Instant.now()); if (userDao.create(user, "fakePasswordForTests".toCharArray())) { System.out.println("Created " + user); @@ -99,7 +98,7 @@ public static void main(String[] args) { // Creating another user with the same email should fail assert !userDao.create( - new User(UUID.randomUUID(), "test2", "user", "testuser@example.com", Instant.now()), + new User(Uuids.random(), "test2", "user", "testuser@example.com", Instant.now()), "fakePasswordForTests2".toCharArray()); // Simulate login attempts diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java index 85704290903..6ec1c7b1aaf 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java @@ -22,13 +22,13 @@ import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; import com.datastax.oss.driver.api.core.cql.DefaultBatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.mapper.MapperContext; import com.datastax.oss.driver.api.mapper.entity.EntityHelper; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; -import java.util.UUID; /** * Provides the implementation of {@link VideoDao#create}. @@ -68,7 +68,7 @@ class CreateVideoQueryProvider { void create(Video video) { if (video.getVideoid() == null) { - video.setVideoid(UUID.randomUUID()); + video.setVideoid(Uuids.random()); } if (video.getAddedDate() == null) { video.setAddedDate(Instant.now()); diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 8451778c92e..a873731705b 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,29 @@ ## Upgrade guide +### 4.10.0 + +[JAVA-2449](https://datastax-oss.atlassian.net/browse/JAVA-2449) modified the implementation of +[Uuids.random()]: this method does not delegate anymore to the JDK's `java.util.UUID.randomUUID()` +implementation, but instead re-implements random UUID generation using the non-cryptographic +random number generator `java.util.Random`. + +For most users, non cryptographic strength is enough and this change should translate into better +performance when generating UUIDs for database insertion. However, in the unlikely case where your +application requires cryptographic strength for UUID generation, you should update your code to +use `java.util.UUID.randomUUID()` instead of `com.datastax.oss.driver.api.core.uuid.Uuids.random()` +from now on. + +This release also introduces two new methods for random UUID generation: + +1. [Uuids.random(Random)]: similar to `Uuids.random()` but allows to pass a custom instance of + `java.util.Random` and/or re-use the same instance across calls. +2. [Uuids.random(SplittableRandom)]: similar to `Uuids.random()` but uses a + `java.util.SplittableRandom` instead. + +[Uuids.random()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[Uuids.random(Random)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.Random- +[Uuids.random(SplittableRandom)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.SplittableRandom- + ### 4.5.x - 4.6.0 These versions are subject to [JAVA-2676](https://datastax-oss.atlassian.net/browse/JAVA-2676), a From 2765972530d914bc32e749cc053fab22eab526b4 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 20 Nov 2020 00:02:02 +0100 Subject: [PATCH 022/395] Replace Uuids.makeEpoch() with compile-time constant --- .../oss/driver/api/core/uuid/Uuids.java | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java b/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java index 39ca0c48d5d..4b63dee3055 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java @@ -28,7 +28,6 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; @@ -37,7 +36,6 @@ import java.util.Random; import java.util.Set; import java.util.SplittableRandom; -import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; @@ -113,7 +111,16 @@ public final class Uuids { private Uuids() {} - private static final long START_EPOCH = makeEpoch(); + /** + * UUID v1 timestamps must be expressed relatively to October 15th, 1582 – the day when Gregorian + * calendar was introduced. This constant captures that moment in time expressed in milliseconds + * before the Unix epoch. It can be obtained by calling: + * + *

+   *   Instant.parse("1582-10-15T00:00:00Z").toEpochMilli();
+   * 
+ */ + private static final long START_EPOCH_MILLIS = -12219292800000L; // Lazily initialize clock seq + node value at time of first access. Quarkus will attempt to // initialize this class at deployment time which prevents us from just setting this value @@ -157,19 +164,6 @@ private long get() { private static final AtomicLong lastTimestamp = new AtomicLong(0L); - private static long makeEpoch() { - // UUID v1 timestamps must be in 100-nanoseconds interval since 00:00:00.000 15 Oct 1582. - Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT-0")); - c.set(Calendar.YEAR, 1582); - c.set(Calendar.MONTH, Calendar.OCTOBER); - c.set(Calendar.DAY_OF_MONTH, 15); - c.set(Calendar.HOUR_OF_DAY, 0); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - return c.getTimeInMillis(); - } - private static long makeNode() { // We don't have access to the MAC address (in pure JAVA at least) but need to generate a node @@ -590,7 +584,7 @@ public static long unixTimestamp(@NonNull UUID uuid) { uuid.version())); } long timestamp = uuid.timestamp(); - return (timestamp / 10000) + START_EPOCH; + return (timestamp / 10000) + START_EPOCH_MILLIS; } // Use {@link System#currentTimeMillis} for a base time in milliseconds, and if we are in the same @@ -627,7 +621,7 @@ private static long getCurrentTimestamp() { @VisibleForTesting static long fromUnixTimestamp(long tstamp) { - return (tstamp - START_EPOCH) * 10000; + return (tstamp - START_EPOCH_MILLIS) * 10000; } private static long millisOf(long timestamp) { From 8fb2007632b5981d855da29439042c186d909644 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 17:04:17 +0100 Subject: [PATCH 023/395] Bulk upgrade of driver dependencies + test fixes (#1517) --- core/revapi.json | 2 +- .../statement/GraphTraversalBatchITBase.java | 4 +- .../osgi/checks/GeoServiceChecks.java | 2 +- pom.xml | 72 +++++++++---------- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/core/revapi.json b/core/revapi.json index b42dd7ca74f..8bf661b8544 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -5028,7 +5028,7 @@ }, { "code": "java.class.nonPublicPartOfAPI", - "new": "class com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder.Node", + "new": "class com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder.Node", "justification": "Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" } ] diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalBatchITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalBatchITBase.java index 264677b3174..413df0c0436 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalBatchITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalBatchITBase.java @@ -151,9 +151,7 @@ public void should_fail_if_no_bytecode_in_batch() { "Should have thrown InvalidQueryException because batch does not contain any traversals."); } catch (InvalidQueryException e) { assertThat(e.getMessage()) - .contains( - "Could not read the traversal from the request sent.", - "The batch statement sent does not contain any traversal."); + .contains("The batch statement sent does not contain any traversal"); } } } diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/checks/GeoServiceChecks.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/checks/GeoServiceChecks.java index 2d93ed93026..4aae717502c 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/checks/GeoServiceChecks.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/checks/GeoServiceChecks.java @@ -38,7 +38,7 @@ public static void checkServiceGeo(GeoMailboxService service) throws Exception { service.sendGeoMessage(message); } Iterable retrievedMessages = service.getGeoMessages(recipient); - assertThat(retrievedMessages).containsExactlyElementsOf(insertedMessages); + assertThat(retrievedMessages).containsExactlyInAnyOrderElementsOf(insertedMessages); } finally { service.clearGeoMailbox(recipient); } diff --git a/pom.xml b/pom.xml index 437ef30d7d2..83a04f9b198 100644 --- a/pom.xml +++ b/pom.xml @@ -45,40 +45,40 @@ true UTF-8 UTF-8 - 1.3.4 - 2.1.11 - 4.0.5 + 1.4.1 + 2.1.12 + 4.1.16 4.1.51.Final 1.2.1 3.4.8 1.7.26 - 1.0.2 - 20190722 + 1.0.3 + 20201115 2.11.0 2.11.0 1.9.12 - 1.1.7.3 - 1.6.0 + 1.1.8.1 + 1.7.1 - 3.13.1 + 3.18.1 1.3 4.13.1 1.2.3 6.0.0 6.0.3 - 4.13.3 - 0.8.9 - 1.0 + 4.13.4 + 0.10.0 + 1.1.4 2.28 2.5.0 - 2.0.1 + 2.1.1 1.1.4 - 2.2.2 - 4.0.2 + 2.2.20 + 4.0.3 2.0.0-M19 2.22.2 - 20.0.0 + 20.3.0 false ${skipTests} @@ -129,7 +129,7 @@ com.github.jnr jnr-posix - 3.0.50 + 3.1.2 io.dropwizard.metrics @@ -202,7 +202,7 @@ com.squareup javapoet - 1.11.1 + 1.13.0 junit @@ -267,7 +267,7 @@ org.ops4j.pax.url pax-url-wrap - 2.5.4 + 2.6.3 org.ops4j.pax.url @@ -322,7 +322,7 @@ javax.annotation javax.annotation-api - 1.2 + 1.3.2 com.fasterxml.jackson.core @@ -337,7 +337,7 @@ com.google.testing.compile compile-testing - 0.18 + 0.19 org.awaitility @@ -347,7 +347,7 @@ org.testng testng - 6.14.3 + 7.3.0 org.apache.directory.server @@ -408,7 +408,7 @@ io.micrometer micrometer-core - 1.5.0 + 1.6.1 org.eclipse.microprofile.metrics @@ -418,7 +418,7 @@ io.smallrye smallrye-metrics - 2.4.2 + 2.4.4 @@ -427,7 +427,7 @@ maven-compiler-plugin - 3.6.1 + 3.8.1 com.coveo @@ -454,11 +454,11 @@ maven-shade-plugin - 3.1.1 + 3.2.3 maven-assembly-plugin - 3.1.0 + 3.3.0 @@ -475,15 +475,15 @@ maven-source-plugin - 3.0.1 + 3.1.0 maven-javadoc-plugin - 3.1.1 + 3.2.0 maven-jar-plugin - 3.0.2 + 3.2.0 org.sonatype.plugins @@ -492,7 +492,7 @@ maven-gpg-plugin - 1.5 + 1.6 maven-release-plugin @@ -500,25 +500,25 @@ maven-install-plugin - 2.4 + 2.5.2 maven-deploy-plugin - 2.7 + 2.8.2 maven-dependency-plugin - 3.1.1 + 3.1.2 org.jacoco jacoco-maven-plugin - 0.8.3 + 0.8.5 org.apache.felix maven-bundle-plugin - 3.5.1 + 4.2.1 org.revapi @@ -540,7 +540,7 @@ org.revapi revapi-java - 0.19.1 + 0.22.1 From 3506c24a4fdbb954915fdd44d8ca96c3ca2317bb Mon Sep 17 00:00:00 2001 From: Olivier Michallat Date: Fri, 18 Dec 2020 08:44:43 -0800 Subject: [PATCH 024/395] JAVA-2871: Allow keyspace exclusions in the metadata, and exclude system keyspaces by default (#1500) Co-authored-by: Alexandre Dutra --- changelog/README.md | 2 + .../driver/api/core/config/OptionsMap.java | 4 + .../queries/CassandraSchemaQueries.java | 26 +-- .../schema/queries/CassandraSchemaRows.java | 25 ++- .../schema/queries/KeyspaceFilter.java | 58 +++++ .../queries/RuleBasedKeyspaceFilter.java | 201 ++++++++++++++++++ core/src/main/resources/reference.conf | 35 ++- .../schema/parsing/AggregateParserTest.java | 2 + .../schema/parsing/SchemaParserTest.java | 3 +- .../schema/parsing/SchemaParserTestBase.java | 9 + .../schema/parsing/TableParserTest.java | 2 +- .../schema/parsing/ViewParserTest.java | 2 +- .../queries/Cassandra3SchemaQueriesTest.java | 2 +- .../schema/queries/KeyspaceFilterTest.java | 141 ++++++++++++ manual/core/metadata/schema/README.md | 52 ++++- 15 files changed, 528 insertions(+), 36 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilter.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/RuleBasedKeyspaceFilter.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilterTest.java diff --git a/changelog/README.md b/changelog/README.md index 00845e97b3d..ccd1f87e1a1 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,8 @@ ### 4.10.0 (in progress) +- [improvement] JAVA-2871: Allow keyspace exclusions in the metadata, and exclude system keyspaces + by default - [improvement] JAVA-2449: Use non-cryptographic random number generation in Uuids.random() - [improvement] JAVA-2893: Allow duplicate keys in DefaultProgrammaticDriverConfigLoaderBuilder - [documentation] JAVA-2894: Clarify usage of Statement.setQueryTimestamp diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 6de7fc76355..5123e341036 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -15,6 +15,7 @@ */ package com.datastax.oss.driver.api.core.config; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.io.InvalidObjectException; @@ -339,6 +340,9 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.METADATA_TOPOLOGY_WINDOW, Duration.ofSeconds(1)); map.put(TypedDriverOption.METADATA_TOPOLOGY_MAX_EVENTS, 20); map.put(TypedDriverOption.METADATA_SCHEMA_ENABLED, true); + map.put( + TypedDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, + ImmutableList.of("!system", "!/^system_.*/", "!/^dse_.*/", "!solr_admin")); map.put(TypedDriverOption.METADATA_SCHEMA_REQUEST_TIMEOUT, requestTimeout); map.put(TypedDriverOption.METADATA_SCHEMA_REQUEST_PAGE_SIZE, requestPageSize); map.put(TypedDriverOption.METADATA_SCHEMA_WINDOW, Duration.ofSeconds(1)); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaQueries.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaQueries.java index e0bece6929b..69a0788bb8a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaQueries.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaQueries.java @@ -48,7 +48,7 @@ public abstract class CassandraSchemaQueries implements SchemaQueries { private final String logPrefix; private final Duration timeout; private final int pageSize; - private final String whereClause; + private final KeyspaceFilter keyspaceFilter; // The future we return from execute, completes when all the queries are done. private final CompletableFuture schemaRowsFuture = new CompletableFuture<>(); private final long startTimeNs = System.nanoTime(); @@ -69,25 +69,8 @@ protected CassandraSchemaQueries( List refreshedKeyspaces = config.getStringList( DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, Collections.emptyList()); - this.whereClause = buildWhereClause(refreshedKeyspaces); - } - - private static String buildWhereClause(List refreshedKeyspaces) { - if (refreshedKeyspaces.isEmpty()) { - return ""; - } else { - StringBuilder builder = new StringBuilder(" WHERE keyspace_name in ("); - boolean first = true; - for (String keyspace : refreshedKeyspaces) { - if (first) { - first = false; - } else { - builder.append(","); - } - builder.append('\'').append(keyspace).append('\''); - } - return builder.append(")").toString(); - } + assert refreshedKeyspaces != null; // per the default value + this.keyspaceFilter = KeyspaceFilter.newInstance(logPrefix, refreshedKeyspaces); } protected abstract String selectKeyspacesQuery(); @@ -125,7 +108,8 @@ public CompletionStage execute() { private void executeOnAdminExecutor() { assert adminExecutor.inEventLoop(); - schemaRowsBuilder = new CassandraSchemaRows.Builder(node, logPrefix); + schemaRowsBuilder = new CassandraSchemaRows.Builder(node, keyspaceFilter, logPrefix); + String whereClause = keyspaceFilter.getWhereClause(); query(selectKeyspacesQuery() + whereClause, schemaRowsBuilder::withKeyspaces); query(selectTypesQuery() + whereClause, schemaRowsBuilder::withTypes); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaRows.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaRows.java index 01a380308c4..7b43cd2664f 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaRows.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/CassandraSchemaRows.java @@ -170,6 +170,7 @@ public static class Builder { private final Node node; private final DataTypeParser dataTypeParser; private final String tableNameColumn; + private final KeyspaceFilter keyspaceFilter; private final String logPrefix; private final ImmutableList.Builder keyspacesBuilder = ImmutableList.builder(); private final ImmutableList.Builder virtualKeyspacesBuilder = ImmutableList.builder(); @@ -196,8 +197,9 @@ public static class Builder { private final Map> edgesBuilders = new LinkedHashMap<>(); - public Builder(Node node, String logPrefix) { + public Builder(Node node, KeyspaceFilter keyspaceFilter, String logPrefix) { this.node = node; + this.keyspaceFilter = keyspaceFilter; this.logPrefix = logPrefix; if (isCassandraV3OrAbove(node)) { this.tableNameColumn = "table_name"; @@ -229,12 +231,16 @@ private static boolean isCassandraV3OrAbove(Node node) { } public Builder withKeyspaces(Iterable rows) { - keyspacesBuilder.addAll(rows); + for (AdminRow row : rows) { + put(keyspacesBuilder, row); + } return this; } public Builder withVirtualKeyspaces(Iterable rows) { - virtualKeyspacesBuilder.addAll(rows); + for (AdminRow row : rows) { + put(virtualKeyspacesBuilder, row); + } return this; } @@ -315,12 +321,21 @@ public Builder withEdges(Iterable rows) { return this; } + private void put(ImmutableList.Builder builder, AdminRow row) { + String keyspace = row.getString("keyspace_name"); + if (keyspace == null) { + LOG.warn("[{}] Skipping system row with missing keyspace name", logPrefix); + } else if (keyspaceFilter.includes(keyspace)) { + builder.add(row); + } + } + private void putByKeyspace( AdminRow row, ImmutableMultimap.Builder builder) { String keyspace = row.getString("keyspace_name"); if (keyspace == null) { LOG.warn("[{}] Skipping system row with missing keyspace name", logPrefix); - } else { + } else if (keyspaceFilter.includes(keyspace)) { builder.put(CqlIdentifier.fromInternal(keyspace), row); } } @@ -334,7 +349,7 @@ private void putByKeyspaceAndTable( LOG.warn("[{}] Skipping system row with missing keyspace name", logPrefix); } else if (table == null) { LOG.warn("[{}] Skipping system row with missing table name", logPrefix); - } else { + } else if (keyspaceFilter.includes(keyspace)) { ImmutableMultimap.Builder builder = builders.computeIfAbsent( CqlIdentifier.fromInternal(keyspace), s -> ImmutableListMultimap.builder()); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilter.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilter.java new file mode 100644 index 00000000000..b82ea69b172 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilter.java @@ -0,0 +1,58 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata.schema.queries; + +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.List; + +/** + * Filters keyspaces during schema metadata queries. + * + *

Depending on the circumstances, we do it either on the server side with a WHERE IN clause that + * will be appended to every query, or on the client side with a predicate that will be applied to + * every fetched row. + */ +public interface KeyspaceFilter { + + static KeyspaceFilter newInstance(@NonNull String logPrefix, @NonNull List specs) { + if (specs.isEmpty()) { + return INCLUDE_ALL; + } else { + return new RuleBasedKeyspaceFilter(logPrefix, specs); + } + } + + /** The WHERE IN clause, or an empty string if there is no server-side filtering. */ + @NonNull + String getWhereClause(); + + /** The predicate that will be invoked for client-side filtering. */ + boolean includes(@NonNull String keyspace); + + KeyspaceFilter INCLUDE_ALL = + new KeyspaceFilter() { + @NonNull + @Override + public String getWhereClause() { + return ""; + } + + @Override + public boolean includes(@NonNull String keyspace) { + return true; + } + }; +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/RuleBasedKeyspaceFilter.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/RuleBasedKeyspaceFilter.java new file mode 100644 index 00000000000..20069aa796f --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/RuleBasedKeyspaceFilter.java @@ -0,0 +1,201 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata.schema.queries; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Filters keyspaces during schema metadata queries. + * + *

Depending on the circumstances, we do it either on the server side with a WHERE IN clause that + * will be appended to every query, or on the client side with a predicate that will be applied to + * every fetched row. + */ +class RuleBasedKeyspaceFilter implements KeyspaceFilter { + + private static final Logger LOG = LoggerFactory.getLogger(RuleBasedKeyspaceFilter.class); + + private static final Pattern EXACT_INCLUDE = Pattern.compile("\\w+"); + private static final Pattern EXACT_EXCLUDE = Pattern.compile("!\\s*(\\w+)"); + private static final Pattern REGEX_INCLUDE = Pattern.compile("/(.+)/"); + private static final Pattern REGEX_EXCLUDE = Pattern.compile("!\\s*/(.+)/"); + + private final String logPrefix; + private final String whereClause; + private final Set exactIncludes = new HashSet<>(); + private final Set exactExcludes = new HashSet<>(); + private final List> regexIncludes = new ArrayList<>(); + private final List> regexExcludes = new ArrayList<>(); + + private final boolean isDebugEnabled; + private final Set loggedKeyspaces; + + RuleBasedKeyspaceFilter(@NonNull String logPrefix, @NonNull List specs) { + assert !specs.isEmpty(); // see KeyspaceFilter#newInstance + + this.logPrefix = logPrefix; + for (String spec : specs) { + spec = spec.trim(); + Matcher matcher; + if (EXACT_INCLUDE.matcher(spec).matches()) { + exactIncludes.add(spec); + if (exactExcludes.remove(spec)) { + LOG.warn( + "[{}] '{}' is both included and excluded, ignoring the exclusion", logPrefix, spec); + } + } else if ((matcher = EXACT_EXCLUDE.matcher(spec)).matches()) { + String name = matcher.group(1); + if (exactIncludes.contains(name)) { + LOG.warn( + "[{}] '{}' is both included and excluded, ignoring the exclusion", logPrefix, name); + } else { + exactExcludes.add(name); + } + } else if ((matcher = REGEX_INCLUDE.matcher(spec)).matches()) { + compile(matcher.group(1)).map(regexIncludes::add); + } else if ((matcher = REGEX_EXCLUDE.matcher(spec)).matches()) { + compile(matcher.group(1)).map(regexExcludes::add); + } else { + LOG.warn( + "[{}] Error while parsing {}: invalid element '{}', skipping", + logPrefix, + DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES.getPath(), + spec); + } + } + + if (!exactIncludes.isEmpty() && regexIncludes.isEmpty() && regexExcludes.isEmpty()) { + // We can filter on the server + whereClause = buildWhereClause(exactIncludes); + if (!exactExcludes.isEmpty()) { + // Proceed, but this is probably a mistake + LOG.warn( + "[{}] {} only has exact includes and excludes, the excludes are redundant", + logPrefix, + DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES.getPath()); + } + LOG.debug("[{}] Filtering server-side with '{}'", logPrefix, whereClause); + } else { + whereClause = ""; + LOG.debug("[{}] No server-side filtering", logPrefix); + } + + isDebugEnabled = LOG.isDebugEnabled(); + loggedKeyspaces = isDebugEnabled ? new HashSet<>() : null; + } + + @NonNull + @Override + public String getWhereClause() { + return whereClause; + } + + @Override + public boolean includes(@NonNull String keyspace) { + if (exactIncludes.contains(keyspace)) { + log(keyspace, true, "it is included by name"); + return true; + } else if (exactExcludes.contains(keyspace)) { + log(keyspace, false, "it is excluded by name"); + return false; + } else if (regexIncludes.isEmpty()) { + if (regexExcludes.isEmpty()) { + log(keyspace, false, "it is not included by name"); + return false; + } else if (matchesAny(keyspace, regexExcludes)) { + log(keyspace, false, "it matches at least one regex exclude"); + return false; + } else { + log(keyspace, true, "it does not match any regex exclude"); + return true; + } + } else { // !regexIncludes.isEmpty() + if (regexExcludes.isEmpty()) { + if (matchesAny(keyspace, regexIncludes)) { + log(keyspace, true, "it matches at least one regex include"); + return true; + } else { + log(keyspace, false, "it does not match any regex include"); + return false; + } + } else { + if (matchesAny(keyspace, regexIncludes) && !matchesAny(keyspace, regexExcludes)) { + log(keyspace, true, "it matches at least one regex include, and no regex exclude"); + return true; + } else { + log(keyspace, false, "it matches either no regex include, or at least one regex exclude"); + return false; + } + } + } + } + + private void log(@NonNull String keyspace, boolean include, @NonNull String reason) { + if (isDebugEnabled && loggedKeyspaces.add(keyspace)) { + LOG.debug( + "[{}] Filtering {} '{}' because {}", logPrefix, include ? "in" : "out", keyspace, reason); + } + } + + private boolean matchesAny(String keyspace, List> rules) { + for (Predicate rule : rules) { + if (rule.test(keyspace)) { + return true; + } + } + return false; + } + + private Optional> compile(String regex) { + try { + return Optional.of(Pattern.compile(regex).asPredicate()); + } catch (PatternSyntaxException e) { + LOG.warn( + "[{}] Error while parsing {}: syntax error in regex /{}/ ({}), skipping", + this.logPrefix, + DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES.getPath(), + regex, + e.getMessage()); + return Optional.empty(); + } + } + + private static String buildWhereClause(Set keyspaces) { + StringBuilder builder = new StringBuilder(" WHERE keyspace_name IN ("); + boolean first = true; + for (String keyspace : keyspaces) { + if (first) { + first = false; + } else { + builder.append(","); + } + builder.append('\'').append(keyspace).append('\''); + } + return builder.append(')').toString(); + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index a025e816d30..d303db0b036 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1785,14 +1785,41 @@ datastax-java-driver { # Overridable in a profile: no enabled = true - # The list of keyspaces for which schema and token metadata should be maintained. If this - # property is absent or empty, all existing keyspaces are processed. + # The keyspaces for which schema and token metadata should be maintained. # - # Required: no + # Each element can be one of the following: + # 1. An exact name inclusion, for example "Ks1". If the name is case-sensitive, it must appear + # in its exact case. + # 2. An exact name exclusion, for example "!Ks1". + # 3. A regex inclusion, enclosed in slashes, for example "/^Ks.*/". The part between the + # slashes must follow the syntax rules of java.util.regex.Pattern. + # 4. A regex exclusion, for example "!/^Ks.*/". + # + # If the list is empty, or the option is unset, all keyspaces will match. Otherwise: + # + # If a keyspace matches an exact name inclusion, it is always included, regardless of what any + # other rule says. + # Otherwise, if it matches an exact name exclusion, it is always excluded, regardless of what + # any regex rule says. + # Otherwise, if there are regex rules: + # - if they're only inclusions, the keyspace must match at least one of them. + # - if they're only exclusions, the keyspace must match none of them. + # - if they're both, the keyspace must match at least one inclusion and none of the + # exclusions. + # + # If an element is malformed, or if its regex has a syntax error, a warning is logged and that + # single element is ignored. + # + # Try to use only exact name inclusions if possible. This allows the driver to filter on the + # server side with a WHERE IN clause. If you use any other rule, it has to fetch all system + # rows and filter on the client side. + # + # Required: no. The default value excludes all Cassandra and DSE system keyspaces. If the + # option is unset, this is interpreted as "include all keyspaces". # Modifiable at runtime: yes, the new value will be used for refreshes issued after the # change. # Overridable in a profile: no - // refreshed-keyspaces = [ "ks1", "ks2" ] + refreshed-keyspaces = [ "!system", "!/^system_.*/", "!/^dse_.*/", "!solr_admin" ] # The timeout for the requests to the schema tables. # diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/AggregateParserTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/AggregateParserTest.java index ee26b25c95d..03202c4ddad 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/AggregateParserTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/AggregateParserTest.java @@ -56,7 +56,9 @@ public class AggregateParserTest extends SchemaParserTestBase { "0"); @Before + @Override public void setup() { + super.setup(); when(context.getCodecRegistry()).thenReturn(CodecRegistry.DEFAULT); when(context.getProtocolVersion()).thenReturn(ProtocolVersion.DEFAULT); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTest.java index 037234b0632..3ff2f497d8b 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTest.java @@ -137,7 +137,8 @@ public void should_parse_multiple_keyspaces() { } private MetadataRefresh parse(Consumer builderConfig) { - CassandraSchemaRows.Builder builder = new CassandraSchemaRows.Builder(NODE_3_0, "test"); + CassandraSchemaRows.Builder builder = + new CassandraSchemaRows.Builder(NODE_3_0, keyspaceFilter, "test"); builderConfig.accept(builder); SchemaRows rows = builder.build(); return new CassandraSchemaParser(rows, context).parse(); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTestBase.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTestBase.java index 009a2db614f..2a6f74285d2 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/SchemaParserTestBase.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.metadata.schema.parsing; import static org.assertj.core.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -25,11 +26,13 @@ import com.datastax.oss.driver.internal.core.adminrequest.AdminRow; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metadata.DefaultMetadata; +import com.datastax.oss.driver.internal.core.metadata.schema.queries.KeyspaceFilter; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import java.nio.ByteBuffer; import java.util.Collections; import java.util.List; +import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -42,6 +45,12 @@ public abstract class SchemaParserTestBase { protected static final CqlIdentifier KEYSPACE_ID = CqlIdentifier.fromInternal("ks"); @Mock protected DefaultMetadata currentMetadata; @Mock protected InternalDriverContext context; + @Mock protected KeyspaceFilter keyspaceFilter; + + @Before + public void setup() { + when(keyspaceFilter.includes(anyString())).thenReturn(true); + } protected static AdminRow mockFunctionRow( String keyspace, diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/TableParserTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/TableParserTest.java index fe106165f67..e8d1228d573 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/TableParserTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/TableParserTest.java @@ -204,7 +204,7 @@ private SchemaRows modernRows( private SchemaRows rows( AdminRow tableRow, Iterable columnRows, Iterable indexesRows, Node node) { CassandraSchemaRows.Builder builder = - new CassandraSchemaRows.Builder(node, "test") + new CassandraSchemaRows.Builder(node, keyspaceFilter, "test") .withTables(ImmutableList.of(tableRow)) .withColumns(columnRows); if (indexesRows != null) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/ViewParserTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/ViewParserTest.java index 4fe83cf34b6..122bb12f863 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/ViewParserTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/ViewParserTest.java @@ -86,7 +86,7 @@ public void should_parse_view() { } private SchemaRows rows(AdminRow viewRow, Iterable columnRows) { - return new CassandraSchemaRows.Builder(NODE_3_0, "test") + return new CassandraSchemaRows.Builder(NODE_3_0, keyspaceFilter, "test") .withViews(ImmutableList.of(viewRow)) .withColumns(columnRows) .build(); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/Cassandra3SchemaQueriesTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/Cassandra3SchemaQueriesTest.java index e41fd78d3ed..59c20d032c5 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/Cassandra3SchemaQueriesTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/Cassandra3SchemaQueriesTest.java @@ -58,7 +58,7 @@ public void should_query_with_keyspace_filter() { DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, Collections.emptyList())) .thenReturn(ImmutableList.of("ks1", "ks2")); - should_query_with_where_clause(" WHERE keyspace_name in ('ks1','ks2')"); + should_query_with_where_clause(" WHERE keyspace_name IN ('ks1','ks2')"); } private void should_query_with_where_clause(String whereClause) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilterTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilterTest.java new file mode 100644 index 00000000000..286d4d6329e --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/queries/KeyspaceFilterTest.java @@ -0,0 +1,141 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata.schema.queries; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.Test; + +public class KeyspaceFilterTest { + + private static final ImmutableSet KEYSPACES = + ImmutableSet.of( + "system", "inventory_test", "inventory_prod", "customers_test", "customers_prod"); + + @Test + public void should_not_filter_when_no_rules() { + KeyspaceFilter filter = KeyspaceFilter.newInstance("test", Arrays.asList()); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).isEqualTo(KEYSPACES); + } + + @Test + public void should_filter_on_server_when_only_exact_rules() { + KeyspaceFilter filter = + KeyspaceFilter.newInstance( + "test", Arrays.asList("inventory_test", "customers_test", "!system")); + // Note that exact excludes are redundant in this case: either they match an include and will be + // ignored, or they don't and the keyspace is already ignored. + // We let it slide, but a warning is logged. + assertThat(filter.getWhereClause()) + .isEqualTo(" WHERE keyspace_name IN ('inventory_test','customers_test')"); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_test", "customers_test"); + } + + @Test + public void should_ignore_exact_exclude_that_collides_with_exact_include() { + KeyspaceFilter filter = + KeyspaceFilter.newInstance("test", Arrays.asList("inventory_test", "!inventory_test")); + assertThat(filter.getWhereClause()).isEqualTo(" WHERE keyspace_name IN ('inventory_test')"); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_test"); + + // Order does not matter + filter = KeyspaceFilter.newInstance("test", Arrays.asList("!inventory_test", "inventory_test")); + assertThat(filter.getWhereClause()).isEqualTo(" WHERE keyspace_name IN ('inventory_test')"); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_test"); + } + + @Test + public void should_apply_disjoint_exact_and_regex_rules() { + KeyspaceFilter filter = + KeyspaceFilter.newInstance("test", Arrays.asList("inventory_test", "/^customers.*/")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)) + .containsOnly("inventory_test", "customers_test", "customers_prod"); + + filter = KeyspaceFilter.newInstance("test", Arrays.asList("!system", "!/^inventory.*/")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).containsOnly("customers_test", "customers_prod"); + + // The remaining cases could be simplified, but they are supported nevertheless: + /*redundant:*/ + filter = KeyspaceFilter.newInstance("test", Arrays.asList("!/^customers.*/", "inventory_test")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_test", "inventory_prod", "system"); + + /*redundant:*/ + filter = KeyspaceFilter.newInstance("test", Arrays.asList("/^customers.*/", "!system")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).containsOnly("customers_test", "customers_prod"); + } + + @Test + public void should_apply_intersecting_exact_and_regex_rules() { + // Include all customer keyspaces except one: + KeyspaceFilter filter = + KeyspaceFilter.newInstance("test", Arrays.asList("/^customers.*/", "!customers_test")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).containsOnly("customers_prod"); + + // Exclude all customer keyspaces except one (also implies include every other keyspace): + filter = KeyspaceFilter.newInstance("test", Arrays.asList("!/^customers.*/", "customers_test")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)) + .containsOnly("customers_test", "inventory_test", "inventory_prod", "system"); + } + + @Test + public void should_apply_intersecting_regex_rules() { + KeyspaceFilter filter = + KeyspaceFilter.newInstance("test", Arrays.asList("/^customers.*/", "!/.*test$/")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).containsOnly("customers_prod"); + + // Throwing an exact name in the mix doesn't change the other rules + filter = + KeyspaceFilter.newInstance( + "test", Arrays.asList("inventory_prod", "/^customers.*/", "!/.*test$/")); + assertThat(filter.getWhereClause()).isEmpty(); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_prod", "customers_prod"); + } + + @Test + public void should_skip_malformed_rule() { + KeyspaceFilter filter = + KeyspaceFilter.newInstance("test", Arrays.asList("inventory_test", "customers_test", "//")); + assertThat(filter.getWhereClause()) + .isEqualTo(" WHERE keyspace_name IN ('inventory_test','customers_test')"); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_test", "customers_test"); + } + + @Test + public void should_skip_invalid_regex() { + KeyspaceFilter filter = + KeyspaceFilter.newInstance( + "test", Arrays.asList("inventory_test", "customers_test", "/*/")); + assertThat(filter.getWhereClause()) + .isEqualTo(" WHERE keyspace_name IN ('inventory_test','customers_test')"); + assertThat(apply(filter, KEYSPACES)).containsOnly("inventory_test", "customers_test"); + } + + private static Set apply(KeyspaceFilter filter, Set keyspaces) { + return keyspaces.stream().filter(filter::includes).collect(Collectors.toSet()); + } +} diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index a140a421ae2..4259e56c107 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -132,7 +132,54 @@ You can also limit the metadata to a subset of keyspaces: datastax-java-driver.advanced.metadata.schema.refreshed-keyspaces = [ "users", "products" ] ``` -If the property is absent or the list is empty, it is interpreted as "all keyspaces". +Each element in the list can be one of the following: + +1. An exact name inclusion, for example `"Ks1"`. If the name is case-sensitive, it must appear in + its exact case. +2. An exact name exclusion, for example `"!Ks1"`. +3. A regex inclusion, enclosed in slashes, for example `"/^Ks.*/"`. The part between the slashes + must follow the syntax rules of [java.util.regex.Pattern]. The regex must match the entire + keyspace name (no partial matching). +4. A regex exclusion, for example `"!/^Ks.*/"`. + +If the list is empty, or the option is unset, all keyspaces will match. Otherwise: + +* If a keyspace matches an exact name inclusion, it is always included, regardless of what any other + rule says. +* Otherwise, if it matches an exact name exclusion, it is always excluded, regardless of what any + regex rule says. +* Otherwise, if there are regex rules: + + * if they're only inclusions, the keyspace must match at least one of them. + * if they're only exclusions, the keyspace must match none of them. + * if they're both, the keyspace must match at least one inclusion and none of the + exclusions. + +For example, given the keyspaces `system`, `ks1`, `ks2`, `data1` and `data2`, here's the outcome of +a few filters: + +|Filter|Outcome|Translation| +|---|---|---| +| `[]` | `system`, `ks1`, `ks2`, `data1`, `data2` | Include all. | +| `["ks1", "ks2"]` | `ks1`, `ks2` | Include ks1 and ks2 (recommended, see explanation below). | +| `["!system"]` | `ks1`, `ks2`, `data1`, `data2` | Include all except system. | +| `["/^ks.*/"]` | `ks1`, `ks2` | Include all that start with ks. | +| `["!/^ks.*/"]` | `system`, `data1`, `data2` | Exclude all that start with ks (and include everything else). | +| `["system", "/^ks.*/"]` | `system`, `ks1`, `ks2` | Include system, and all that start with ks. | +| `["/^ks.*/", "!ks2"]` | `ks1` | Include all that start with ks, except ks2. | +| `["!/^ks.*/", "ks1"]` | `system`, `ks1`, `data1`, `data2` | Exclude all that start with ks, except ks1 (and also include everything else). | +| `["/^s.*/", /^ks.*/", "!/.*2$/"]` | `system`, `ks1` | Include all that start with s or ks, except if they end with 2. | + + +If an element is malformed, or if its regex has a syntax error, a warning is logged and that single +element is ignored. + +The default configuration (see [reference.conf](../../configuration/reference/)) excludes all +Cassandra and DSE system keyspaces. + +Try to use only exact name inclusions if possible. This allows the driver to filter on the server +side with a `WHERE IN` clause. If you use any other rule, it has to fetch all system rows and filter +on the client side. Note that, if you change the list at runtime, `onKeyspaceAdded`/`onKeyspaceDropped` will be invoked on your schema listeners for the newly included/excluded keyspaces. @@ -271,4 +318,5 @@ take a look at the [Performance](../../performance/#schema-updates) page for a f [DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html [DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html -[JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 \ No newline at end of file +[JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 +[java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html From e63de8a55dcc46fc67b86f436b54cbb522669592 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 18:25:08 +0100 Subject: [PATCH 025/395] Revert Snappy version upgrade Version 1.1.8.1 causes the related OSGi tests to fail. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 83a04f9b198..08309f95361 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 2.11.0 1.9.12 - 1.1.8.1 + 1.1.7.3 1.7.1 3.18.1 From 2a705683df13f28eba2fb76ec9cdd8f1e8774df7 Mon Sep 17 00:00:00 2001 From: Olivier Michallat Date: Fri, 18 Dec 2020 09:38:25 -0800 Subject: [PATCH 026/395] JAVA-2877: Allow skipping validation for individual mapped entities (#1502) Co-authored-by: Alexandre Dutra --- changelog/README.md | 1 + .../oss/driver/mapper/SchemaValidationIT.java | 61 ++++++++++++- manual/mapper/mapper/README.md | 3 + ...HelperSchemaValidationMethodGenerator.java | 87 ++++++++++--------- .../api/mapper/annotations/SchemaHint.java | 7 +- 5 files changed, 116 insertions(+), 43 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index ccd1f87e1a1..d720271d9c5 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [improvement] JAVA-2877: Allow skipping validation for individual mapped entities - [improvement] JAVA-2871: Allow keyspace exclusions in the metadata, and exclude system keyspaces by default - [improvement] JAVA-2449: Use non-cryptographic random number generation in Uuids.random() diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java index ec0c579c3c3..9abaa714996 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java @@ -15,11 +15,13 @@ */ package com.datastax.oss.driver.mapper; -import static com.datastax.oss.driver.api.mapper.annotations.SchemaHint.*; +import static com.datastax.oss.driver.api.mapper.annotations.SchemaHint.TargetElement; import static com.datastax.oss.driver.internal.core.util.LoggerTest.setupTestLogger; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; @@ -28,6 +30,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; +import com.datastax.oss.driver.api.mapper.MapperContext; import com.datastax.oss.driver.api.mapper.annotations.ClusteringColumn; import com.datastax.oss.driver.api.mapper.annotations.Dao; import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; @@ -35,9 +38,11 @@ import com.datastax.oss.driver.api.mapper.annotations.Entity; import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; +import com.datastax.oss.driver.api.mapper.annotations.QueryProvider; import com.datastax.oss.driver.api.mapper.annotations.SchemaHint; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.annotations.Update; +import com.datastax.oss.driver.api.mapper.entity.EntityHelper; import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -312,6 +317,20 @@ public void should_log_warning_when_passing_not_existing_keyspace() { } } + @Test + public void should_not_warn_or_throw_when_target_element_is_NONE() { + LoggerTest.LoggerSetup logger = + setupTestLogger( + SchemaValidationIT_DoesNotExistNoValidationHelper__MapperGenerated.class, Level.WARN); + + // when + mapper.noValidationDao(sessionRule.keyspace()); + + // then + // no exceptions, no logs + verify(logger.appender, never()).doAppend(any()); + } + @Mapper public interface InventoryMapper { @DaoFactory @@ -353,6 +372,9 @@ ProductSimpleMissingClusteringColumnDao productSimpleMissingClusteringColumn( @DaoFactory ProductPkAndClusteringDao productPkAndClusteringDao(@DaoKeyspace CqlIdentifier keyspace); + + @DaoFactory + NoValidationDao noValidationDao(@DaoKeyspace CqlIdentifier keyspace); } @Dao @@ -437,6 +459,25 @@ public interface ProductPkAndClusteringDao { ProductPkAndClustering findById(UUID productId); } + @Dao + public interface NoValidationDao { + // Not a real query, we just need to reference the entities + @QueryProvider( + providerClass = DummyProvider.class, + entityHelpers = {DoesNotExistNoValidation.class, ProductCqlTableMissingNoValidation.class}) + void doNothing(); + } + + @SuppressWarnings("unused") + static class DummyProvider { + DummyProvider( + MapperContext context, + EntityHelper helper1, + EntityHelper helper2) {} + + void doNothing() {} + } + @Entity public static class ProductCqlTableMissing { @PartitionKey private UUID id; @@ -1188,4 +1229,22 @@ public String toString() { + '}'; } } + + @Entity + @SchemaHint(targetElement = TargetElement.NONE) + public static class DoesNotExistNoValidation { + private int k; + + public int getK() { + return k; + } + + public void setK(int k) { + this.k = k; + } + } + + @Entity + @SchemaHint(targetElement = TargetElement.NONE) + public static class ProductCqlTableMissingNoValidation extends ProductCqlTableMissing {} } diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 2dd0e500f4e..e2834b0d99f 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -227,6 +227,9 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) .build(); ``` +You can also permanently disable validation of an individual entity by annotating it with +`@SchemaHint(targetElement = NONE)`. + [CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlIdentifier.html [@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html [@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSchemaValidationMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSchemaValidationMethodGenerator.java index 3aa9957ac82..17b4246d3a3 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSchemaValidationMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSchemaValidationMethodGenerator.java @@ -64,51 +64,59 @@ public Optional generate() { .addModifiers(Modifier.PUBLIC) .returns(TypeName.VOID); - // get keyspaceId from context, and if not present fallback to keyspace set on session - methodBuilder.addStatement( - "$1T keyspaceId = this.keyspaceId != null ? this.keyspaceId : context.getSession().getKeyspace().orElse(null)", - CqlIdentifier.class); + Optional targetElement = + Optional.ofNullable(entityTypeElement.getAnnotation(SchemaHint.class)) + .map(SchemaHint::targetElement); - methodBuilder.addStatement("String entityClassName = $S", entityDefinition.getClassName()); - generateKeyspaceNull(methodBuilder); + if (targetElement.isPresent() && targetElement.get() == TargetElement.NONE) { + methodBuilder.addComment( + "Nothing to do, validation was disabled with @SchemaHint(targetElement = NONE)"); + } else { + // get keyspaceId from context, and if not present fallback to keyspace set on session + methodBuilder.addStatement( + "$1T keyspaceId = this.keyspaceId != null ? this.keyspaceId : context.getSession().getKeyspace().orElse(null)", + CqlIdentifier.class); - generateKeyspaceNameWrong(methodBuilder); + methodBuilder.addStatement("String entityClassName = $S", entityDefinition.getClassName()); + generateKeyspaceNull(methodBuilder); - methodBuilder.addStatement( - "$1T<$2T> keyspace = context.getSession().getMetadata().getKeyspace(keyspaceId)", - Optional.class, - KeyspaceMetadata.class); + generateKeyspaceNameWrong(methodBuilder); - // Generates expected names to be present in cql (table or udt) - List expectedCqlNames = - entityDefinition.getAllColumns().stream() - .map(PropertyDefinition::getCqlName) - .collect(Collectors.toList()); - methodBuilder.addStatement( - "$1T<$2T> expectedCqlNames = new $3T<>()", - List.class, - CqlIdentifier.class, - ArrayList.class); - for (CodeBlock expectedCqlName : expectedCqlNames) { methodBuilder.addStatement( - "expectedCqlNames.add($1T.fromCql($2L))", CqlIdentifier.class, expectedCqlName); - } - - methodBuilder.addStatement( - "$1T<$2T> tableMetadata = keyspace.flatMap(v -> v.getTable(tableId))", - Optional.class, - TableMetadata.class); + "$1T<$2T> keyspace = context.getSession().getMetadata().getKeyspace(keyspaceId)", + Optional.class, + KeyspaceMetadata.class); + + // Generates expected names to be present in cql (table or udt) + List expectedCqlNames = + entityDefinition.getAllColumns().stream() + .map(PropertyDefinition::getCqlName) + .collect(Collectors.toList()); + methodBuilder.addStatement( + "$1T<$2T> expectedCqlNames = new $3T<>()", + List.class, + CqlIdentifier.class, + ArrayList.class); + for (CodeBlock expectedCqlName : expectedCqlNames) { + methodBuilder.addStatement( + "expectedCqlNames.add($1T.fromCql($2L))", CqlIdentifier.class, expectedCqlName); + } - // Generated UserDefineTypes metadata - methodBuilder.addStatement( - "$1T<$2T> userDefinedType = keyspace.flatMap(v -> v.getUserDefinedType(tableId))", - Optional.class, - UserDefinedType.class); + methodBuilder.addStatement( + "$1T<$2T> tableMetadata = keyspace.flatMap(v -> v.getTable(tableId))", + Optional.class, + TableMetadata.class); - generateValidationChecks(methodBuilder); + // Generated UserDefineTypes metadata + methodBuilder.addStatement( + "$1T<$2T> userDefinedType = keyspace.flatMap(v -> v.getUserDefinedType(tableId))", + Optional.class, + UserDefinedType.class); - logMissingMetadata(methodBuilder); + generateValidationChecks(methodBuilder, targetElement); + logMissingMetadata(methodBuilder); + } return Optional.of(methodBuilder.build()); } @@ -159,11 +167,8 @@ private void generateKeyspaceNull(MethodSpec.Builder methodBuilder) { methodBuilder.endControlFlow(); } - private void generateValidationChecks(MethodSpec.Builder methodBuilder) { - Optional targetElement = - Optional.ofNullable(entityTypeElement.getAnnotation(SchemaHint.class)) - .map(SchemaHint::targetElement); - + private void generateValidationChecks( + MethodSpec.Builder methodBuilder, Optional targetElement) { // if SchemaHint was not provided explicitly try to match TABLE, then fallback to UDT if (!targetElement.isPresent()) { validateColumnsInTable(methodBuilder); diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SchemaHint.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SchemaHint.java index b33ec132f08..c972cdbf936 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SchemaHint.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SchemaHint.java @@ -39,6 +39,9 @@ *

By default, the mapper first tries to match the entity with a table, and if that doesn't work, * with a UDT. This annotation allows you to provide a hint as to which check should be done, so * that the mapper can skip the other one. + * + *

In addition, you can ask to completely skip the validation for this entity by using {@link + * TargetElement#NONE}. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -47,6 +50,8 @@ enum TargetElement { TABLE, - UDT + UDT, + NONE, + ; } } From d32c7fe52de7a8ed25768134c70ae13c0b3f9fc0 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Dec 2020 19:03:46 +0100 Subject: [PATCH 027/395] JAVA-2903: BlockHound integration (#1514) --- changelog/README.md | 1 + core-shaded/pom.xml | 4 +- core/pom.xml | 7 +- .../ContinuousRequestHandlerBase.java | 44 +-- .../metadata/SafeInitNodeStateListener.java | 3 + .../api/core/session/SessionBuilder.java | 6 + .../session/throttling/RequestThrottler.java | 9 +- .../oss/driver/api/core/uuid/Uuids.java | 6 + .../core/context/DefaultNettyOptions.java | 10 +- .../oss/driver/internal/core/time/Clock.java | 9 +- .../util/concurrent/BlockingOperation.java | 2 +- .../DriverBlockHoundIntegration.java | 109 +++++++ ...ockhound.integration.BlockHoundIntegration | 1 + integration-tests/pom.xml | 15 + .../DriverBlockHoundIntegrationCcmIT.java | 120 ++++++++ .../DriverBlockHoundIntegrationIT.java | 132 ++++++++ .../src/test/resources/application.conf | 2 +- manual/core/async/README.md | 8 +- manual/core/non_blocking/README.md | 289 ++++++++++++++++++ manual/core/reactive/README.md | 6 +- manual/developer/common/concurrency/README.md | 19 +- pom.xml | 17 ++ 22 files changed, 780 insertions(+), 39 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegration.java create mode 100644 core/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java create mode 100644 manual/core/non_blocking/README.md diff --git a/changelog/README.md b/changelog/README.md index d720271d9c5..86b2d3d04d3 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [new feature] JAVA-2903: BlockHound integration - [improvement] JAVA-2877: Allow skipping validation for individual mapped entities - [improvement] JAVA-2871: Allow keyspace exclusions in the metadata, and exclude system keyspaces by default diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 4d92a37736f..addaf4070d1 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -317,11 +317,11 @@ Note: dependencies marked as optional are by default included with optional resolution in the manifest; we only need to manually set the resolution to optional for dependencies declared as non-optional in the pom files. - -->jnr.*;resolution:=optional, com.esri.core.geometry.*;resolution:=optional,org.reactivestreams.*;resolution:=optional, org.apache.tinkerpop.*;resolution:=optional, org.javatuples.*;resolution:=optional, + -->jnr.*;resolution:=optional, com.esri.core.geometry.*;resolution:=optional,org.reactivestreams.*;resolution:=optional, org.apache.tinkerpop.*;resolution:=optional, org.javatuples.*;resolution:=optional, reactor.blockhound.*;resolution:=optional, !com.google.protobuf.*, !com.jcraft.jzlib.*, !com.ning.compress.*, !lzma.sdk.*, !net.jpountz.xxhash.*, !org.bouncycastle.*, !org.conscrypt.*, !org.apache.commons.logging.*, !org.apache.log4j.*, !org.apache.logging.log4j.*, !org.eclipse.jetty.*, !org.jboss.marshalling.*, !sun.misc.*, !sun.security.*, !com.barchart.udt.*, !com.fasterxml.aalto.*, !com.sun.nio.sctp.*, !gnu.io.*, !org.xml.sax.*, !org.w3c.dom.*, !reactor.blockhound.*, * + -->!com.google.protobuf.*, !com.jcraft.jzlib.*, !com.ning.compress.*, !lzma.sdk.*, !net.jpountz.xxhash.*, !org.bouncycastle.*, !org.conscrypt.*, !org.apache.commons.logging.*, !org.apache.log4j.*, !org.apache.logging.log4j.*, !org.eclipse.jetty.*, !org.jboss.marshalling.*, !sun.misc.*, !sun.security.*, !com.barchart.udt.*, !com.fasterxml.aalto.*, !com.sun.nio.sctp.*, !gnu.io.*, !org.xml.sax.*, !org.w3c.dom.*, * jnr.*;resolution:=optional, com.esri.core.geometry.*;resolution:=optional, org.reactivestreams.*;resolution:=optional, org.apache.tinkerpop.*;resolution:=optional, org.javatuples.*;resolution:=optional, * + -->jnr.*;resolution:=optional, com.esri.core.geometry.*;resolution:=optional, org.reactivestreams.*;resolution:=optional, org.apache.tinkerpop.*;resolution:=optional, org.javatuples.*;resolution:=optional, reactor.blockhound.*;resolution:=optional, * com.datastax.oss.driver.*.core.*, com.datastax.dse.driver.*.core.* diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java index c7754702bcf..de6dee6f8be 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java @@ -696,28 +696,28 @@ private Timeout schedulePageTimeout(int expectedPage) { } LOG.trace("[{}] Scheduling timeout for page {} in {}", logPrefix, expectedPage, timeout); return timer.newTimeout( - timeout1 -> { - lock.lock(); - try { - if (state == expectedPage) { - abort( - new DriverTimeoutException( - String.format("Timed out waiting for page %d", expectedPage)), - false); - } else { - // Ignore timeout if the request has moved on in the interim. - LOG.trace( - "[{}] Timeout fired for page {} but query already at state {}, skipping", - logPrefix, - expectedPage, - state); - } - } finally { - lock.unlock(); - } - }, - timeout.toNanos(), - TimeUnit.NANOSECONDS); + t -> onPageTimeout(expectedPage), timeout.toNanos(), TimeUnit.NANOSECONDS); + } + + private void onPageTimeout(int expectedPage) { + lock.lock(); + try { + if (state == expectedPage) { + abort( + new DriverTimeoutException( + String.format("Timed out waiting for page %d", expectedPage)), + false); + } else { + // Ignore timeout if the request has moved on in the interim. + LOG.trace( + "[{}] Timeout fired for page {} but query already at state {}, skipping", + logPrefix, + expectedPage, + state); + } + } finally { + lock.unlock(); + } } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.java b/core/src/main/java/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.java index f75f2179a8a..4eabd59829c 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.java @@ -58,6 +58,9 @@ *

  • if {@code false}, they are discarded. * * + *

    Usage in non-blocking applications: beware that this class is not lock-free. It is implemented + * with locks for internal coordination. + * * @since 4.6.0 */ public class SafeInitNodeStateListener implements NodeStateListener { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index af4eb467a95..abe28786b62 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -676,6 +676,8 @@ public SelfT withMetricRegistry(@Nullable Object metricRegistry) { /** * Creates the session with the options set by this builder. * + *

    The session initialization will happen asynchronously in a driver internal thread pool. + * * @return a completion stage that completes with the session when it is fully initialized. */ @NonNull @@ -689,6 +691,10 @@ public CompletionStage buildAsync() { /** * Convenience method to call {@link #buildAsync()} and block on the result. * + *

    Usage in non-blocking applications: beware that session initialization is a costly + * operation. It should only be triggered from a thread that is allowed to block. If that is not + * the case, consider using {@link #buildAsync()} instead. + * *

    This must not be called on a driver thread. */ @NonNull diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java index 21ae3b5e396..db7dd432266 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java @@ -18,7 +18,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; import java.io.Closeable; -/** Limits the number of concurrent requests executed by the driver. */ +/** + * Limits the number of concurrent requests executed by the driver. + * + *

    Usage in non-blocking applications: beware that all built-in implementations of this interface + * use locks for internal coordination, and do not qualify as lock-free, with the obvious exception + * of {@code PassThroughRequestThrottler}. If your application enforces strict lock-freedom, then + * request throttling should not be enabled. + */ public interface RequestThrottler extends Closeable { /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java b/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java index 4b63dee3055..337f950aff6 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/uuid/Uuids.java @@ -511,6 +511,12 @@ private static byte[] toBytes(long msb, long lsb) { * * If you simply need to perform a range query on a {@code timeuuid} column, use the "fake" UUID * generated by {@link #startOf(long)} and {@link #endOf(long)}. + * + *

    Usage with non-blocking threads: beware that this method may block the calling thread on its + * very first invocation, because the node part of time-based UUIDs needs to be computed at that + * moment, and the computation may require the loading of native libraries. If that is a problem, + * consider invoking this method once from a thread that is allowed to block. Subsequent + * invocations are guaranteed not to block. */ @NonNull public static UUID timeBased() { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java index aefd6d55bde..af613d92366 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java @@ -108,12 +108,20 @@ public DefaultNettyOptions(InternalDriverContext context) { + "Please set advanced.netty.timer.tick-duration to 100 ms or higher.", tickDuration.toMillis()); } - timer = + this.timer = createTimer(timerThreadFactory, tickDuration); + } + + private HashedWheelTimer createTimer(ThreadFactory timerThreadFactory, Duration tickDuration) { + HashedWheelTimer timer = new HashedWheelTimer( timerThreadFactory, tickDuration.toNanos(), TimeUnit.NANOSECONDS, config.getInt(DefaultDriverOption.NETTY_TIMER_TICKS_PER_WHEEL)); + // Start the background thread eagerly during session initialization because + // it is a blocking operation. + timer.start(); + return timer; } @Override diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/time/Clock.java b/core/src/main/java/com/datastax/oss/driver/internal/core/time/Clock.java index 4a12a788068..dd00171ab63 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/time/Clock.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/time/Clock.java @@ -26,7 +26,14 @@ public interface Clock { Logger LOG = LoggerFactory.getLogger(Clock.class); - /** Returns the best implementation for the current platform. */ + /** + * Returns the best implementation for the current platform. + * + *

    Usage with non-blocking threads: beware that this method may block the calling thread on its + * very first invocation, because native libraries used by the driver will be loaded at that + * moment. If that is a problem, consider invoking this method once from a thread that is allowed + * to block. Subsequent invocations are guaranteed not to block. + */ static Clock getInstance(boolean forceJavaClock) { if (forceJavaClock) { LOG.info("Using Java system clock because this was explicitly required in the configuration"); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/BlockingOperation.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/BlockingOperation.java index 7797594b7b9..091c88be2ee 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/BlockingOperation.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/BlockingOperation.java @@ -59,7 +59,7 @@ public Thread newThread(@NonNull Runnable r) { } } - private static class InternalThread extends FastThreadLocalThread { + static class InternalThread extends FastThreadLocalThread { private InternalThread(Runnable runnable) { super(runnable); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegration.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegration.java new file mode 100644 index 00000000000..d18b33c4c69 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegration.java @@ -0,0 +1,109 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.concurrent; + +import com.datastax.oss.driver.internal.core.util.concurrent.BlockingOperation.InternalThread; +import reactor.blockhound.BlockHound; +import reactor.blockhound.integration.BlockHoundIntegration; + +public final class DriverBlockHoundIntegration implements BlockHoundIntegration { + + @Override + public void applyTo(BlockHound.Builder builder) { + + // disallow blocking operations in driver internal threads by default; + // note that session initialization will happen on one of these threads, which is why + // we need to allow a few blocking calls below. + builder.nonBlockingThreadPredicate(current -> current.or(InternalThread.class::isInstance)); + + // blocking calls in initialization methods + + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.context.DefaultNettyOptions", "createTimer"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.os.Native$LibcLoader", "load"); + builder.allowBlockingCallsInside( + // requires native libraries + "com.datastax.oss.driver.internal.core.time.Clock", "getInstance"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.util.concurrent.LazyReference", "get"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.util.concurrent.ReplayingEventFilter", "accept"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.util.concurrent.ReplayingEventFilter", "markReady"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.util.concurrent.ReplayingEventFilter", "start"); + + // called upon initialization but also on topology/status events + + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.metadata.LoadBalancingPolicyWrapper$SinglePolicyDistanceReporter", + "setDistance"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.pool.ChannelSet", "add"); + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.pool.ChannelSet", "remove"); + + // never called directly by the driver; locks that usually operate with low thread contention + + builder.allowBlockingCallsInside( + "com.datastax.oss.driver.internal.core.type.codec.registry.CachingCodecRegistry", + "register"); + builder.allowBlockingCallsInside( + // requires native libraries, for now because of Uuids.getProcessPiece; if JAVA-1116 gets + // implemented, Uuids.getCurrentTimestamp will also require an exception. Pre-emptively + // protect the whole Uuids.timeBased method. + "com.datastax.oss.driver.api.core.uuid.Uuids", "timeBased"); + + // continuous paging + + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "cancel"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "dequeueOrCreatePending"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "isLastResponse"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "onFailure"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "onPageTimeout"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "onResponse"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "onStreamIdAssigned"); + builder.allowBlockingCallsInside( + "com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase$NodeResponseCallback", + "operationComplete"); + + // Netty extra exceptions + + // see https://github.com/netty/netty/pull/10810 + builder.allowBlockingCallsInside("io.netty.util.HashedWheelTimer", "start"); + builder.allowBlockingCallsInside("io.netty.util.HashedWheelTimer", "stop"); + + // see https://github.com/netty/netty/pull/10811 + builder.allowBlockingCallsInside("io.netty.util.concurrent.GlobalEventExecutor", "addTask"); + builder.allowBlockingCallsInside( + "io.netty.util.concurrent.SingleThreadEventExecutor", "addTask"); + } +} diff --git a/core/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration b/core/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration new file mode 100644 index 00000000000..b848ce24855 --- /dev/null +++ b/core/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration @@ -0,0 +1 @@ +com.datastax.oss.driver.internal.core.util.concurrent.DriverBlockHoundIntegration \ No newline at end of file diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index d9daac364a4..3cf5c8076cd 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -186,6 +186,21 @@ smallrye-metrics test + + io.projectreactor + reactor-core + test + + + io.projectreactor + reactor-test + test + + + io.projectreactor.tools + blockhound-junit-platform + test + diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java new file mode 100644 index 00000000000..c275eaae12b --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java @@ -0,0 +1,120 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.concurrent; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; + +import com.datastax.dse.driver.api.core.config.DseDriverOption; +import com.datastax.dse.driver.api.core.cql.continuous.ContinuousAsyncResultSet; +import com.datastax.dse.driver.api.core.cql.continuous.ContinuousPagingITBase; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.categories.IsolatedTests; +import java.time.Duration; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import reactor.blockhound.BlockHound; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; +import reactor.test.StepVerifier; + +/** + * This test exercises the driver with BlockHound installed and tests that the rules defined in + * {@link DriverBlockHoundIntegration} are being applied, and especially when continuous paging is + * used. + */ +@DseRequirement( + min = "5.1.0", + description = "Continuous paging is only available from 5.1.0 onwards") +@Category(IsolatedTests.class) +public class DriverBlockHoundIntegrationCcmIT extends ContinuousPagingITBase { + + static { + BlockHound.install(); + } + + private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().build(); + + // Note: Insights monitoring will be detected by BlockHound, but the error is swallowed and + // logged by DefaultSession.SingleThreaded.notifyListeners, so it's not necessary to explicitly + // disable Insights here. + private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); + + @ClassRule public static TestRule chain = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); + + @BeforeClass + public static void setUp() { + initialize(SESSION_RULE.session(), SESSION_RULE.slowProfile()); + } + + @Test + public void should_not_detect_blocking_call_with_continuous_paging() { + CqlSession session = SESSION_RULE.session(); + SimpleStatement statement = SimpleStatement.newInstance("SELECT v from test where k=?", KEY); + Flux rows = + Flux.range(0, 10) + .flatMap( + i -> + Flux.fromIterable(session.executeContinuously(statement)) + .subscribeOn(Schedulers.parallel())); + StepVerifier.create(rows).expectNextCount(1000).expectComplete().verify(); + } + + /** Copied from com.datastax.dse.driver.api.core.cql.continuous.ContinuousPagingIT. */ + @Test + public void should_not_detect_blocking_call_with_continuous_paging_when_timeout() + throws Exception { + CqlSession session = SESSION_RULE.session(); + SimpleStatement statement = SimpleStatement.newInstance("SELECT v from test where k=?", KEY); + // Throttle server at a page per second and set client timeout much lower so that the client + // will experience a timeout. + // Note that this might not be perfect if there are pauses in the JVM and the timeout + // doesn't fire soon enough. + DriverExecutionProfile profile = + session + .getContext() + .getConfig() + .getDefaultProfile() + .withInt(DseDriverOption.CONTINUOUS_PAGING_PAGE_SIZE, 10) + .withInt(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES_PER_SECOND, 1) + .withDuration( + DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_OTHER_PAGES, Duration.ofMillis(100)); + CompletionStage future = + session.executeContinuouslyAsync(statement.setExecutionProfile(profile)); + ContinuousAsyncResultSet pagingResult = CompletableFutures.getUninterruptibly(future); + try { + pagingResult.fetchNextPage().toCompletableFuture().get(); + fail("Expected a timeout"); + } catch (ExecutionException e) { + assertThat(e.getCause()) + .isInstanceOf(DriverTimeoutException.class) + .hasMessageContaining("Timed out waiting for page 2"); + } + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java new file mode 100644 index 00000000000..afe08817fae --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java @@ -0,0 +1,132 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.concurrent; + +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.rows; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; + +import com.datastax.dse.driver.api.core.cql.reactive.ReactiveRow; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.IsolatedTests; +import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import java.util.UUID; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import reactor.blockhound.BlockHound; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import reactor.test.StepVerifier; + +/** + * This test exercises the driver with BlockHound installed and tests that the rules defined in + * {@link DriverBlockHoundIntegration} are being applied. + */ +@Category(IsolatedTests.class) +public class DriverBlockHoundIntegrationIT { + + static { + BlockHound.install(); + } + + @ClassRule + public static final SimulacronRule SIMULACRON_RULE = + new SimulacronRule(ClusterSpec.builder().withNodes(1)); + + @Before + public void setup() { + SIMULACRON_RULE.cluster().prime(when("SELECT c1, c2 FROM ks.t1").then(rows().row("foo", 42))); + } + + @Test + @SuppressWarnings("BlockingMethodInNonBlockingContext") + public void should_detect_blocking_call() { + // this is just to make sure the detection mechanism is properly installed + Mono blockingPublisher = + Mono.fromCallable( + () -> { + Thread.sleep(1); + return 0; + }) + .subscribeOn(Schedulers.parallel()); + StepVerifier.create(blockingPublisher) + .expectErrorMatches(e -> e instanceof Error && e.getMessage().contains("Blocking call!")) + .verify(); + } + + @Test + public void should_not_detect_blocking_call_on_asynchronous_execution() { + try (CqlSession session = SessionUtils.newSession(SIMULACRON_RULE)) { + Flux rows = + Flux.range(0, 1000) + .flatMap( + i -> + Flux.from(session.executeReactive("SELECT c1, c2 FROM ks.t1")) + .subscribeOn(Schedulers.parallel())); + StepVerifier.create(rows).expectNextCount(1000).expectComplete().verify(); + } + } + + @Test + public void should_not_detect_blocking_call_on_asynchronous_execution_prepared() { + try (CqlSession session = SessionUtils.newSession(SIMULACRON_RULE)) { + Flux rows = + Mono.fromCompletionStage(() -> session.prepareAsync("SELECT c1, c2 FROM ks.t1")) + .flatMapMany( + ps -> + Flux.range(0, 1000) + .map(i -> ps.bind()) + .flatMap( + bs -> + Flux.from(session.executeReactive(bs)) + .subscribeOn(Schedulers.parallel()))); + StepVerifier.create(rows).expectNextCount(1000).expectComplete().verify(); + } + } + + @Test + public void should_not_detect_blocking_call_on_random_uuid_generation() { + Flux uuids = + Flux.create( + sink -> { + for (int i = 0; i < 1_000_000; ++i) { + sink.next(Uuids.random()); + } + sink.complete(); + }) + .subscribeOn(Schedulers.parallel()); + StepVerifier.create(uuids).expectNextCount(1_000_000).expectComplete().verify(); + } + + @Test + public void should_not_detect_blocking_call_on_time_based_uuid_generation() { + Flux uuids = + Flux.create( + sink -> { + for (int i = 0; i < 1_000_000; ++i) { + sink.next(Uuids.timeBased()); + } + sink.complete(); + }) + .subscribeOn(Schedulers.parallel()); + StepVerifier.create(uuids).expectNextCount(1_000_000).expectComplete().verify(); + } +} diff --git a/integration-tests/src/test/resources/application.conf b/integration-tests/src/test/resources/application.conf index 45c1366bd45..668a71059cf 100644 --- a/integration-tests/src/test/resources/application.conf +++ b/integration-tests/src/test/resources/application.conf @@ -8,7 +8,7 @@ datastax-java-driver { # (see CcmBridge). local-datacenter = dc1 } - + config-reload-interval = 0 request.timeout = 10 seconds graph.timeout = 10 seconds } diff --git a/manual/core/async/README.md b/manual/core/async/README.md index 66687509cf2..2b70c64d1a4 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -61,8 +61,12 @@ resultStage.thenAccept(resultSet -> System.out.println(Thread.currentThread().ge // prints s0-io-n (I/O pool thread) ``` -As long as you use the asynchronous API, the driver never blocks. You can safely call a driver -method from inside a callback: +As long as you use the asynchronous API, the driver will behave in a non-blocking manner: its +internal threads will almost never block. There are a few exceptions to the rule though: see the +manual page on [non-blocking programming](../non_blocking) for details. + +Because the asynchronous API is non-blocking, you can safely call a driver method from inside a +callback, even when the callback's execution is triggered by a future returned by the driver: ```java // Get the department id for a given user: diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md new file mode 100644 index 00000000000..8f0aace18f3 --- /dev/null +++ b/manual/core/non_blocking/README.md @@ -0,0 +1,289 @@ +## Non-blocking programming + +### Quick overview + +With the advent of reactive programming, the demand for fully non-blocking libraries has become +popular among application developers. The recent availability of frameworks enforcing lock-freedom, +such as [Vert.x] or [Reactor], along with tools for automatic detection of blocking calls like +[BlockHound], has exacerbated this trend even more so. + +[Vert.x]: https://vertx.io +[Reactor]: https://projectreactor.io +[BlockHound]: https://github.com/reactor/BlockHound + +**In summary, when used properly, the DataStax Java driver offers non-blocking guarantees for most +of its operations, and during most of the session lifecycle.** + +These guarantees and their exceptions are detailed below. A final chapter explains how to use the +driver with BlockHound. + +The developer guide also has more information on driver internals and its +[concurrency model](../../developer/common/concurrency). + +### Definition of "non-blocking" + +Since the term "non-blocking" is subject to interpretation, in this page the term should be +understood as "[lock-free]": a program is non-blocking if at least one thread is guaranteed to make +progress; such programs are implemented without locks, mutexes nor semaphores, using only low-level +primitives such as atomic variables and CAS (compare-and-swap) instructions. + +A further distinction is generally established between "lock-free" and "wait-free" algorithms: the +former ones allow progress of the overall system, while the latter ones allow each thread to make +progress at any time. This distinction is however rather theoretical and is outside of the scope of +this document. + +[lock-free]: https://www.baeldung.com/lock-free-programming + +### Driver lock-free guarantees + +#### Driver lock-free guarantees per execution models + +The driver offers many execution models. For the built-in ones, the lock-free guarantees are as +follows: + +* The synchronous API is blocking and does not offer any lock-free guarantee. +* The [asynchronous](../async) API is implemented in lock-free algorithms. +* The [reactive](../reactive) API is implemented in lock-free algorithms (it's actually wait-free). + +For example, calling any synchronous method declared in [`SyncCqlSession`], such as [`execute`], +will block until the result is available. These methods should never be used in non-blocking +applications. + +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- + +However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all +safe for use in non-blocking applications; the statement execution and asynchronous result delivery +is guaranteed to never block. + +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- + +The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the +returned publisher will never block when subscribed to, until the final results are delivered to +the subscriber. + +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- + +There is one exception though: continuous paging queries (a feature specific to DSE) have a special +execution model which uses internal locks for coordination. Although such locks are only held for +extremely brief periods of time, and never under high contention, this execution model doesn't +qualify as lock-free. + +As a consequence, all methods declared in [`ContinuousSession`] and [`ContinuousReactiveSession`] +cannot be considered as implemented 100% lock-free, even those built on top of the asynchronous or +reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactive`]. In practice +though, continuous paging is extremely efficient and can safely be used in most non-blocking +contexts, unless they require strict lock-freedom. + +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- + +#### Driver lock-free guarantees per session lifecycle phases + +The guarantees vary according to three possible session states: initializing, running, and closing. + +Session initialization is a costly operation that performs many I/O operations, hitting both the +local filesystem (configuration files) and the network (connection initialization). This procedure +is triggered by a call to [`SessionBuilder.buildAsync()`] and happens partially on the calling +thread, and partially asynchronously on an internal driver thread. + +* The creation of the [driver context] happens synchronously on the calling thread. The context + creation usually requires file I/O, mainly to read configuration files. A call to + `SessionBuilder.buildAsync()`, in spite of its name, is thus a blocking call and must be + dispatched to a thread that is allowed to block. +* The rest of the initialization process will happen asynchronously, on an internal driver admin + thread. This process is mostly non-blocking, with a few exceptions listed below. Therefore, + the driver admin thread performing the initialization tasks must be allowed to block, at least + temporarily. + +[driver context]: ../../developer/common/context + +For the reasons above, the initialization phase obviously doesn't qualify as lock-free. For +non-blocking applications, it is generally advised to trigger session initialization during +application startup, before strong non-blocking guarantees are enforced on application threads. + +Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as it will block the +calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` +should be avoided in non-blocking applications. + +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- + +Once the session is initialized, however, the driver is guaranteed to be non-blocking during the +session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. + +Finally, closing the session is generally non-blocking, but the driver offers no strong guarantees +during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseable`], including the +asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is +shut down and lock-freedom enforcement is disabled. + +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- + +#### Driver lock-free guarantees for specific components + +Certain driver components are not implemented in lock-free algorithms. + +For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It +should not be used if strict lock-freedom is enforced. + +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html + +The same is valid for both built-in [request throttlers]: + +* `ConcurrencyLimitingRequestThrottler` +* `RateLimitingRequestThrottler` + +See the section about [throttling](../throttling) for details about these components. Again, they +use locks internally, and depending on how many requests are being executed in parallel, the thread +contention on these locks can be high: in short, if your application enforces strict lock-freedom, +then these components should not be used. + +[request throttlers]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html + +Other components may be lock-free, *except* for their first invocation. This is the case of the +following items: + +* All built-in implementations of [`TimestampGenerator`], upon instantiation; +* The utility method [`Uuids.timeBased()`]. + +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- + +Both components need to access native libraries when they get initialized and this may involve +hitting the local filesystem, thus causing the initialization to become a blocking call. + +Timestamp generators are automatically created when the session is initialized, and are thus +generally safe to use afterwards. + +`Uuids.timeBased()`, however, is a convenience method that the driver doesn't use internally. For +this reason, it is advised that this method be called once during application startup, so that it is +safe to use it afterwards in a non-blocking context. + +Alternatively, it's possible to disable the usage of client-side timestamp generation, and/or the +usage of native libraries. See the manual sections on [query timestamps](../query_timestamps) and +[integration](../integration) for more information. + +One component, the codec registry, can block when its [`register`] method is called; it is +therefore advised that codecs should be registered during application startup exclusively. See the +[custom codecs](../custom_codecs) section for more details about registering codecs. + +[`register`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- + +Finally, a few internal components also use locks, but only during session initialization; once the +session is ready, they are either discarded, or don't use locks anymore for the rest of the +session's lifecycle. + +These components are safe to use once the session is ready, although they could be reported by +lock-freedom monitoring tools. They are listed below in case their exclusion is necessary: + +* `com.datastax.oss.driver.internal.core.context.DefaultNettyOptions` +* `com.datastax.oss.driver.internal.core.util.concurrent.LazyReference` +* `com.datastax.oss.driver.internal.core.util.concurrent.ReplayingEventFilter` + +#### Driver lock-free guarantees on topology and status events + +Topology and status events can cause the driver to use locks temporarily. + +When a node gets added to the cluster, or when a node state changes (DOWN to UP or vice versa), the +driver needs to notify a few components: the load balancing policies need to coordinate in order to +assign a new distance to the node (LOCAL, REMOTE or IGNORED); and the node connection pool will have +to be resized either to accommodate new connections, or to close existing ones. + +These operations use internal locks for coordination. Again, they are only held for extremely brief +periods of time, and never under high contention. Note that this behavior cannot be disabled or +changed; if you need to enforce strict lock-freedom, and topology or status changes are being +reported as infringements, consider adding exceptions for the following method calls: + + * `com.datastax.oss.driver.internal.core.pool.ChannelSet#add(DriverChannel)` + * `com.datastax.oss.driver.internal.core.pool.ChannelSet#remote(DriverChannel)` + * `com.datastax.oss.driver.internal.core.metadata.LoadBalancingPolicyWrapper$SinglePolicyDistanceReporter#setDistance(Node,NodeDistance)` + +#### Driver lock-free guarantees on random uuid generation + +Until driver 4.9, the [`Uuids.random()`] method was a blocking call. Because of that, this method +could not be used in non-blocking contexts, making UUID generation a difficult issue to solve. + +Moreover, this method is used in a few places internally. This situation was unfortunate because +lock-freedom enforcement tools could report calls to that method, but it was impossible to suppress +these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a +non-blocking call and random UUIDs can now be safely generated in non-blocking applications. + +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 + +#### Driver lock-free guarantees when reloading the configuration + +The driver has a pluggable configuration mechanism built around the [`DriverConfigLoader`] +interface. Implementors may choose to support [hot-reloading] of configuration files, and the +default built-in implementation has this feature enabled by default. + +Beware that a hot-reloading of the default configuration mechanism is performed on a driver internal +admin thread. If hot-reloading is enabled, then this might be reported by lock-freedom infringement +detectors. If that is the case, it is advised to disable hot-reloading by setting the +`datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on +[configuration](../configuration) for more information. + +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- + +#### Driver lock-free guarantees when connecting to DSE + +When connecting to clusters running recent DSE versions, the driver automatically enables periodic +status reporting. When preparing the status report, the driver has to hit the local filesystem, and +because of that, the status reporting process does not qualify as lock-free. + +If lock-freedom is being enforced, then automatic status reporting must be disabled by setting the +`datastax-java-driver.advanced.monitor-reporting.enabled` property to false in the driver +configuration. + +### Driver mechanism for detection of blocking calls + +The driver has its own mechanism for detecting blocking calls happening on an internal driver +thread. This mechanism is capable of detecting and reporting blatant cases of misuse of the +asynchronous and reactive APIs, e.g. when the synchronous API is invoked inside a future or callback +produced by the asynchronous execution of a statement. See the core manual page on the +[asynchronous](../async) API or the developer manual page on +[driver concurrency](../../developer/common/concurrency) for details. + +The driver is not capable, however, of detecting low-level lock-freedom infringements, such as the +usage of locks. You must use an external tool to achieve that. See below how to use BlockHound for +that. + +### Using the driver with Reactor BlockHound + +[Reactor]'s tool for automatic detection of blocking calls, [BlockHound], is capable of detecting +and reporting any sort of blocking calls, including I/O, locks, `Thread.sleep`, etc. + +When used with the driver, BlockHound can report some calls that, for the reasons explained above, +could be safely considered as false positives. + +For this reason, the driver, since version 4.10, ships with a custom `DriverBlockHoundIntegration` +class which is automatically discovered by BlockHound through the Service Loader mechanism. It +contains BlockHound customizations that target most of the cases detailed above, and prevent them +from being reported as blocking calls. + +More specifically, the following items are currently declared to be allowed: + +* Loading of native libraries during startup (`TimestampGenerator`); +* Locks held during startup only (`DefaultNettyOptions`, `LazyReference`, `ReplayingEventFilter`); +* Locks held during startup and topology and status events processing (`ChannelSet`, + `DistanceReporter`); +* Locks held when executing continuous paging queries; +* Locks held during calls to `MutableCodecRegistry.register()` and `Uuids.timeBased()`. + +The following items are NOT declared to be allowed and are likely to be reported by BlockHound if +used: + +* Request throttlers; +* Automatic status reporting; +* `SafeInitNodeStateListener`. + +Note that other blocking startup steps, e.g. loading of configuration files, are also not declared +to be allowed, because these are genuine blocking I/O calls. For this reason, if BlockHound is being +used, the loading of the driver context, performed by the thread calling `SessionBuilder.build()` +or `SessionBuilder.buildAsync()`, must be allowed to perform blocking calls. diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index 25f74a26579..1c88908f4cd 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -6,13 +6,15 @@ streams]. Notes: -* reactive capabilities require the [Reactive Streams API] to be present on the classpath. The +* Reactive capabilities require the [Reactive Streams API] to be present on the classpath. The driver has a dependency on that library, but if your application does not use reactive queries at all, it is possible to exclude it to minimize the number of runtime dependencies. If the library cannot be found at runtime, reactive queries won't be available, and a warning will be logged, but the driver will otherwise operate normally (this is also valid for OSGi deployments). -* for historical reasons, reactive-related driver types reside in a package prefixed with `dse`; +* For historical reasons, reactive-related driver types reside in a package prefixed with `dse`; however, reactive queries also work with regular Cassandra. +* The reactive execution model is implemented in a non-blocking fashion: see the manual page on + [non-blocking programming](../non_blocking) for details. ### Overview diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index 3c6078f2eb4..be51e184ac5 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -77,12 +77,16 @@ fields, and methods are guaranteed to always run in isolation, eliminating subtl ### Non-blocking -Whether on the hot or cold path, internal code **never blocks**. If an internal component needs to -execute a query, it does so asynchronously, and registers callbacks to process the results. -Examples of this can be found in `ReprepareOnUp` and `DefaultTopologyMonitor` (among others). +Whether on the hot or cold path, internal code is almost 100% lock-free. The driver guarantees on +lock-freedom are [detailed](../../../core/non_blocking) in the core manual. -The only place where the driver blocks are synchronous wrapper methods in the public API, for -example: +If an internal component needs to execute a query, it does so asynchronously, and registers +callbacks to process the results. Examples of this can be found in `ReprepareOnUp` and +`DefaultTopologyMonitor` (among others). + +The only place where the driver blocks is when using the synchronous API (methods declared in +[`SyncCqlSession`]), and when calling other synchronous wrapper methods in the public API, for +example, [`ExecutionInfo.getQueryTrace()`]: ```java public interface ExecutionInfo { @@ -95,6 +99,11 @@ public interface ExecutionInfo { } ``` +When a public API method is blocking, this is generally clearly stated in its javadocs. + +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` + `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/pom.xml b/pom.xml index 08309f95361..5e9fe4473df 100644 --- a/pom.xml +++ b/pom.xml @@ -420,6 +420,23 @@ smallrye-metrics 2.4.4 + + io.projectreactor + reactor-bom + 2020.0.1 + pom + import + + + io.projectreactor.tools + blockhound + 1.0.4.RELEASE + + + io.projectreactor.tools + blockhound-junit-platform + 1.0.4.RELEASE + From e6ae0529f8441ba149a4c35c16b4fd78a235ff95 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 19 Dec 2020 18:46:22 +0100 Subject: [PATCH 028/395] Fix wrong keyspace inclusion/exclusion logic in MetadataManager (JAVA-2871 follow-up) --- .../oss/driver/internal/core/metadata/MetadataManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java index 6db1db038bd..594c37430d4 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java @@ -25,6 +25,7 @@ import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.control.ControlConnection; import com.datastax.oss.driver.internal.core.metadata.schema.parsing.SchemaParserFactory; +import com.datastax.oss.driver.internal.core.metadata.schema.queries.KeyspaceFilter; import com.datastax.oss.driver.internal.core.metadata.schema.queries.SchemaQueriesFactory; import com.datastax.oss.driver.internal.core.metadata.schema.queries.SchemaRows; import com.datastax.oss.driver.internal.core.metadata.schema.refresh.SchemaRefresh; @@ -65,6 +66,7 @@ public class MetadataManager implements AsyncAutoCloseable { private volatile DefaultMetadata metadata; // only updated from adminExecutor private volatile boolean schemaEnabledInConfig; private volatile List refreshedKeyspaces; + private volatile KeyspaceFilter keyspaceFilter; private volatile Boolean schemaEnabledProgrammatically; private volatile boolean tokenMapEnabled; private volatile Set contactPoints; @@ -86,6 +88,7 @@ protected MetadataManager(InternalDriverContext context, DefaultMetadata initial this.refreshedKeyspaces = config.getStringList( DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, Collections.emptyList()); + this.keyspaceFilter = KeyspaceFilter.newInstance(logPrefix, refreshedKeyspaces); this.tokenMapEnabled = config.getBoolean(DefaultDriverOption.METADATA_TOKEN_MAP_ENABLED); context.getEventBus().register(ConfigChangeEvent.class, this::onConfigChanged); @@ -100,6 +103,7 @@ private void onConfigChanged(@SuppressWarnings("unused") ConfigChangeEvent event this.refreshedKeyspaces = config.getStringList( DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, Collections.emptyList()); + this.keyspaceFilter = KeyspaceFilter.newInstance(logPrefix, refreshedKeyspaces); this.tokenMapEnabled = config.getBoolean(DefaultDriverOption.METADATA_TOKEN_MAP_ENABLED); if ((!schemaEnabledBefore @@ -372,8 +376,7 @@ private void refreshSchema( } // If this is an event, make sure it's not targeting a keyspace that we're ignoring. - boolean isRefreshedKeyspace = - keyspace == null || refreshedKeyspaces.isEmpty() || refreshedKeyspaces.contains(keyspace); + boolean isRefreshedKeyspace = keyspace == null || keyspaceFilter.includes(keyspace); if (isRefreshedKeyspace && (evenIfDisabled || isSchemaEnabled())) { acceptSchemaRequest(future, flushNow); From 5f24d21c2b7e0464b15a15a397c07276f64c4ead Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 19 Dec 2020 18:46:44 +0100 Subject: [PATCH 029/395] Exclude OpsCenter keyspace by default (JAVA-2871 follow-up) --- .../com/datastax/oss/driver/api/core/config/OptionsMap.java | 2 +- core/src/main/resources/reference.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 5123e341036..2b4a767e29d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -342,7 +342,7 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.METADATA_SCHEMA_ENABLED, true); map.put( TypedDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, - ImmutableList.of("!system", "!/^system_.*/", "!/^dse_.*/", "!solr_admin")); + ImmutableList.of("!system", "!/^system_.*/", "!/^dse_.*/", "!solr_admin", "!OpsCenter")); map.put(TypedDriverOption.METADATA_SCHEMA_REQUEST_TIMEOUT, requestTimeout); map.put(TypedDriverOption.METADATA_SCHEMA_REQUEST_PAGE_SIZE, requestPageSize); map.put(TypedDriverOption.METADATA_SCHEMA_WINDOW, Duration.ofSeconds(1)); diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index d303db0b036..3ff88c024b0 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1819,7 +1819,7 @@ datastax-java-driver { # Modifiable at runtime: yes, the new value will be used for refreshes issued after the # change. # Overridable in a profile: no - refreshed-keyspaces = [ "!system", "!/^system_.*/", "!/^dse_.*/", "!solr_admin" ] + refreshed-keyspaces = [ "!system", "!/^system_.*/", "!/^dse_.*/", "!solr_admin", "!OpsCenter" ] # The timeout for the requests to the schema tables. # From 0be46e020cd8e1e2a32f691d02813333923c5f1a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 19 Dec 2020 18:47:22 +0100 Subject: [PATCH 030/395] FIx failing integration tests (JAVA-2871 follow-up) --- .../datastax/oss/driver/core/ConnectIT.java | 4 +-- .../oss/driver/core/metadata/SchemaIT.java | 29 ++++++++----------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java index d933643e647..f7619d41791 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ConnectIT.java @@ -67,7 +67,7 @@ public void setup() { // Absolute minimum for a working schema metadata (we just want to check that it gets // loaded at startup). when("SELECT * FROM system_schema.keyspaces") - .then(rows().row("keyspace_name", "system"))); + .then(rows().row("keyspace_name", "system").row("keyspace_name", "test"))); } @Test @@ -113,7 +113,7 @@ public void should_wait_for_contact_points_if_reconnection_enabled() throws Exce // Then this doesn't throw try (Session session = sessionFuture.get(30, TimeUnit.SECONDS)) { - assertThat(session.getMetadata().getKeyspaces()).containsKey(CqlIdentifier.fromCql("system")); + assertThat(session.getMetadata().getKeyspaces()).containsKey(CqlIdentifier.fromCql("test")); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index 249e0a5377d..aa5a862cb42 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -60,18 +60,21 @@ public class SchemaIT { @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); @Test - public void should_expose_system_and_test_keyspace() { + public void should_not_expose_system_and_test_keyspace() { Map keyspaces = sessionRule.session().getMetadata().getKeyspaces(); assertThat(keyspaces) - .containsKeys( + .doesNotContainKeys( // Don't test exhaustively because system keyspaces depend on the Cassandra version, and // keyspaces from other tests might also be present - CqlIdentifier.fromInternal("system"), - CqlIdentifier.fromInternal("system_traces"), - sessionRule.keyspace()); - assertThat(keyspaces.get(CqlIdentifier.fromInternal("system")).getTables()) - .containsKeys(CqlIdentifier.fromInternal("local"), CqlIdentifier.fromInternal("peers")); + CqlIdentifier.fromInternal("system"), CqlIdentifier.fromInternal("system_traces")); + } + + @Test + public void should_expose_test_keyspace() { + Map keyspaces = + sessionRule.session().getMetadata().getKeyspaces(); + assertThat(keyspaces).containsKey(sessionRule.keyspace()); } @Test @@ -124,11 +127,7 @@ public void should_enable_schema_programmatically_when_disabled_in_config() { .pollInterval(500, TimeUnit.MILLISECONDS) .atMost(60, TimeUnit.SECONDS) .untilAsserted(() -> assertThat(session.getMetadata().getKeyspaces()).isNotEmpty()); - assertThat(session.getMetadata().getKeyspaces()) - .containsKeys( - CqlIdentifier.fromInternal("system"), - CqlIdentifier.fromInternal("system_traces"), - sessionRule.keyspace()); + assertThat(session.getMetadata().getKeyspaces()).containsKey(sessionRule.keyspace()); session.setSchemaMetadataEnabled(null); assertThat(session.isSchemaMetadataEnabled()).isFalse(); @@ -177,11 +176,7 @@ public void should_refresh_schema_manually() { assertThat(session.getMetadata().getKeyspaces()).isEmpty(); Metadata newMetadata = session.refreshSchema(); - assertThat(newMetadata.getKeyspaces()) - .containsKeys( - CqlIdentifier.fromInternal("system"), - CqlIdentifier.fromInternal("system_traces"), - sessionRule.keyspace()); + assertThat(newMetadata.getKeyspaces()).containsKey(sessionRule.keyspace()); assertThat(session.getMetadata()).isSameAs(newMetadata); } From aedcc71acafd383e89e665c97823710c6f480090 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 19 Dec 2020 19:04:54 +0100 Subject: [PATCH 031/395] Mention automatically excluded keyspaces in upgrade guide (JAVA-2871 follow-up) --- upgrade_guide/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index a873731705b..6b1536ad12c 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -2,6 +2,8 @@ ### 4.10.0 +#### Enhancements to the `Uuids` utility class + [JAVA-2449](https://datastax-oss.atlassian.net/browse/JAVA-2449) modified the implementation of [Uuids.random()]: this method does not delegate anymore to the JDK's `java.util.UUID.randomUUID()` implementation, but instead re-implements random UUID generation using the non-cryptographic @@ -24,6 +26,29 @@ This release also introduces two new methods for random UUID generation: [Uuids.random(Random)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.Random- [Uuids.random(SplittableRandom)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.SplittableRandom- +#### System and DSE keyspaces automatically excluded from metadata and token map computation + +[JAVA-2871](https://datastax-oss.atlassian.net/browse/JAVA-2871) now allows for a more fine-grained +control over which keyspaces should qualify for metadata and token map computation, including the +ability to *exclude* keyspaces based on their names. + +From now on, the following keyspaces are automatically excluded: + +1. The `system` keyspace; +2. All keyspaces starting with `system_`; +3. DSE-specific keyspaces: + 1. All keyspaces starting with `dse_`; + 2. The `solr_admin` keyspace; + 3. The `OpsCenter` keyspace. + +This means that they won't show up anymore in [Metadata.getKeyspaces()], and [TokenMap] will return +empty replicas and token ranges for them. If you need the driver to keep computing metadata and +token map for these keyspaces, you now must modify the following configuration option: +`datastax-java-driver.advanced.metadata.schema.refreshed-keyspaces`. + +[Metadata.getKeyspaces()]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/TokenMap.html + ### 4.5.x - 4.6.0 These versions are subject to [JAVA-2676](https://datastax-oss.atlassian.net/browse/JAVA-2676), a From 25d5c7382adffaf09296c5311cfb8fc0375d2e72 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 11:08:19 +0100 Subject: [PATCH 032/395] Simplify lambda --- .../oss/driver/internal/core/control/ControlConnection.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java b/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java index 294bfd7e060..bcba1e76583 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java @@ -303,9 +303,7 @@ private void init( connect( nodes, null, - () -> { - initFuture.complete(null); - }, + () -> initFuture.complete(null), error -> { if (isAuthFailure(error)) { LOG.warn( From ae2d208b24678710a4235f79dc7c8d9d1e84972a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 11:08:35 +0100 Subject: [PATCH 033/395] Remove unused field --- .../driver/internal/core/control/ControlConnectionTestBase.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/control/ControlConnectionTestBase.java b/core/src/test/java/com/datastax/oss/driver/internal/core/control/ControlConnectionTestBase.java index ca349d135a1..8e994c5fdc9 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/control/ControlConnectionTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/control/ControlConnectionTestBase.java @@ -58,7 +58,6 @@ abstract class ControlConnectionTestBase { protected static final InetSocketAddress ADDRESS1 = new InetSocketAddress("127.0.0.1", 9042); - protected static final InetSocketAddress ADDRESS2 = new InetSocketAddress("127.0.0.2", 9042); /** How long we wait when verifying mocks for async invocations */ protected static final VerificationWithTimeout VERIFY_TIMEOUT = timeout(500); From ad3db9cda4bfd6af74e35346057764fa1745ee21 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 11:17:26 +0100 Subject: [PATCH 034/395] JAVA-2904: Upgrade Jackson to 2.12.0 and Tinkerpop to 3.4.9 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 5e9fe4473df..f4097e4d1a4 100644 --- a/pom.xml +++ b/pom.xml @@ -50,12 +50,12 @@ 4.1.16 4.1.51.Final 1.2.1 - 3.4.8 + 3.4.9 1.7.26 1.0.3 20201115 - 2.11.0 - 2.11.0 + 2.12.0 + 2.12.0 1.9.12 1.1.7.3 From 6ec72c452e00c22a7488d6cccec3ef87420f7c6b Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 27 Nov 2020 21:28:39 +0100 Subject: [PATCH 035/395] JAVA-2900: Allow the request to retry to be customized by the retry policy --- .../ContinuousCqlRequestHandler.java | 57 ++--- .../ContinuousRequestHandlerBase.java | 194 ++++++++-------- .../graph/ContinuousGraphRequestHandler.java | 55 +++-- .../internal/core/graph/GraphConversions.java | 17 ++ .../core/graph/GraphRequestHandler.java | 219 ++++++++++-------- .../driver/api/core/retry/RetryDecision.java | 6 +- .../driver/api/core/retry/RetryPolicy.java | 154 ++++++++++++ .../driver/api/core/retry/RetryVerdict.java | 60 +++++ .../driver/internal/core/cql/Conversions.java | 29 +++ .../internal/core/cql/CqlPrepareHandler.java | 99 ++++---- .../internal/core/cql/CqlRequestHandler.java | 219 ++++++++++-------- .../core/retry/DefaultRetryPolicy.java | 5 + .../ContinuousCqlRequestHandlerRetryTest.java | 98 ++++---- .../ContinuousGraphRequestHandlerTest.java | 11 +- .../api/core/retry/RetryPolicyTestBase.java | 17 +- .../core/cql/CqlPrepareHandlerTest.java | 14 +- .../core/cql/CqlRequestHandlerRetryTest.java | 54 ++--- .../oss/driver/core/AllNodesFailedIT.java | 1 + .../core/config/MapBasedConfigLoaderIT.java | 5 + .../driver/core/connection/FrameLengthIT.java | 1 + .../core/retry/PerProfileRetryPolicyIT.java | 6 + upgrade_guide/README.md | 24 ++ 22 files changed, 876 insertions(+), 469 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandler.java index ca2631fae75..310872cfe47 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandler.java @@ -20,6 +20,7 @@ import com.datastax.dse.driver.api.core.metrics.DseSessionMetric; import com.datastax.dse.driver.internal.core.cql.DseConversions; import com.datastax.dse.protocol.internal.response.result.DseRowsMetadata; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.ColumnDefinitions; import com.datastax.oss.driver.api.core.cql.ExecutionInfo; import com.datastax.oss.driver.api.core.cql.Row; @@ -27,6 +28,7 @@ import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.cql.Conversions; import com.datastax.oss.driver.internal.core.cql.DefaultRow; import com.datastax.oss.driver.internal.core.session.DefaultSession; import com.datastax.oss.driver.internal.core.util.CountingIterator; @@ -45,13 +47,7 @@ */ @ThreadSafe public class ContinuousCqlRequestHandler - extends ContinuousRequestHandlerBase { - - private final Message message; - private final Duration firstPageTimeout; - private final Duration otherPagesTimeout; - private final int maxEnqueuedPages; - private final int maxPages; + extends ContinuousRequestHandlerBase, ContinuousAsyncResultSet> { ContinuousCqlRequestHandler( @NonNull Statement statement, @@ -68,14 +64,6 @@ public class ContinuousCqlRequestHandler DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, DseSessionMetric.CONTINUOUS_CQL_REQUESTS, DefaultNodeMetric.CQL_MESSAGES); - message = DseConversions.toContinuousPagingMessage(statement, executionProfile, context); - firstPageTimeout = - executionProfile.getDuration(DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_FIRST_PAGE); - otherPagesTimeout = - executionProfile.getDuration(DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_OTHER_PAGES); - maxEnqueuedPages = - executionProfile.getInt(DseDriverOption.CONTINUOUS_PAGING_MAX_ENQUEUED_PAGES); - maxPages = executionProfile.getInt(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES); // NOTE that ordering of the following statement matters. // We should register this request after all fields have been initialized. throttler.register(this); @@ -89,40 +77,54 @@ protected Duration getGlobalTimeout() { @NonNull @Override - protected Duration getPageTimeout(int pageNumber) { - return pageNumber == 1 ? firstPageTimeout : otherPagesTimeout; + protected Duration getPageTimeout(@NonNull Statement statement, int pageNumber) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + if (pageNumber == 1) { + return executionProfile.getDuration(DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_FIRST_PAGE); + } else { + return executionProfile.getDuration(DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_OTHER_PAGES); + } } @NonNull @Override - protected Duration getReviseRequestTimeout() { - return otherPagesTimeout; + protected Duration getReviseRequestTimeout(@NonNull Statement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return executionProfile.getDuration(DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_OTHER_PAGES); } @Override - protected int getMaxEnqueuedPages() { - return maxEnqueuedPages; + protected int getMaxEnqueuedPages(@NonNull Statement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return executionProfile.getInt(DseDriverOption.CONTINUOUS_PAGING_MAX_ENQUEUED_PAGES); } @Override - protected int getMaxPages() { - return maxPages; + protected int getMaxPages(@NonNull Statement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return executionProfile.getInt(DseDriverOption.CONTINUOUS_PAGING_MAX_PAGES); } @NonNull @Override - protected Message getMessage() { - return message; + protected Message getMessage(@NonNull Statement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return DseConversions.toContinuousPagingMessage(statement, executionProfile, context); } @Override - protected boolean isTracingEnabled() { + protected boolean isTracingEnabled(@NonNull Statement statement) { return false; } @NonNull @Override - protected Map createPayload() { + protected Map createPayload(@NonNull Statement statement) { return statement.getCustomPayload(); } @@ -135,6 +137,7 @@ protected ContinuousAsyncResultSet createEmptyResultSet(@NonNull ExecutionInfo e @NonNull @Override protected DefaultContinuousAsyncResultSet createResultSet( + @NonNull Statement statement, @NonNull Rows rows, @NonNull ExecutionInfo executionInfo, @NonNull ColumnDefinitions columnDefinitions) { diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java index de6dee6f8be..c7784c2b2d3 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java @@ -36,8 +36,8 @@ import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; -import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; import com.datastax.oss.driver.api.core.servererrors.FunctionFailureException; @@ -49,7 +49,6 @@ import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.api.core.session.throttling.Throttled; -import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.internal.core.adminrequest.ThrottledAdminRequestHandler; import com.datastax.oss.driver.internal.core.adminrequest.UnexpectedResponseException; import com.datastax.oss.driver.internal.core.channel.DriverChannel; @@ -114,23 +113,19 @@ public abstract class ContinuousRequestHandlerBase queryPlan; - private final RetryPolicy retryPolicy; protected final RequestThrottler throttler; private final boolean protocolBackpressureAvailable; - private final boolean isIdempotent; private final Timer timer; private final SessionMetricUpdater sessionMetricUpdater; private final boolean specExecEnabled; private final SessionMetric clientTimeoutsMetric; private final SessionMetric continuousRequestsMetric; private final NodeMetric messagesMetric; - private final SpeculativeExecutionPolicy speculativeExecutionPolicy; private final List scheduledExecutions; // The errors on the nodes that were already tried. @@ -162,10 +157,10 @@ public abstract class ContinuousRequestHandlerBase resultSetClass; + private final Class resultSetClass; public ContinuousRequestHandlerBase( @NonNull StatementT statement, @@ -191,23 +186,18 @@ public ContinuousRequestHandlerBase( this.messagesMetric = messagesMetric; this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); LOG.trace("[{}] Creating new continuous handler for request {}", logPrefix, statement); - this.statement = statement; + this.initialStatement = statement; this.session = session; this.keyspace = session.getKeyspace().orElse(null); this.context = context; - this.executionProfile = Conversions.resolveExecutionProfile(this.statement, this.context); + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); this.queryPlan = statement.getNode() != null ? new QueryPlan(statement.getNode()) : context .getLoadBalancingPolicyWrapper() .newQueryPlan(statement, executionProfile.getName(), session); - this.retryPolicy = context.getRetryPolicy(executionProfile.getName()); - Boolean idempotent = statement.isIdempotent(); - this.isIdempotent = - idempotent == null - ? executionProfile.getBoolean(DefaultDriverOption.REQUEST_DEFAULT_IDEMPOTENCE) - : idempotent; this.timer = context.getNettyOptions().getTimer(); this.protocolBackpressureAvailable = @@ -215,11 +205,7 @@ public ContinuousRequestHandlerBase( this.throttler = context.getRequestThrottler(); this.sessionMetricUpdater = session.getMetricUpdater(); this.startTimeNanos = System.nanoTime(); - this.specExecEnabled = specExecEnabled && isIdempotent; - this.speculativeExecutionPolicy = - this.specExecEnabled - ? context.getSpeculativeExecutionPolicy(executionProfile.getName()) - : null; + this.specExecEnabled = specExecEnabled; this.scheduledExecutions = this.specExecEnabled ? new CopyOnWriteArrayList<>() : null; } @@ -227,22 +213,22 @@ public ContinuousRequestHandlerBase( protected abstract Duration getGlobalTimeout(); @NonNull - protected abstract Duration getPageTimeout(int pageNumber); + protected abstract Duration getPageTimeout(@NonNull StatementT statement, int pageNumber); @NonNull - protected abstract Duration getReviseRequestTimeout(); + protected abstract Duration getReviseRequestTimeout(@NonNull StatementT statement); - protected abstract int getMaxEnqueuedPages(); + protected abstract int getMaxEnqueuedPages(@NonNull StatementT statement); - protected abstract int getMaxPages(); + protected abstract int getMaxPages(@NonNull StatementT statement); @NonNull - protected abstract Message getMessage(); + protected abstract Message getMessage(@NonNull StatementT statement); - protected abstract boolean isTracingEnabled(); + protected abstract boolean isTracingEnabled(@NonNull StatementT statement); @NonNull - protected abstract Map createPayload(); + protected abstract Map createPayload(@NonNull StatementT statement); @NonNull protected abstract ResultSetT createEmptyResultSet(@NonNull ExecutionInfo executionInfo); @@ -251,6 +237,7 @@ public ContinuousRequestHandlerBase( @NonNull protected abstract ResultSetT createResultSet( + @NonNull StatementT statement, @NonNull Rows rows, @NonNull ExecutionInfo executionInfo, @NonNull ColumnDefinitions columnDefinitions) @@ -260,6 +247,8 @@ protected abstract ResultSetT createResultSet( @Override public void onThrottleReady(boolean wasDelayed) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialStatement, context); if (wasDelayed // avoid call to nanoTime() if metric is disabled: && sessionMetricUpdater.isEnabled( @@ -273,11 +262,13 @@ public void onThrottleReady(boolean wasDelayed) { TimeUnit.NANOSECONDS); } activeExecutionsCount.incrementAndGet(); - sendRequest(null, 0, 0, specExecEnabled); + sendRequest(initialStatement, null, 0, 0, specExecEnabled); } @Override public void onThrottleFailure(@NonNull RequestThrottlingException error) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialStatement, context); session .getMetricUpdater() .incrementCounter(DefaultSessionMetric.THROTTLING_ERRORS, executionProfile.getName()); @@ -346,6 +337,7 @@ public CompletionStage fetchNextPage() { * @param scheduleSpeculativeExecution whether to schedule the next speculative execution */ private void sendRequest( + StatementT statement, @Nullable Node node, int currentExecutionIndex, int retryCount, @@ -368,6 +360,7 @@ private void sendRequest( } else if (!chosenCallback.isDone()) { NodeResponseCallback nodeResponseCallback = new NodeResponseCallback( + statement, node, channel, currentExecutionIndex, @@ -376,7 +369,11 @@ private void sendRequest( logPrefix); inFlightCallbacks.add(nodeResponseCallback); channel - .write(getMessage(), isTracingEnabled(), createPayload(), nodeResponseCallback) + .write( + getMessage(statement), + isTracingEnabled(statement), + createPayload(statement), + nodeResponseCallback) .addListener(nodeResponseCallback); } } @@ -469,6 +466,7 @@ private class NodeResponseCallback implements ResponseCallback, GenericFutureListener> { private final long messageStartTimeNanos = System.nanoTime(); + private final StatementT statement; private final Node node; private final DriverChannel channel; // The identifier of the current execution (0 for the initial execution, 1 for the first @@ -479,6 +477,8 @@ private class NodeResponseCallback private final String logPrefix; private final boolean scheduleSpeculativeExecution; + private final DriverExecutionProfile executionProfile; + // Coordinates concurrent accesses between the client and I/O threads private final ReentrantLock lock = new ReentrantLock(); @@ -534,18 +534,21 @@ private class NodeResponseCallback private final AtomicBoolean nodeSuccessReported = new AtomicBoolean(false); public NodeResponseCallback( + StatementT statement, Node node, DriverChannel channel, int executionIndex, int retryCount, boolean scheduleSpeculativeExecution, String logPrefix) { + this.statement = statement; this.node = node; this.channel = channel; this.executionIndex = executionIndex; this.retryCount = retryCount; this.scheduleSpeculativeExecution = scheduleSpeculativeExecution; this.logPrefix = logPrefix + "|" + executionIndex; + this.executionProfile = Conversions.resolveExecutionProfile(statement, context); } @Override @@ -632,16 +635,17 @@ public void operationComplete(@NonNull Future future) { .incrementCounter(DefaultNodeMetric.UNSENT_REQUESTS, executionProfile.getName()); recordError(node, error); trackNodeError(node, error.getCause()); - sendRequest(null, executionIndex, retryCount, scheduleSpeculativeExecution); + sendRequest(statement, null, executionIndex, retryCount, scheduleSpeculativeExecution); } } else { LOG.trace("[{}] Request sent on {}", logPrefix, channel); - if (scheduleSpeculativeExecution) { + if (scheduleSpeculativeExecution && Conversions.resolveIdempotence(statement, context)) { int nextExecution = executionIndex + 1; // Note that `node` is the first node of the execution, it might not be the "slow" one // if there were retries, but in practice retries are rare. long nextDelay = - speculativeExecutionPolicy.nextExecution(node, keyspace, statement, nextExecution); + Conversions.resolveSpeculativeExecutionPolicy(statement, context) + .nextExecution(node, keyspace, statement, nextExecution); if (nextDelay >= 0) { scheduleSpeculativeExecution(nextExecution, nextDelay); } else { @@ -676,7 +680,7 @@ private void scheduleSpeculativeExecution(int nextExecutionIndex, long delay) { nodeMetricUpdater.incrementCounter( DefaultNodeMetric.SPECULATIVE_EXECUTIONS, executionProfile.getName()); } - sendRequest(null, nextExecutionIndex, 0, true); + sendRequest(statement, null, nextExecutionIndex, 0, true); } }, delay, @@ -690,7 +694,7 @@ private Timeout schedulePageTimeout(int expectedPage) { if (expectedPage < 0) { return null; } - Duration timeout = getPageTimeout(expectedPage); + Duration timeout = getPageTimeout(statement, expectedPage); if (timeout.toNanos() <= 0) { return null; } @@ -765,7 +769,7 @@ public void onResponse(@NonNull Frame response) { * Invoked when a continuous paging request hits an unexpected error. * *

    Delegates further processing to to the retry policy ({@link - * #processRetryDecision(RetryDecision, Throwable)}. + * #processRetryVerdict(RetryVerdict, Throwable)}. * * @param error the error encountered, usually a network problem. */ @@ -773,12 +777,14 @@ public void onResponse(@NonNull Frame response) { public void onFailure(@NonNull Throwable error) { cancelTimeout(pageTimeout); LOG.trace(String.format("[%s] Request failure", logPrefix), error); - RetryDecision decision; - if (!isIdempotent || error instanceof FrameTooLongException) { - decision = RetryDecision.RETHROW; + RetryVerdict verdict; + if (!Conversions.resolveIdempotence(statement, context) + || error instanceof FrameTooLongException) { + verdict = RetryVerdict.RETHROW; } else { try { - decision = retryPolicy.onRequestAborted(statement, error, retryCount); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + verdict = retryPolicy.onRequestAbortedVerdict(statement, error, retryCount); } catch (Throwable cause) { abort( new IllegalStateException("Unexpected error while invoking the retry policy", cause), @@ -788,13 +794,13 @@ public void onFailure(@NonNull Throwable error) { } updateErrorMetrics( ((DefaultNode) node).getMetricUpdater(), - decision, + verdict, DefaultNodeMetric.ABORTED_REQUESTS, DefaultNodeMetric.RETRIES_ON_ABORTED, DefaultNodeMetric.IGNORES_ON_ABORTED); lock.lock(); try { - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); } finally { lock.unlock(); } @@ -814,7 +820,7 @@ public void onFailure(@NonNull Throwable error) { private void processResultResponse(@NonNull Result result, @Nullable Frame frame) { assert lock.isHeldByCurrentThread(); try { - ExecutionInfo executionInfo = createExecutionInfo(node, result, frame, executionIndex); + ExecutionInfo executionInfo = createExecutionInfo(result, frame); if (result instanceof Rows) { DseRowsMetadata rowsMetadata = (DseRowsMetadata) ((Rows) result).getMetadata(); if (columnDefinitions == null) { @@ -833,7 +839,8 @@ private void processResultResponse(@NonNull Result result, @Nullable Frame frame false); } else { int pageSize = ((Rows) result).getData().size(); - ResultSetT resultSet = createResultSet((Rows) result, executionInfo, columnDefinitions); + ResultSetT resultSet = + createResultSet(statement, (Rows) result, executionInfo, columnDefinitions); if (rowsMetadata.isLastContinuousPage) { LOG.trace("[{}] Received last page ({} - {} rows)", logPrefix, pageNumber, pageSize); state = STATE_FINISHED; @@ -894,7 +901,7 @@ private void processErrorResponse(@NonNull Error errorMessage) { LOG.trace("[{}] {} is bootstrapping, trying next node", logPrefix, node); recordError(node, error); trackNodeError(node, error); - sendRequest(null, executionIndex, retryCount, false); + sendRequest(statement, null, executionIndex, retryCount, false); } else if (error instanceof QueryValidationException || error instanceof FunctionFailureException || error instanceof ProtocolError @@ -921,18 +928,19 @@ private void processErrorResponse(@NonNull Error errorMessage) { * Processes a recoverable error. * *

    In most cases, delegates to the retry policy and its decision, see {@link - * #processRetryDecision(RetryDecision, Throwable)}. + * #processRetryVerdict(RetryVerdict, Throwable)}. * * @param error the recoverable error. */ private void processRecoverableError(@NonNull CoordinatorException error) { assert lock.isHeldByCurrentThread(); NodeMetricUpdater metricUpdater = ((DefaultNode) node).getMetricUpdater(); - RetryDecision decision; + RetryVerdict verdict; + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); if (error instanceof ReadTimeoutException) { ReadTimeoutException readTimeout = (ReadTimeoutException) error; - decision = - retryPolicy.onReadTimeout( + verdict = + retryPolicy.onReadTimeoutVerdict( statement, readTimeout.getConsistencyLevel(), readTimeout.getBlockFor(), @@ -941,15 +949,15 @@ private void processRecoverableError(@NonNull CoordinatorException error) { retryCount); updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.READ_TIMEOUTS, DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT); } else if (error instanceof WriteTimeoutException) { WriteTimeoutException writeTimeout = (WriteTimeoutException) error; - if (isIdempotent) { - decision = - retryPolicy.onWriteTimeout( + if (Conversions.resolveIdempotence(statement, context)) { + verdict = + retryPolicy.onWriteTimeoutVerdict( statement, writeTimeout.getConsistencyLevel(), writeTimeout.getWriteType(), @@ -957,18 +965,18 @@ private void processRecoverableError(@NonNull CoordinatorException error) { writeTimeout.getReceived(), retryCount); } else { - decision = RetryDecision.RETHROW; + verdict = RetryVerdict.RETHROW; } updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.WRITE_TIMEOUTS, DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT); } else if (error instanceof UnavailableException) { UnavailableException unavailable = (UnavailableException) error; - decision = - retryPolicy.onUnavailable( + verdict = + retryPolicy.onUnavailableVerdict( statement, unavailable.getConsistencyLevel(), unavailable.getRequired(), @@ -976,23 +984,23 @@ private void processRecoverableError(@NonNull CoordinatorException error) { retryCount); updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.UNAVAILABLES, DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, DefaultNodeMetric.IGNORES_ON_UNAVAILABLE); } else { - decision = - isIdempotent - ? retryPolicy.onErrorResponse(statement, error, retryCount) - : RetryDecision.RETHROW; + verdict = + Conversions.resolveIdempotence(statement, context) + ? retryPolicy.onErrorResponseVerdict(statement, error, retryCount) + : RetryVerdict.RETHROW; updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.OTHER_ERRORS, DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, DefaultNodeMetric.IGNORES_ON_OTHER_ERROR); } - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); } /** @@ -1050,7 +1058,7 @@ private void processUnprepared(@NonNull Unprepared errorMessage) { "[{}] Re-prepare successful, retrying on the same node ({})", logPrefix, node); - sendRequest(node, executionIndex, retryCount, false); + sendRequest(statement, node, executionIndex, retryCount, false); } } else { if (exception instanceof UnexpectedResponseException) { @@ -1074,7 +1082,7 @@ private void processUnprepared(@NonNull Unprepared errorMessage) { LOG.trace("[{}] Re-prepare failed, trying next node", logPrefix); recordError(node, exception); trackNodeError(node, exception); - sendRequest(null, executionIndex, retryCount, false); + sendRequest(statement, null, executionIndex, retryCount, false); } } if (fatalError != null) { @@ -1092,22 +1100,24 @@ private void processUnprepared(@NonNull Unprepared errorMessage) { * Processes the retry decision by triggering a retry, aborting or ignoring; also records the * failures for further access. * - * @param decision the decision to process. + * @param verdict the verdict to process. * @param error the original error. */ - private void processRetryDecision(@NonNull RetryDecision decision, @NonNull Throwable error) { + private void processRetryVerdict(@NonNull RetryVerdict verdict, @NonNull Throwable error) { assert lock.isHeldByCurrentThread(); - LOG.trace("[{}] Processing retry decision {}", logPrefix, decision); - switch (decision) { + LOG.trace("[{}] Processing retry decision {}", logPrefix, verdict); + switch (verdict.getRetryDecision()) { case RETRY_SAME: recordError(node, error); trackNodeError(node, error); - sendRequest(node, executionIndex, retryCount + 1, false); + sendRequest( + verdict.getRetryRequest(statement), node, executionIndex, retryCount + 1, false); break; case RETRY_NEXT: recordError(node, error); trackNodeError(node, error); - sendRequest(null, executionIndex, retryCount + 1, false); + sendRequest( + verdict.getRetryRequest(statement), null, executionIndex, retryCount + 1, false); break; case RETHROW: trackNodeError(node, error); @@ -1148,8 +1158,8 @@ private void enqueueOrCompletePending(@NonNull Object pageOrError) { return; } - queue = new ArrayDeque<>(getMaxEnqueuedPages()); - numPagesRequested = protocolBackpressureAvailable ? getMaxEnqueuedPages() : 0; + queue = new ArrayDeque<>(getMaxEnqueuedPages(statement)); + numPagesRequested = protocolBackpressureAvailable ? getMaxEnqueuedPages(statement) : 0; cancelScheduledTasks(this); } @@ -1174,7 +1184,9 @@ private void enqueueOrCompletePending(@NonNull Object pageOrError) { // Backpressure without protocol support: if the queue grows too large, // disable auto-read so that the channel eventually becomes // non-writable on the server side (causing it to back off for a while) - if (!protocolBackpressureAvailable && queue.size() == getMaxEnqueuedPages() && state > 0) { + if (!protocolBackpressureAvailable + && queue.size() == getMaxEnqueuedPages(statement) + && state > 0) { LOG.trace( "[{}] Exceeded {} queued response pages, disabling auto-read", logPrefix, @@ -1207,7 +1219,7 @@ public CompletableFuture dequeueOrCreatePending() { head = queue.poll(); if (!protocolBackpressureAvailable && head != null - && queue.size() == getMaxEnqueuedPages() - 1) { + && queue.size() == getMaxEnqueuedPages(statement) - 1) { LOG.trace( "[{}] Back to {} queued response pages, re-enabling auto-read", logPrefix, @@ -1270,17 +1282,19 @@ private void maybeRequestMore() { return; } // if we have already requested more than the client needs, then no need to request some more - if (getMaxPages() > 0 && numPagesRequested >= getMaxPages()) { + int maxPages = getMaxPages(statement); + if (maxPages > 0 && numPagesRequested >= maxPages) { return; } // the pages received so far, which is the state minus one int received = state - 1; int requested = numPagesRequested; // the pages that fit in the queue, which is the queue free space minus the requests in flight - int freeSpace = getMaxEnqueuedPages() - queue.size(); + int freeSpace = getMaxEnqueuedPages(statement) - queue.size(); int inFlight = requested - received; int numPagesFittingInQueue = freeSpace - inFlight; - if (numPagesFittingInQueue > 0 && numPagesFittingInQueue >= getMaxEnqueuedPages() / 2) { + if (numPagesFittingInQueue > 0 + && numPagesFittingInQueue >= getMaxEnqueuedPages(statement) / 2) { LOG.trace("[{}] Requesting more {} pages", logPrefix, numPagesFittingInQueue); numPagesRequested = requested + numPagesFittingInQueue; sendMorePagesRequest(numPagesFittingInQueue); @@ -1305,7 +1319,7 @@ private void sendMorePagesRequest(int nextPages) { true, Revise.requestMoreContinuousPages(streamId, nextPages), statement.getCustomPayload(), - getReviseRequestTimeout(), + getReviseRequestTimeout(statement), throttler, session.getMetricUpdater(), logPrefix, @@ -1384,7 +1398,7 @@ private void sendCancelRequest() { true, Revise.cancelContinuousPaging(streamId), statement.getCustomPayload(), - getReviseRequestTimeout(), + getReviseRequestTimeout(statement), throttler, session.getMetricUpdater(), logPrefix, @@ -1428,7 +1442,7 @@ private void trackNodeError(@NonNull Node node, @NonNull Throwable error) { long latencyNanos = System.nanoTime() - this.messageStartTimeNanos; context .getRequestTracker() - .onNodeError(statement, error, latencyNanos, executionProfile, node, logPrefix); + .onNodeError(this.statement, error, latencyNanos, executionProfile, node, logPrefix); } } @@ -1490,19 +1504,19 @@ private void stopGlobalRequestTimer() { .getMetricUpdater() .updateTimer( continuousRequestsMetric, - executionProfile.getName(), + null, System.nanoTime() - startTimeNanos, TimeUnit.NANOSECONDS); } private void updateErrorMetrics( @NonNull NodeMetricUpdater metricUpdater, - @NonNull RetryDecision decision, + @NonNull RetryVerdict verdict, @NonNull DefaultNodeMetric error, @NonNull DefaultNodeMetric retriesOnError, @NonNull DefaultNodeMetric ignoresOnError) { metricUpdater.incrementCounter(error, executionProfile.getName()); - switch (decision) { + switch (verdict.getRetryDecision()) { case RETRY_SAME: case RETRY_NEXT: metricUpdater.incrementCounter(DefaultNodeMetric.RETRIES, executionProfile.getName()); @@ -1570,18 +1584,14 @@ private void completeResultSetFuture( } @NonNull - private ExecutionInfo createExecutionInfo( - @NonNull Node node, - @NonNull Result result, - @Nullable Frame response, - int successfulExecutionIndex) { + private ExecutionInfo createExecutionInfo(@NonNull Result result, @Nullable Frame response) { ByteBuffer pagingState = result instanceof Rows ? ((Rows) result).getMetadata().pagingState : null; return new DefaultExecutionInfo( statement, node, startedSpeculativeExecutionsCount.get(), - successfulExecutionIndex, + executionIndex, errors, pagingState, response, diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandler.java index 0e4d79f90d3..d792ed873c6 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandler.java @@ -24,9 +24,11 @@ import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousRequestHandlerBase; import com.datastax.dse.driver.internal.core.graph.binary.GraphBinaryModule; import com.datastax.dse.protocol.internal.response.result.DseRowsMetadata; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.ColumnDefinitions; import com.datastax.oss.driver.api.core.cql.ExecutionInfo; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.cql.Conversions; import com.datastax.oss.driver.internal.core.session.DefaultSession; import com.datastax.oss.driver.shaded.guava.common.base.MoreObjects; import com.datastax.oss.protocol.internal.Message; @@ -49,12 +51,9 @@ public class ContinuousGraphRequestHandler extends ContinuousRequestHandlerBase, AsyncGraphResultSet> { - private final Message message; - private final GraphProtocol subProtocol; private final GraphBinaryModule graphBinaryModule; + private final GraphSupportChecker graphSupportChecker; private final Duration globalTimeout; - private final int maxEnqueuedPages; - private final int maxPages; ContinuousGraphRequestHandler( @NonNull GraphStatement statement, @@ -74,17 +73,13 @@ public class ContinuousGraphRequestHandler DseSessionMetric.GRAPH_REQUESTS, DseNodeMetric.GRAPH_MESSAGES); this.graphBinaryModule = graphBinaryModule; - subProtocol = graphSupportChecker.inferGraphProtocol(statement, executionProfile, context); - message = - GraphConversions.createContinuousMessageFromGraphStatement( - statement, subProtocol, executionProfile, context, graphBinaryModule); + this.graphSupportChecker = graphSupportChecker; + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); globalTimeout = MoreObjects.firstNonNull( statement.getTimeout(), executionProfile.getDuration(DseDriverOption.GRAPH_TIMEOUT, Duration.ZERO)); - maxEnqueuedPages = - executionProfile.getInt(DseDriverOption.GRAPH_CONTINUOUS_PAGING_MAX_ENQUEUED_PAGES); - maxPages = executionProfile.getInt(DseDriverOption.GRAPH_CONTINUOUS_PAGING_MAX_PAGES); // NOTE that ordering of the following statement matters. // We should register this request after all fields have been initialized. throttler.register(this); @@ -98,40 +93,53 @@ protected Duration getGlobalTimeout() { @NonNull @Override - protected Duration getPageTimeout(int pageNumber) { + protected Duration getPageTimeout(@NonNull GraphStatement statement, int pageNumber) { return Duration.ZERO; } @NonNull @Override - protected Duration getReviseRequestTimeout() { + protected Duration getReviseRequestTimeout(@NonNull GraphStatement statement) { return Duration.ZERO; } @Override - protected int getMaxEnqueuedPages() { - return maxEnqueuedPages; + protected int getMaxEnqueuedPages(@NonNull GraphStatement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return executionProfile.getInt(DseDriverOption.GRAPH_CONTINUOUS_PAGING_MAX_ENQUEUED_PAGES); } @Override - protected int getMaxPages() { - return maxPages; + protected int getMaxPages(@NonNull GraphStatement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return executionProfile.getInt(DseDriverOption.GRAPH_CONTINUOUS_PAGING_MAX_PAGES); } @NonNull @Override - protected Message getMessage() { - return message; + protected Message getMessage(@NonNull GraphStatement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + GraphProtocol subProtocol = + graphSupportChecker.inferGraphProtocol(statement, executionProfile, context); + return GraphConversions.createContinuousMessageFromGraphStatement( + statement, subProtocol, executionProfile, context, graphBinaryModule); } @Override - protected boolean isTracingEnabled() { + protected boolean isTracingEnabled(@NonNull GraphStatement statement) { return statement.isTracing(); } @NonNull @Override - protected Map createPayload() { + protected Map createPayload(@NonNull GraphStatement statement) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + GraphProtocol subProtocol = + graphSupportChecker.inferGraphProtocol(statement, executionProfile, context); return GraphConversions.createCustomPayload( statement, subProtocol, executionProfile, context, graphBinaryModule); } @@ -145,10 +153,15 @@ protected AsyncGraphResultSet createEmptyResultSet(@NonNull ExecutionInfo execut @NonNull @Override protected ContinuousAsyncGraphResultSet createResultSet( + @NonNull GraphStatement statement, @NonNull Rows rows, @NonNull ExecutionInfo executionInfo, @NonNull ColumnDefinitions columnDefinitions) throws IOException { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + GraphProtocol subProtocol = + graphSupportChecker.inferGraphProtocol(statement, executionProfile, context); Queue graphNodes = new ArrayDeque<>(); for (List row : rows.getData()) { diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java index 7af7160baa1..53f8e98b0ee 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java @@ -384,4 +384,21 @@ public static GraphNode createGraphBinaryGraphNode( : "Graph protocol error. Received object should be a Traverser but it is not."; return new ObjectGraphNode(deserializedObject); } + + public static Duration resolveGraphRequestTimeout( + GraphStatement statement, InternalDriverContext context) { + DriverExecutionProfile executionProfile = resolveExecutionProfile(statement, context); + return statement.getTimeout() != null + ? statement.getTimeout() + : executionProfile.getDuration(DseDriverOption.GRAPH_TIMEOUT); + } + + public static GraphProtocol resolveGraphSubProtocol( + GraphStatement statement, + GraphSupportChecker graphSupportChecker, + InternalDriverContext context) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + return graphSupportChecker.inferGraphProtocol(statement, executionProfile, context); + } } diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java index 46dbaa88768..b193805a2c6 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java @@ -15,7 +15,6 @@ */ package com.datastax.dse.driver.internal.core.graph; -import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.api.core.graph.AsyncGraphResultSet; import com.datastax.dse.driver.api.core.graph.GraphNode; import com.datastax.dse.driver.api.core.graph.GraphStatement; @@ -33,8 +32,8 @@ import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; -import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; import com.datastax.oss.driver.api.core.servererrors.FunctionFailureException; @@ -45,7 +44,6 @@ import com.datastax.oss.driver.api.core.servererrors.WriteTimeoutException; import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.api.core.session.throttling.Throttled; -import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.internal.core.channel.DriverChannel; import com.datastax.oss.driver.internal.core.channel.ResponseCallback; @@ -99,15 +97,11 @@ public class GraphRequestHandler implements Throttled { private final long startTimeNanos; private final String logPrefix; - private final GraphStatement statement; + private final GraphStatement initialStatement; private final DefaultSession session; private final InternalDriverContext context; - private final DriverExecutionProfile executionProfile; - private final boolean isIdempotent; protected final CompletableFuture result; - private final Message message; private final Timer timer; - private final GraphProtocol subProtocol; /** * How many speculative executions are currently running (including the initial execution). We @@ -126,13 +120,11 @@ public class GraphRequestHandler implements Throttled { private final Timeout scheduledTimeout; private final List scheduledExecutions; private final List inFlightCallbacks; - private final RetryPolicy retryPolicy; - private final SpeculativeExecutionPolicy speculativeExecutionPolicy; private final RequestThrottler throttler; private final RequestTracker requestTracker; private final SessionMetricUpdater sessionMetricUpdater; - private final Map queryCustomPayload; private final GraphBinaryModule graphBinaryModule; + private final GraphSupportChecker graphSupportChecker; // The errors on the nodes that were already tried (lazily initialized on the first error). // We don't use a map because nodes can appear multiple times. @@ -148,18 +140,10 @@ public class GraphRequestHandler implements Throttled { this.startTimeNanos = System.nanoTime(); this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); LOG.trace("[{}] Creating new Graph request handler for request {}", logPrefix, statement); - this.statement = statement; + this.initialStatement = statement; this.session = dseSession; this.context = context; - this.executionProfile = GraphConversions.resolveExecutionProfile(this.statement, this.context); - this.retryPolicy = context.getRetryPolicy(executionProfile.getName()); - this.speculativeExecutionPolicy = - context.getSpeculativeExecutionPolicy(executionProfile.getName()); - Boolean statementIsIdempotent = statement.isIdempotent(); - this.isIdempotent = - (statementIsIdempotent == null) - ? executionProfile.getBoolean(DefaultDriverOption.REQUEST_DEFAULT_IDEMPOTENCE) - : statementIsIdempotent; + this.graphSupportChecker = graphSupportChecker; this.result = new CompletableFuture<>(); this.result.exceptionally( t -> { @@ -173,37 +157,27 @@ public class GraphRequestHandler implements Throttled { return null; }); this.graphBinaryModule = graphBinaryModule; - this.subProtocol = - graphSupportChecker.inferGraphProtocol(this.statement, executionProfile, this.context); - LOG.debug("[{}], Graph protocol used for query: {}", logPrefix, subProtocol); - this.message = - GraphConversions.createMessageFromGraphStatement( - this.statement, subProtocol, executionProfile, this.context, this.graphBinaryModule); this.timer = context.getNettyOptions().getTimer(); - Duration timeout = - statement.getTimeout() != null - ? statement.getTimeout() - : executionProfile.getDuration(DseDriverOption.GRAPH_TIMEOUT, null); - this.scheduledTimeout = scheduleTimeout(timeout); this.activeExecutionsCount = new AtomicInteger(1); this.startedSpeculativeExecutionsCount = new AtomicInteger(0); - this.scheduledExecutions = isIdempotent ? new CopyOnWriteArrayList<>() : null; + this.scheduledExecutions = new CopyOnWriteArrayList<>(); this.inFlightCallbacks = new CopyOnWriteArrayList<>(); - this.queryCustomPayload = - GraphConversions.createCustomPayload( - this.statement, subProtocol, executionProfile, this.context, this.graphBinaryModule); - this.requestTracker = context.getRequestTracker(); this.sessionMetricUpdater = session.getMetricUpdater(); + Duration timeout = GraphConversions.resolveGraphRequestTimeout(statement, context); + this.scheduledTimeout = scheduleTimeout(timeout); + this.throttler = context.getRequestThrottler(); this.throttler.register(this); } @Override public void onThrottleReady(boolean wasDelayed) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialStatement, context); if (wasDelayed // avoid call to nanoTime() if metric is disabled: && sessionMetricUpdater.isEnabled( @@ -215,12 +189,12 @@ public void onThrottleReady(boolean wasDelayed) { TimeUnit.NANOSECONDS); } Queue queryPlan = - statement.getNode() != null - ? new QueryPlan(statement.getNode()) + initialStatement.getNode() != null + ? new QueryPlan(initialStatement.getNode()) : context .getLoadBalancingPolicyWrapper() - .newQueryPlan(statement, executionProfile.getName(), session); - sendRequest(null, queryPlan, 0, 0, true); + .newQueryPlan(initialStatement, executionProfile.getName(), session); + sendRequest(initialStatement, null, queryPlan, 0, 0, true); } public CompletionStage handle() { @@ -233,6 +207,7 @@ private Timeout scheduleTimeout(Duration timeoutDuration) { return this.timer.newTimeout( (Timeout timeout1) -> setFinalError( + initialStatement, new DriverTimeoutException("Query timed out after " + timeoutDuration), null, NO_SUCCESSFUL_EXECUTION), @@ -262,6 +237,7 @@ private Timeout scheduleTimeout(Duration timeoutDuration) { * @param scheduleNextExecution whether to schedule the next speculative execution */ private void sendRequest( + GraphStatement statement, Node retriedNode, Queue queryPlan, int currentExecutionIndex, @@ -285,11 +261,15 @@ private void sendRequest( if (!result.isDone() && activeExecutionsCount.decrementAndGet() == 0) { // We're the last execution so fail the result setFinalError( - AllNodesFailedException.fromErrors(this.errors), null, NO_SUCCESSFUL_EXECUTION); + statement, + AllNodesFailedException.fromErrors(this.errors), + null, + NO_SUCCESSFUL_EXECUTION); } } else { NodeResponseCallback nodeResponseCallback = new NodeResponseCallback( + statement, node, queryPlan, channel, @@ -297,8 +277,18 @@ private void sendRequest( retryCount, scheduleNextExecution, logPrefix); + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + GraphProtocol graphSubProtocol = + GraphConversions.resolveGraphSubProtocol(statement, graphSupportChecker, context); + Message message = + GraphConversions.createMessageFromGraphStatement( + statement, graphSubProtocol, executionProfile, context, graphBinaryModule); + Map customPayload = + GraphConversions.createCustomPayload( + statement, graphSubProtocol, executionProfile, context, graphBinaryModule); channel - .write(message, statement.isTracing(), queryCustomPayload, nodeResponseCallback) + .write(message, statement.isTracing(), customPayload, nodeResponseCallback) .addListener(nodeResponseCallback); } } @@ -335,7 +325,11 @@ private void setFinalResult( Result resultMessage, Frame responseFrame, NodeResponseCallback callback) { try { ExecutionInfo executionInfo = buildExecutionInfo(callback, responseFrame); - + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(callback.statement, context); + GraphProtocol subProtocol = + GraphConversions.resolveGraphSubProtocol( + callback.statement, graphSupportChecker, context); Queue graphNodes = new ArrayDeque<>(); for (List row : ((Rows) resultMessage).getData()) { if (subProtocol.isGraphBinary()) { @@ -361,9 +355,9 @@ private void setFinalResult( totalLatencyNanos = completionTimeNanos - startTimeNanos; long nodeLatencyNanos = completionTimeNanos - callback.nodeStartTimeNanos; requestTracker.onNodeSuccess( - statement, nodeLatencyNanos, executionProfile, callback.node, logPrefix); + callback.statement, nodeLatencyNanos, executionProfile, callback.node, logPrefix); requestTracker.onSuccess( - statement, totalLatencyNanos, executionProfile, callback.node, logPrefix); + callback.statement, totalLatencyNanos, executionProfile, callback.node, logPrefix); } if (sessionMetricUpdater.isEnabled( DseSessionMetric.GRAPH_REQUESTS, executionProfile.getName())) { @@ -382,14 +376,16 @@ private void setFinalResult( if (!executionInfo.getWarnings().isEmpty() && executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOG_WARNINGS) && LOG.isWarnEnabled()) { - logServerWarnings(executionInfo.getWarnings()); + logServerWarnings(callback.statement, executionInfo.getWarnings()); } } catch (Throwable error) { - setFinalError(error, callback.node, NO_SUCCESSFUL_EXECUTION); + setFinalError(callback.statement, error, callback.node, NO_SUCCESSFUL_EXECUTION); } } - private void logServerWarnings(List warnings) { + private void logServerWarnings(GraphStatement statement, List warnings) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); // use the RequestLogFormatter to format the query StringBuilder statementString = new StringBuilder(); context @@ -416,8 +412,10 @@ private void logServerWarnings(List warnings) { } private ExecutionInfo buildExecutionInfo(NodeResponseCallback callback, Frame responseFrame) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(callback.statement, context); return new DefaultExecutionInfo( - statement, + callback.statement, callback.node, startedSpeculativeExecutionsCount.get(), callback.execution, @@ -432,12 +430,17 @@ private ExecutionInfo buildExecutionInfo(NodeResponseCallback callback, Frame re @Override public void onThrottleFailure(@NonNull RequestThrottlingException error) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialStatement, context); sessionMetricUpdater.incrementCounter( DefaultSessionMetric.THROTTLING_ERRORS, executionProfile.getName()); - setFinalError(error, null, NO_SUCCESSFUL_EXECUTION); + setFinalError(initialStatement, error, null, NO_SUCCESSFUL_EXECUTION); } - private void setFinalError(Throwable error, Node node, int execution) { + private void setFinalError( + GraphStatement statement, Throwable error, Node node, int execution) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); if (error instanceof DriverException) { ((DriverException) error) .setExecutionInfo( @@ -479,6 +482,7 @@ private class NodeResponseCallback implements ResponseCallback, GenericFutureListener> { private final long nodeStartTimeNanos = System.nanoTime(); + private final GraphStatement statement; private final Node node; private final Queue queryPlan; private final DriverChannel channel; @@ -490,8 +494,10 @@ private class NodeResponseCallback private final int retryCount; private final boolean scheduleNextExecution; private final String logPrefix; + private final DriverExecutionProfile executionProfile; private NodeResponseCallback( + GraphStatement statement, Node node, Queue queryPlan, DriverChannel channel, @@ -499,6 +505,7 @@ private NodeResponseCallback( int retryCount, boolean scheduleNextExecution, String logPrefix) { + this.statement = statement; this.node = node; this.queryPlan = queryPlan; this.channel = channel; @@ -506,6 +513,7 @@ private NodeResponseCallback( this.retryCount = retryCount; this.scheduleNextExecution = scheduleNextExecution; this.logPrefix = logPrefix + "|" + execution; + this.executionProfile = Conversions.resolveExecutionProfile(statement, context); } // this gets invoked once the write completes. @@ -516,7 +524,7 @@ public void operationComplete(Future future) { if (error instanceof EncoderException && error.getCause() instanceof FrameTooLongException) { trackNodeError(node, error.getCause(), NANOTIME_NOT_MEASURED_YET); - setFinalError(error.getCause(), node, execution); + setFinalError(statement, error.getCause(), node, execution); } else { LOG.trace( "[{}] Failed to send request on {}, trying next node (cause: {})", @@ -529,7 +537,12 @@ public void operationComplete(Future future) { .getMetricUpdater() .incrementCounter(DefaultNodeMetric.UNSENT_REQUESTS, executionProfile.getName()); sendRequest( - null, queryPlan, execution, retryCount, scheduleNextExecution); // try next node + statement, + null, + queryPlan, + execution, + retryCount, + scheduleNextExecution); // try next node } } else { LOG.trace("[{}] Request sent on {}", logPrefix, channel); @@ -539,12 +552,13 @@ public void operationComplete(Future future) { cancel(); } else { inFlightCallbacks.add(this); - if (scheduleNextExecution && isIdempotent) { + if (scheduleNextExecution && Conversions.resolveIdempotence(statement, context)) { int nextExecution = execution + 1; long nextDelay; try { nextDelay = - speculativeExecutionPolicy.nextExecution(node, null, statement, nextExecution); + Conversions.resolveSpeculativeExecutionPolicy(statement, context) + .nextExecution(node, null, statement, nextExecution); } catch (Throwable cause) { // This is a bug in the policy, but not fatal since we have at least one other // execution already running. Don't fail the whole request. @@ -586,7 +600,7 @@ private void scheduleSpeculativeExecution(int index, long delay) { .getMetricUpdater() .incrementCounter( DefaultNodeMetric.SPECULATIVE_EXECUTIONS, executionProfile.getName()); - sendRequest(null, queryPlan, index, 0, true); + sendRequest(statement, null, queryPlan, index, 0, true); } }, delay, @@ -632,11 +646,14 @@ public void onResponse(Frame responseFrame) { new IllegalStateException("Unexpected response " + responseMessage), nodeResponseTimeNanos); setFinalError( - new IllegalStateException("Unexpected response " + responseMessage), node, execution); + statement, + new IllegalStateException("Unexpected response " + responseMessage), + node, + execution); } } catch (Throwable t) { trackNodeError(node, t, nodeResponseTimeNanos); - setFinalError(t, node, execution); + setFinalError(statement, t, node, execution); } } @@ -647,20 +664,21 @@ private void processErrorResponse(Error errorMessage) { LOG.trace("[{}] {} is bootstrapping, trying next node", logPrefix, node); recordError(node, error); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - sendRequest(null, queryPlan, execution, retryCount, false); + sendRequest(statement, null, queryPlan, execution, retryCount, false); } else if (error instanceof QueryValidationException || error instanceof FunctionFailureException || error instanceof ProtocolError) { LOG.trace("[{}] Unrecoverable error, rethrowing", logPrefix); metricUpdater.incrementCounter(DefaultNodeMetric.OTHER_ERRORS, executionProfile.getName()); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - setFinalError(error, node, execution); + setFinalError(statement, error, node, execution); } else { - RetryDecision decision; + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryVerdict verdict; if (error instanceof ReadTimeoutException) { ReadTimeoutException readTimeout = (ReadTimeoutException) error; - decision = - retryPolicy.onReadTimeout( + verdict = + retryPolicy.onReadTimeoutVerdict( statement, readTimeout.getConsistencyLevel(), readTimeout.getBlockFor(), @@ -669,32 +687,32 @@ private void processErrorResponse(Error errorMessage) { retryCount); updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.READ_TIMEOUTS, DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT); } else if (error instanceof WriteTimeoutException) { WriteTimeoutException writeTimeout = (WriteTimeoutException) error; - decision = - isIdempotent - ? retryPolicy.onWriteTimeout( + verdict = + Conversions.resolveIdempotence(statement, context) + ? retryPolicy.onWriteTimeoutVerdict( statement, writeTimeout.getConsistencyLevel(), writeTimeout.getWriteType(), writeTimeout.getBlockFor(), writeTimeout.getReceived(), retryCount) - : RetryDecision.RETHROW; + : RetryVerdict.RETHROW; updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.WRITE_TIMEOUTS, DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT); } else if (error instanceof UnavailableException) { UnavailableException unavailable = (UnavailableException) error; - decision = - retryPolicy.onUnavailable( + verdict = + retryPolicy.onUnavailableVerdict( statement, unavailable.getConsistencyLevel(), unavailable.getRequired(), @@ -702,42 +720,54 @@ private void processErrorResponse(Error errorMessage) { retryCount); updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.UNAVAILABLES, DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, DefaultNodeMetric.IGNORES_ON_UNAVAILABLE); } else { - decision = - isIdempotent - ? retryPolicy.onErrorResponse(statement, error, retryCount) - : RetryDecision.RETHROW; + verdict = + Conversions.resolveIdempotence(statement, context) + ? retryPolicy.onErrorResponseVerdict(statement, error, retryCount) + : RetryVerdict.RETHROW; updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.OTHER_ERRORS, DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, DefaultNodeMetric.IGNORES_ON_OTHER_ERROR); } - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); } } - private void processRetryDecision(RetryDecision decision, Throwable error) { - LOG.trace("[{}] Processing retry decision {}", logPrefix, decision); - switch (decision) { + private void processRetryVerdict(RetryVerdict verdict, Throwable error) { + LOG.trace("[{}] Processing retry decision {}", logPrefix, verdict); + switch (verdict.getRetryDecision()) { case RETRY_SAME: recordError(node, error); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - sendRequest(node, queryPlan, execution, retryCount + 1, false); + sendRequest( + verdict.getRetryRequest(statement), + node, + queryPlan, + execution, + retryCount + 1, + false); break; case RETRY_NEXT: recordError(node, error); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - sendRequest(null, queryPlan, execution, retryCount + 1, false); + sendRequest( + verdict.getRetryRequest(statement), + null, + queryPlan, + execution, + retryCount + 1, + false); break; case RETHROW: trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - setFinalError(error, node, execution); + setFinalError(statement, error, node, execution); break; case IGNORE: setFinalResult(Void.INSTANCE, null, this); @@ -747,12 +777,12 @@ private void processRetryDecision(RetryDecision decision, Throwable error) { private void updateErrorMetrics( NodeMetricUpdater metricUpdater, - RetryDecision decision, + RetryVerdict verdict, DefaultNodeMetric error, DefaultNodeMetric retriesOnError, DefaultNodeMetric ignoresOnError) { metricUpdater.incrementCounter(error, executionProfile.getName()); - switch (decision) { + switch (verdict.getRetryDecision()) { case RETRY_SAME: case RETRY_NEXT: metricUpdater.incrementCounter(DefaultNodeMetric.RETRIES, executionProfile.getName()); @@ -774,24 +804,27 @@ public void onFailure(Throwable error) { return; } LOG.trace("[{}] Request failure, processing: {}", logPrefix, error); - RetryDecision decision; - if (!isIdempotent || error instanceof FrameTooLongException) { - decision = RetryDecision.RETHROW; + RetryVerdict verdict; + if (!Conversions.resolveIdempotence(statement, context) + || error instanceof FrameTooLongException) { + verdict = RetryVerdict.RETHROW; } else { try { - decision = retryPolicy.onRequestAborted(statement, error, retryCount); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + verdict = retryPolicy.onRequestAbortedVerdict(statement, error, retryCount); } catch (Throwable cause) { setFinalError( + statement, new IllegalStateException("Unexpected error while invoking the retry policy", cause), node, NO_SUCCESSFUL_EXECUTION); return; } } - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); updateErrorMetrics( ((DefaultNode) node).getMetricUpdater(), - decision, + verdict, DefaultNodeMetric.ABORTED_REQUESTS, DefaultNodeMetric.RETRIES_ON_ABORTED, DefaultNodeMetric.IGNORES_ON_ABORTED); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryDecision.java b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryDecision.java index 8859cdd6e4f..77daed28d93 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryDecision.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryDecision.java @@ -15,7 +15,11 @@ */ package com.datastax.oss.driver.api.core.retry; -/** A decision from the {@link RetryPolicy} on how to handle a retry. */ +/** + * A decision from the {@link RetryPolicy} on how to handle a retry. + * + * @see RetryVerdict#getRetryDecision() + */ public enum RetryDecision { /** Retry the operation on the same node. */ RETRY_SAME, diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java index e36658c9d8e..99df4ca26f9 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java @@ -64,7 +64,10 @@ public interface RetryPolicy extends AutoCloseable { * {@link ReadTimeoutException#wasDataPresent()}. * @param retryCount how many times the retry policy has been invoked already for this request * (not counting the current invocation). + * @deprecated As of version 4.10, use {@link #onReadTimeoutVerdict(Request, ConsistencyLevel, + * int, int, boolean, int)} instead. */ + @Deprecated RetryDecision onReadTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -73,6 +76,34 @@ RetryDecision onReadTimeout( boolean dataPresent, int retryCount); + /** + * Whether to retry when the server replied with a {@code READ_TIMEOUT} error; this indicates a + * server-side timeout during a read query, i.e. some replicas did not reply to the + * coordinator in time. + * + * @param request the request that timed out. + * @param cl the requested consistency level. + * @param blockFor the minimum number of replica acknowledgements/responses that were required to + * fulfill the operation. + * @param received the number of replica that had acknowledged/responded to the operation before + * it failed. + * @param dataPresent whether the actual data was amongst the received replica responses. See + * {@link ReadTimeoutException#wasDataPresent()}. + * @param retryCount how many times the retry policy has been invoked already for this request + * (not counting the current invocation). + */ + default RetryVerdict onReadTimeoutVerdict( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + int blockFor, + int received, + boolean dataPresent, + int retryCount) { + RetryDecision decision = + onReadTimeout(request, cl, blockFor, received, dataPresent, retryCount); + return () -> decision; + } + /** * Whether to retry when the server replied with a {@code WRITE_TIMEOUT} error; this indicates a * server-side timeout during a write query, i.e. some replicas did not reply to the @@ -92,7 +123,10 @@ RetryDecision onReadTimeout( * it failed. * @param retryCount how many times the retry policy has been invoked already for this request * (not counting the current invocation). + * @deprecated As of version 4.10, use {@link #onWriteTimeoutVerdict(Request, ConsistencyLevel, + * WriteType, int, int, int)} instead. */ + @Deprecated RetryDecision onWriteTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -101,6 +135,37 @@ RetryDecision onWriteTimeout( int received, int retryCount); + /** + * Whether to retry when the server replied with a {@code WRITE_TIMEOUT} error; this indicates a + * server-side timeout during a write query, i.e. some replicas did not reply to the + * coordinator in time. + * + *

    Note that this method will only be invoked for {@link Request#isIdempotent()} idempotent} + * requests: when a write times out, it is impossible to determine with 100% certainty whether the + * mutation was applied or not, so the write is never safe to retry; the driver will rethrow the + * error directly, without invoking the retry policy. + * + * @param request the request that timed out. + * @param cl the requested consistency level. + * @param writeType the type of the write for which the timeout was raised. + * @param blockFor the minimum number of replica acknowledgements/responses that were required to + * fulfill the operation. + * @param received the number of replica that had acknowledged/responded to the operation before + * it failed. + * @param retryCount how many times the retry policy has been invoked already for this request + * (not counting the current invocation). + */ + default RetryVerdict onWriteTimeoutVerdict( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + @NonNull WriteType writeType, + int blockFor, + int received, + int retryCount) { + RetryDecision decision = onWriteTimeout(request, cl, writeType, blockFor, received, retryCount); + return () -> decision; + } + /** * Whether to retry when the server replied with an {@code UNAVAILABLE} error; this indicates that * the coordinator determined that there were not enough replicas alive to perform a query with @@ -114,7 +179,10 @@ RetryDecision onWriteTimeout( * tried to execute the operation. * @param retryCount how many times the retry policy has been invoked already for this request * (not counting the current invocation). + * @deprecated As of version 4.10, use {@link #onUnavailableVerdict(Request, ConsistencyLevel, + * int, int, int)} instead. */ + @Deprecated RetryDecision onUnavailable( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -122,6 +190,30 @@ RetryDecision onUnavailable( int alive, int retryCount); + /** + * Whether to retry when the server replied with an {@code UNAVAILABLE} error; this indicates that + * the coordinator determined that there were not enough replicas alive to perform a query with + * the requested consistency level. + * + * @param request the request that timed out. + * @param cl the requested consistency level. + * @param required the number of replica acknowledgements/responses required to perform the + * operation (with its required consistency level). + * @param alive the number of replicas that were known to be alive by the coordinator node when it + * tried to execute the operation. + * @param retryCount how many times the retry policy has been invoked already for this request + * (not counting the current invocation). + */ + default RetryVerdict onUnavailableVerdict( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + int required, + int alive, + int retryCount) { + RetryDecision decision = onUnavailable(request, cl, required, alive, retryCount); + return () -> decision; + } + /** * Whether to retry when a request was aborted before we could get a response from the server. * @@ -139,10 +231,37 @@ RetryDecision onUnavailable( * @param error the error. * @param retryCount how many times the retry policy has been invoked already for this request * (not counting the current invocation). + * @deprecated As of version 4.10, use {@link #onRequestAbortedVerdict(Request, Throwable, int)} + * instead. */ + @Deprecated RetryDecision onRequestAborted( @NonNull Request request, @NonNull Throwable error, int retryCount); + /** + * Whether to retry when a request was aborted before we could get a response from the server. + * + *

    This can happen in two cases: if the connection was closed due to an external event (this + * will manifest as a {@link ClosedConnectionException}, or {@link HeartbeatException} for a + * heartbeat failure); or if there was an unexpected error while decoding the response (this can + * only be a driver bug). + * + *

    Note that this method will only be invoked for {@linkplain Request#isIdempotent() + * idempotent} requests: when execution was aborted before getting a response, it is impossible to + * determine with 100% certainty whether a mutation was applied or not, so a write is never safe + * to retry; the driver will rethrow the error directly, without invoking the retry policy. + * + * @param request the request that was aborted. + * @param error the error. + * @param retryCount how many times the retry policy has been invoked already for this request + * (not counting the current invocation). + */ + default RetryVerdict onRequestAbortedVerdict( + @NonNull Request request, @NonNull Throwable error, int retryCount) { + RetryDecision decision = onRequestAborted(request, error, retryCount); + return () -> decision; + } + /** * Whether to retry when the server replied with a recoverable error (other than {@code * READ_TIMEOUT}, {@code WRITE_TIMEOUT} or {@code UNAVAILABLE}). @@ -168,10 +287,45 @@ RetryDecision onRequestAborted( * @param error the error. * @param retryCount how many times the retry policy has been invoked already for this request * (not counting the current invocation). + * @deprecated As of version 4.10, use {@link #onErrorResponseVerdict(Request, + * CoordinatorException, int)} instead. */ + @Deprecated RetryDecision onErrorResponse( @NonNull Request request, @NonNull CoordinatorException error, int retryCount); + /** + * Whether to retry when the server replied with a recoverable error (other than {@code + * READ_TIMEOUT}, {@code WRITE_TIMEOUT} or {@code UNAVAILABLE}). + * + *

    This can happen for the following errors: {@link OverloadedException}, {@link ServerError}, + * {@link TruncateException}, {@link ReadFailureException}, {@link WriteFailureException}. + * + *

    The following errors are handled internally by the driver, and therefore will never + * be encountered in this method: + * + *

      + *
    • {@link BootstrappingException}: always retried on the next node; + *
    • {@link QueryValidationException} (and its subclasses), {@link FunctionFailureException} + * and {@link ProtocolError}: always rethrown. + *
    + * + *

    Note that this method will only be invoked for {@link Request#isIdempotent()} idempotent} + * requests: when execution was aborted before getting a response, it is impossible to determine + * with 100% certainty whether a mutation was applied or not, so a write is never safe to retry; + * the driver will rethrow the error directly, without invoking the retry policy. + * + * @param request the request that failed. + * @param error the error. + * @param retryCount how many times the retry policy has been invoked already for this request + * (not counting the current invocation). + */ + default RetryVerdict onErrorResponseVerdict( + @NonNull Request request, @NonNull CoordinatorException error, int retryCount) { + RetryDecision decision = onErrorResponse(request, error, retryCount); + return () -> decision; + } + /** Called when the cluster that this policy is associated with closes. */ @Override void close(); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java new file mode 100644 index 00000000000..735019aa80f --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java @@ -0,0 +1,60 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.retry; + +import com.datastax.oss.driver.api.core.session.Request; +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * The verdict returned by a {@link RetryPolicy} determining what to do when a request failed. A + * verdict contains a {@link RetryDecision} indicating if a retry should be attempted at all and + * where, and a method that allows the original request to be modified before the retry. + */ +@FunctionalInterface +public interface RetryVerdict { + + /** A retry verdict that retries the same request on the same node. */ + RetryVerdict RETRY_SAME = () -> RetryDecision.RETRY_SAME; + + /** A retry verdict that retries the same request on the next node in the query plan. */ + RetryVerdict RETRY_NEXT = () -> RetryDecision.RETRY_NEXT; + + /** A retry verdict that ignores the error, returning and empty result set to the caller. */ + RetryVerdict IGNORE = () -> RetryDecision.IGNORE; + + /** A retry verdict that rethrows the execution error to the calling code. */ + RetryVerdict RETHROW = () -> RetryDecision.RETHROW; + + /** @return The retry decision to apply. */ + @NonNull + RetryDecision getRetryDecision(); + + /** + * Returns the request to retry, based on the request that was just executed (and failed). + * + *

    The default retry policy always returns the request as is. Custom retry policies can use + * this method to customize the request to retry, for example, by changing its consistency level, + * query timestamp, custom payload, or even its execution profile. + * + * @param The actual type of the request. + * @param previous The request that was just executed (and failed). + * @return The request to retry. + */ + @NonNull + default RequestT getRetryRequest(@NonNull RequestT previous) { + return previous; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java index 2dc6e5ddc46..242bf673a7a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java @@ -37,6 +37,7 @@ import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata; import com.datastax.oss.driver.api.core.metadata.schema.RelationMetadata; +import com.datastax.oss.driver.api.core.retry.RetryPolicy; import com.datastax.oss.driver.api.core.servererrors.AlreadyExistsException; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; @@ -55,6 +56,7 @@ import com.datastax.oss.driver.api.core.servererrors.WriteFailureException; import com.datastax.oss.driver.api.core.servererrors.WriteTimeoutException; import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.DefaultProtocolFeature; @@ -86,6 +88,7 @@ import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableList; import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; import java.nio.ByteBuffer; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -517,4 +520,30 @@ public static CoordinatorException toThrowable( return new ProtocolError(node, "Unknown error code: " + errorMessage.code); } } + + public static boolean resolveIdempotence(Request request, InternalDriverContext context) { + Boolean requestIsIdempotent = request.isIdempotent(); + DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); + return (requestIsIdempotent == null) + ? executionProfile.getBoolean(DefaultDriverOption.REQUEST_DEFAULT_IDEMPOTENCE) + : requestIsIdempotent; + } + + public static Duration resolveRequestTimeout(Request request, InternalDriverContext context) { + DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); + return request.getTimeout() != null + ? request.getTimeout() + : executionProfile.getDuration(DefaultDriverOption.REQUEST_TIMEOUT); + } + + public static RetryPolicy resolveRetryPolicy(Request request, InternalDriverContext context) { + DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); + return context.getRetryPolicy(executionProfile.getName()); + } + + public static SpeculativeExecutionPolicy resolveSpeculativeExecutionPolicy( + Request request, InternalDriverContext context) { + DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); + return context.getSpeculativeExecutionPolicy(executionProfile.getName()); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java index 33ce8de23ee..d60a6c65260 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java @@ -28,6 +28,7 @@ import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; import com.datastax.oss.driver.api.core.servererrors.FunctionFailureException; @@ -79,17 +80,13 @@ public class CqlPrepareHandler implements Throttled { private final long startTimeNanos; private final String logPrefix; - private final PrepareRequest request; + private final PrepareRequest initialRequest; private final DefaultSession session; private final InternalDriverContext context; - private final DriverExecutionProfile executionProfile; private final Queue queryPlan; protected final CompletableFuture result; - private final Message message; private final Timer timer; - private final Duration timeout; private final Timeout scheduledTimeout; - private final RetryPolicy retryPolicy; private final RequestThrottler throttler; private final Boolean prepareOnAllNodes; private volatile InitialPrepareCallback initialCallback; @@ -108,15 +105,14 @@ protected CqlPrepareHandler( this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); LOG.trace("[{}] Creating new handler for prepare request {}", logPrefix, request); - this.request = request; + this.initialRequest = request; this.session = session; this.context = context; - this.executionProfile = Conversions.resolveExecutionProfile(request, context); + DriverExecutionProfile executionProfile = Conversions.resolveExecutionProfile(request, context); this.queryPlan = context .getLoadBalancingPolicyWrapper() .newQueryPlan(request, executionProfile.getName(), session); - this.retryPolicy = context.getRetryPolicy(executionProfile.getName()); this.result = new CompletableFuture<>(); this.result.exceptionally( @@ -130,22 +126,9 @@ protected CqlPrepareHandler( } return null; }); - ProtocolVersion protocolVersion = context.getProtocolVersion(); - ProtocolVersionRegistry registry = context.getProtocolVersionRegistry(); - CqlIdentifier keyspace = request.getKeyspace(); - if (keyspace != null - && !registry.supports(protocolVersion, DefaultProtocolFeature.PER_REQUEST_KEYSPACE)) { - throw new IllegalArgumentException( - "Can't use per-request keyspace with protocol " + protocolVersion); - } - this.message = - new Prepare(request.getQuery(), (keyspace == null) ? null : keyspace.asInternal()); this.timer = context.getNettyOptions().getTimer(); - this.timeout = - request.getTimeout() != null - ? request.getTimeout() - : executionProfile.getDuration(DefaultDriverOption.REQUEST_TIMEOUT); + Duration timeout = Conversions.resolveRequestTimeout(request, context); this.scheduledTimeout = scheduleTimeout(timeout); this.prepareOnAllNodes = executionProfile.getBoolean(DefaultDriverOption.PREPARE_ON_ALL_NODES); @@ -155,6 +138,8 @@ protected CqlPrepareHandler( @Override public void onThrottleReady(boolean wasDelayed) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialRequest, context); if (wasDelayed) { session .getMetricUpdater() @@ -164,7 +149,7 @@ public void onThrottleReady(boolean wasDelayed) { System.nanoTime() - startTimeNanos, TimeUnit.NANOSECONDS); } - sendRequest(null, 0); + sendRequest(initialRequest, null, 0); } public CompletableFuture handle() { @@ -193,7 +178,7 @@ private void cancelTimeout() { } } - private void sendRequest(Node node, int retryCount) { + private void sendRequest(PrepareRequest request, Node node, int retryCount) { if (result.isDone()) { return; } @@ -210,13 +195,29 @@ private void sendRequest(Node node, int retryCount) { setFinalError(AllNodesFailedException.fromErrors(this.errors)); } else { InitialPrepareCallback initialPrepareCallback = - new InitialPrepareCallback(node, channel, retryCount); + new InitialPrepareCallback(request, node, channel, retryCount); + + Prepare message = toPrepareMessage(request); + channel .write(message, false, request.getCustomPayload(), initialPrepareCallback) .addListener(initialPrepareCallback); } } + @NonNull + private Prepare toPrepareMessage(PrepareRequest request) { + ProtocolVersion protocolVersion = context.getProtocolVersion(); + ProtocolVersionRegistry registry = context.getProtocolVersionRegistry(); + CqlIdentifier keyspace = request.getKeyspace(); + if (keyspace != null + && !registry.supports(protocolVersion, DefaultProtocolFeature.PER_REQUEST_KEYSPACE)) { + throw new IllegalArgumentException( + "Can't use per-request keyspace with protocol " + protocolVersion); + } + return new Prepare(request.getQuery(), (keyspace == null) ? null : keyspace.asInternal()); + } + private void recordError(Node node, Throwable error) { // Use a local variable to do only a single single volatile read in the nominal case List> errorsSnapshot = this.errors; @@ -231,19 +232,19 @@ private void recordError(Node node, Throwable error) { errorsSnapshot.add(new AbstractMap.SimpleEntry<>(node, error)); } - private void setFinalResult(Prepared prepared) { + private void setFinalResult(PrepareRequest request, Prepared response) { // Whatever happens below, we're done with this stream id throttler.signalSuccess(this); DefaultPreparedStatement preparedStatement = - Conversions.toPreparedStatement(prepared, request, context); + Conversions.toPreparedStatement(response, request, context); session .getRepreparePayloads() .put(preparedStatement.getId(), preparedStatement.getRepreparePayload()); if (prepareOnAllNodes) { - prepareOnOtherNodes() + prepareOnOtherNodes(request) .thenRun( () -> { LOG.trace( @@ -261,19 +262,19 @@ private void setFinalResult(Prepared prepared) { } } - private CompletionStage prepareOnOtherNodes() { + private CompletionStage prepareOnOtherNodes(PrepareRequest request) { List> otherNodesFutures = new ArrayList<>(); // Only process the rest of the query plan. Any node before that is either the coordinator, or // a node that failed (we assume that retrying right now has little chance of success). for (Node node : queryPlan) { - otherNodesFutures.add(prepareOnOtherNode(node)); + otherNodesFutures.add(prepareOnOtherNode(request, node)); } return CompletableFutures.allDone(otherNodesFutures); } // Try to reprepare on another node, after the initial query has succeeded. Errors are not // blocking, the preparation will be retried later on that node. Simply warn and move on. - private CompletionStage prepareOnOtherNode(Node node) { + private CompletionStage prepareOnOtherNode(PrepareRequest request, Node node) { LOG.trace("[{}] Repreparing on {}", logPrefix, node); DriverChannel channel = session.getChannel(node, logPrefix); if (channel == null) { @@ -284,9 +285,9 @@ private CompletionStage prepareOnOtherNode(Node node) { ThrottledAdminRequestHandler.prepare( channel, false, - message, + toPrepareMessage(request), request.getCustomPayload(), - timeout, + Conversions.resolveRequestTimeout(request, context), throttler, session.getMetricUpdater(), logPrefix); @@ -307,6 +308,8 @@ private CompletionStage prepareOnOtherNode(Node node) { @Override public void onThrottleFailure(@NonNull RequestThrottlingException error) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialRequest, context); session .getMetricUpdater() .incrementCounter(DefaultSessionMetric.THROTTLING_ERRORS, executionProfile.getName()); @@ -326,13 +329,16 @@ private void setFinalError(Throwable error) { private class InitialPrepareCallback implements ResponseCallback, GenericFutureListener> { + private final PrepareRequest request; private final Node node; private final DriverChannel channel; // How many times we've invoked the retry policy and it has returned a "retry" decision (0 for // the first attempt of each execution). private final int retryCount; - private InitialPrepareCallback(Node node, DriverChannel channel, int retryCount) { + private InitialPrepareCallback( + PrepareRequest request, Node node, DriverChannel channel, int retryCount) { + this.request = request; this.node = node; this.channel = channel; this.retryCount = retryCount; @@ -348,7 +354,7 @@ public void operationComplete(Future future) { node, future.cause().toString()); recordError(node, future.cause()); - sendRequest(null, retryCount); // try next host + sendRequest(request, null, retryCount); // try next host } else { if (result.isDone()) { // Might happen if the timeout just fired @@ -369,7 +375,7 @@ public void onResponse(Frame responseFrame) { Message responseMessage = responseFrame.message; if (responseMessage instanceof Prepared) { LOG.trace("[{}] Got result, completing", logPrefix); - setFinalResult((Prepared) responseMessage); + setFinalResult(request, (Prepared) responseMessage); } else if (responseMessage instanceof Error) { LOG.trace("[{}] Got error response, processing", logPrefix); processErrorResponse((Error) responseMessage); @@ -399,7 +405,7 @@ private void processErrorResponse(Error errorMessage) { if (error instanceof BootstrappingException) { LOG.trace("[{}] {} is bootstrapping, trying next node", logPrefix, node); recordError(node, error); - sendRequest(null, retryCount); + sendRequest(request, null, retryCount); } else if (error instanceof QueryValidationException || error instanceof FunctionFailureException || error instanceof ProtocolError) { @@ -408,21 +414,23 @@ private void processErrorResponse(Error errorMessage) { } else { // Because prepare requests are known to always be idempotent, we call the retry policy // directly, without checking the flag. - RetryDecision decision = retryPolicy.onErrorResponse(request, error, retryCount); - processRetryDecision(decision, error); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(request, context); + RetryVerdict verdict = retryPolicy.onErrorResponseVerdict(request, error, retryCount); + processRetryVerdict(verdict, error); } } - private void processRetryDecision(RetryDecision decision, Throwable error) { + private void processRetryVerdict(RetryVerdict verdict, Throwable error) { + RetryDecision decision = verdict.getRetryDecision(); LOG.trace("[{}] Processing retry decision {}", logPrefix, decision); switch (decision) { case RETRY_SAME: recordError(node, error); - sendRequest(node, retryCount + 1); + sendRequest(verdict.getRetryRequest(request), node, retryCount + 1); break; case RETRY_NEXT: recordError(node, error); - sendRequest(null, retryCount + 1); + sendRequest(verdict.getRetryRequest(request), null, retryCount + 1); break; case RETHROW: setFinalError(error); @@ -442,15 +450,16 @@ public void onFailure(Throwable error) { return; } LOG.trace("[{}] Request failure, processing: {}", logPrefix, error.toString()); - RetryDecision decision; + RetryVerdict verdict; try { - decision = retryPolicy.onRequestAborted(request, error, retryCount); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(request, context); + verdict = retryPolicy.onRequestAbortedVerdict(request, error, retryCount); } catch (Throwable cause) { setFinalError( new IllegalStateException("Unexpected error while invoking the retry policy", cause)); return; } - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); } public void cancel() { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java index 0f973964694..166563b3160 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java @@ -29,8 +29,8 @@ import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; -import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; import com.datastax.oss.driver.api.core.servererrors.FunctionFailureException; @@ -41,7 +41,6 @@ import com.datastax.oss.driver.api.core.servererrors.WriteTimeoutException; import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.api.core.session.throttling.Throttled; -import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.internal.core.adminrequest.ThrottledAdminRequestHandler; import com.datastax.oss.driver.internal.core.adminrequest.UnexpectedResponseException; @@ -99,14 +98,11 @@ public class CqlRequestHandler implements Throttled { private final long startTimeNanos; private final String logPrefix; - private final Statement statement; + private final Statement initialStatement; private final DefaultSession session; private final CqlIdentifier keyspace; private final InternalDriverContext context; - @NonNull private final DriverExecutionProfile executionProfile; - private final boolean isIdempotent; protected final CompletableFuture result; - private final Message message; private final Timer timer; /** * How many speculative executions are currently running (including the initial execution). We @@ -121,12 +117,9 @@ public class CqlRequestHandler implements Throttled { */ private final AtomicInteger startedSpeculativeExecutionsCount; - private final Duration timeout; final Timeout scheduledTimeout; final List scheduledExecutions; private final List inFlightCallbacks; - private final RetryPolicy retryPolicy; - private final SpeculativeExecutionPolicy speculativeExecutionPolicy; private final RequestThrottler throttler; private final RequestTracker requestTracker; private final SessionMetricUpdater sessionMetricUpdater; @@ -145,19 +138,10 @@ protected CqlRequestHandler( this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); LOG.trace("[{}] Creating new handler for request {}", logPrefix, statement); - this.statement = statement; + this.initialStatement = statement; this.session = session; this.keyspace = session.getKeyspace().orElse(null); this.context = context; - this.executionProfile = Conversions.resolveExecutionProfile(statement, context); - this.retryPolicy = context.getRetryPolicy(executionProfile.getName()); - this.speculativeExecutionPolicy = - context.getSpeculativeExecutionPolicy(executionProfile.getName()); - Boolean statementIsIdempotent = statement.isIdempotent(); - this.isIdempotent = - (statementIsIdempotent == null) - ? executionProfile.getBoolean(DefaultDriverOption.REQUEST_DEFAULT_IDEMPOTENCE) - : statementIsIdempotent; this.result = new CompletableFuture<>(); this.result.exceptionally( t -> { @@ -170,29 +154,27 @@ protected CqlRequestHandler( } return null; }); - this.message = Conversions.toMessage(statement, executionProfile, context); - this.timer = context.getNettyOptions().getTimer(); - - this.timeout = - statement.getTimeout() != null - ? statement.getTimeout() - : executionProfile.getDuration(DefaultDriverOption.REQUEST_TIMEOUT); - this.scheduledTimeout = scheduleTimeout(timeout); this.activeExecutionsCount = new AtomicInteger(1); this.startedSpeculativeExecutionsCount = new AtomicInteger(0); - this.scheduledExecutions = isIdempotent ? new CopyOnWriteArrayList<>() : null; + this.scheduledExecutions = new CopyOnWriteArrayList<>(); this.inFlightCallbacks = new CopyOnWriteArrayList<>(); this.requestTracker = context.getRequestTracker(); this.sessionMetricUpdater = session.getMetricUpdater(); + this.timer = context.getNettyOptions().getTimer(); + Duration timeout = Conversions.resolveRequestTimeout(statement, context); + this.scheduledTimeout = scheduleTimeout(timeout); + this.throttler = context.getRequestThrottler(); this.throttler.register(this); } @Override public void onThrottleReady(boolean wasDelayed) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialStatement, context); if (wasDelayed // avoid call to nanoTime() if metric is disabled: && sessionMetricUpdater.isEnabled( @@ -204,12 +186,12 @@ public void onThrottleReady(boolean wasDelayed) { TimeUnit.NANOSECONDS); } Queue queryPlan = - this.statement.getNode() != null - ? new QueryPlan(this.statement.getNode()) + this.initialStatement.getNode() != null + ? new QueryPlan(this.initialStatement.getNode()) : context .getLoadBalancingPolicyWrapper() - .newQueryPlan(statement, executionProfile.getName(), session); - sendRequest(null, queryPlan, 0, 0, true); + .newQueryPlan(initialStatement, executionProfile.getName(), session); + sendRequest(initialStatement, null, queryPlan, 0, 0, true); } public CompletionStage handle() { @@ -222,6 +204,7 @@ private Timeout scheduleTimeout(Duration timeoutDuration) { return this.timer.newTimeout( (Timeout timeout1) -> setFinalError( + initialStatement, new DriverTimeoutException("Query timed out after " + timeoutDuration), null, -1), @@ -242,6 +225,7 @@ private Timeout scheduleTimeout(Duration timeoutDuration) { /** * Sends the request to the next available node. * + * @param statement The statement to execute. * @param retriedNode if not null, it will be attempted first before the rest of the query plan. * @param queryPlan the list of nodes to try (shared with all other executions) * @param currentExecutionIndex 0 for the initial execution, 1 for the first speculative one, etc. @@ -251,6 +235,7 @@ private Timeout scheduleTimeout(Duration timeoutDuration) { * @param scheduleNextExecution whether to schedule the next speculative execution */ private void sendRequest( + Statement statement, Node retriedNode, Queue queryPlan, int currentExecutionIndex, @@ -273,11 +258,12 @@ private void sendRequest( // We've reached the end of the query plan without finding any node to write to if (!result.isDone() && activeExecutionsCount.decrementAndGet() == 0) { // We're the last execution so fail the result - setFinalError(AllNodesFailedException.fromErrors(this.errors), null, -1); + setFinalError(statement, AllNodesFailedException.fromErrors(this.errors), null, -1); } } else { NodeResponseCallback nodeResponseCallback = new NodeResponseCallback( + statement, node, queryPlan, channel, @@ -285,6 +271,9 @@ private void sendRequest( retryCount, scheduleNextExecution, logPrefix); + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); + Message message = Conversions.toMessage(statement, executionProfile, context); channel .write(message, statement.isTracing(), statement.getCustomPayload(), nodeResponseCallback) .addListener(nodeResponseCallback); @@ -336,40 +325,51 @@ private void setFinalResult( // Only call nanoTime() if we're actually going to use it long completionTimeNanos = NANOTIME_NOT_MEASURED_YET, totalLatencyNanos = NANOTIME_NOT_MEASURED_YET; + if (!(requestTracker instanceof NoopRequestTracker)) { completionTimeNanos = System.nanoTime(); totalLatencyNanos = completionTimeNanos - startTimeNanos; long nodeLatencyNanos = completionTimeNanos - callback.nodeStartTimeNanos; requestTracker.onNodeSuccess( - statement, nodeLatencyNanos, executionProfile, callback.node, logPrefix); + callback.statement, + nodeLatencyNanos, + callback.executionProfile, + callback.node, + logPrefix); requestTracker.onSuccess( - statement, totalLatencyNanos, executionProfile, callback.node, logPrefix); + callback.statement, + totalLatencyNanos, + callback.executionProfile, + callback.node, + logPrefix); } if (sessionMetricUpdater.isEnabled( - DefaultSessionMetric.CQL_REQUESTS, executionProfile.getName())) { + DefaultSessionMetric.CQL_REQUESTS, callback.executionProfile.getName())) { if (completionTimeNanos == NANOTIME_NOT_MEASURED_YET) { completionTimeNanos = System.nanoTime(); totalLatencyNanos = completionTimeNanos - startTimeNanos; } sessionMetricUpdater.updateTimer( DefaultSessionMetric.CQL_REQUESTS, - executionProfile.getName(), + callback.executionProfile.getName(), totalLatencyNanos, TimeUnit.NANOSECONDS); } } // log the warnings if they have NOT been disabled if (!executionInfo.getWarnings().isEmpty() - && executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOG_WARNINGS) + && callback.executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOG_WARNINGS) && LOG.isWarnEnabled()) { - logServerWarnings(executionInfo.getWarnings()); + logServerWarnings( + callback.statement, callback.executionProfile, executionInfo.getWarnings()); } } catch (Throwable error) { - setFinalError(error, callback.node, -1); + setFinalError(callback.statement, error, callback.node, -1); } } - private void logServerWarnings(List warnings) { + private void logServerWarnings( + Statement statement, DriverExecutionProfile executionProfile, List warnings) { // use the RequestLogFormatter to format the query StringBuilder statementString = new StringBuilder(); context @@ -403,7 +403,7 @@ private ExecutionInfo buildExecutionInfo( ByteBuffer pagingState = (resultMessage instanceof Rows) ? ((Rows) resultMessage).getMetadata().pagingState : null; return new DefaultExecutionInfo( - statement, + callback.statement, callback.node, startedSpeculativeExecutionsCount.get(), callback.execution, @@ -413,17 +413,21 @@ private ExecutionInfo buildExecutionInfo( schemaInAgreement, session, context, - executionProfile); + callback.executionProfile); } @Override public void onThrottleFailure(@NonNull RequestThrottlingException error) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(initialStatement, context); sessionMetricUpdater.incrementCounter( DefaultSessionMetric.THROTTLING_ERRORS, executionProfile.getName()); - setFinalError(error, null, -1); + setFinalError(initialStatement, error, null, -1); } - private void setFinalError(Throwable error, Node node, int execution) { + private void setFinalError(Statement statement, Throwable error, Node node, int execution) { + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(statement, context); if (error instanceof DriverException) { ((DriverException) error) .setExecutionInfo( @@ -465,6 +469,8 @@ private class NodeResponseCallback implements ResponseCallback, GenericFutureListener> { private final long nodeStartTimeNanos = System.nanoTime(); + private final Statement statement; + private final DriverExecutionProfile executionProfile; private final Node node; private final Queue queryPlan; private final DriverChannel channel; @@ -478,6 +484,7 @@ private class NodeResponseCallback private final String logPrefix; private NodeResponseCallback( + Statement statement, Node node, Queue queryPlan, DriverChannel channel, @@ -485,6 +492,7 @@ private NodeResponseCallback( int retryCount, boolean scheduleNextExecution, String logPrefix) { + this.statement = statement; this.node = node; this.queryPlan = queryPlan; this.channel = channel; @@ -492,6 +500,7 @@ private NodeResponseCallback( this.retryCount = retryCount; this.scheduleNextExecution = scheduleNextExecution; this.logPrefix = logPrefix + "|" + execution; + this.executionProfile = Conversions.resolveExecutionProfile(statement, context); } // this gets invoked once the write completes. @@ -502,7 +511,7 @@ public void operationComplete(Future future) throws Exception { if (error instanceof EncoderException && error.getCause() instanceof FrameTooLongException) { trackNodeError(node, error.getCause(), NANOTIME_NOT_MEASURED_YET); - setFinalError(error.getCause(), node, execution); + setFinalError(statement, error.getCause(), node, execution); } else { LOG.trace( "[{}] Failed to send request on {}, trying next node (cause: {})", @@ -515,7 +524,12 @@ public void operationComplete(Future future) throws Exception { .getMetricUpdater() .incrementCounter(DefaultNodeMetric.UNSENT_REQUESTS, executionProfile.getName()); sendRequest( - null, queryPlan, execution, retryCount, scheduleNextExecution); // try next node + statement, + null, + queryPlan, + execution, + retryCount, + scheduleNextExecution); // try next node } } else { LOG.trace("[{}] Request sent on {}", logPrefix, channel); @@ -525,13 +539,13 @@ public void operationComplete(Future future) throws Exception { cancel(); } else { inFlightCallbacks.add(this); - if (scheduleNextExecution && isIdempotent) { + if (scheduleNextExecution && Conversions.resolveIdempotence(statement, context)) { int nextExecution = execution + 1; long nextDelay; try { nextDelay = - speculativeExecutionPolicy.nextExecution( - node, keyspace, statement, nextExecution); + Conversions.resolveSpeculativeExecutionPolicy(statement, context) + .nextExecution(node, keyspace, statement, nextExecution); } catch (Throwable cause) { // This is a bug in the policy, but not fatal since we have at least one other // execution already running. Don't fail the whole request. @@ -573,7 +587,7 @@ private void scheduleSpeculativeExecution(int index, long delay) { .getMetricUpdater() .incrementCounter( DefaultNodeMetric.SPECULATIVE_EXECUTIONS, executionProfile.getName()); - sendRequest(null, queryPlan, index, 0, true); + sendRequest(statement, null, queryPlan, index, 0, true); } }, delay, @@ -645,11 +659,14 @@ public void onResponse(Frame responseFrame) { new IllegalStateException("Unexpected response " + responseMessage), nodeResponseTimeNanos); setFinalError( - new IllegalStateException("Unexpected response " + responseMessage), node, execution); + statement, + new IllegalStateException("Unexpected response " + responseMessage), + node, + execution); } } catch (Throwable t) { trackNodeError(node, t, nodeResponseTimeNanos); - setFinalError(t, node, execution); + setFinalError(statement, t, node, execution); } } @@ -675,7 +692,7 @@ private void processErrorResponse(Error errorMessage) { true, reprepareMessage, repreparePayload.customPayload, - timeout, + Conversions.resolveRequestTimeout(statement, context), throttler, sessionMetricUpdater, logPrefix); @@ -696,19 +713,19 @@ private void processErrorResponse(Error errorMessage) { || prepareError instanceof ProtocolError) { LOG.trace("[{}] Unrecoverable error on reprepare, rethrowing", logPrefix); trackNodeError(node, prepareError, NANOTIME_NOT_MEASURED_YET); - setFinalError(prepareError, node, execution); + setFinalError(statement, prepareError, node, execution); return null; } } } else if (exception instanceof RequestThrottlingException) { trackNodeError(node, exception, NANOTIME_NOT_MEASURED_YET); - setFinalError(exception, node, execution); + setFinalError(statement, exception, node, execution); return null; } recordError(node, exception); trackNodeError(node, exception, NANOTIME_NOT_MEASURED_YET); LOG.trace("[{}] Reprepare failed, trying next node", logPrefix); - sendRequest(null, queryPlan, execution, retryCount, false); + sendRequest(statement, null, queryPlan, execution, retryCount, false); } else { if (!repreparedId.equals(idToReprepare)) { IllegalStateException illegalStateException = @@ -721,10 +738,10 @@ private void processErrorResponse(Error errorMessage) { Bytes.toHexString(idToReprepare), Bytes.toHexString(repreparedId))); trackNodeError(node, illegalStateException, NANOTIME_NOT_MEASURED_YET); - setFinalError(illegalStateException, node, execution); + setFinalError(statement, illegalStateException, node, execution); } LOG.trace("[{}] Reprepare sucessful, retrying", logPrefix); - sendRequest(node, queryPlan, execution, retryCount, false); + sendRequest(statement, node, queryPlan, execution, retryCount, false); } return null; }); @@ -736,20 +753,21 @@ private void processErrorResponse(Error errorMessage) { LOG.trace("[{}] {} is bootstrapping, trying next node", logPrefix, node); recordError(node, error); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - sendRequest(null, queryPlan, execution, retryCount, false); + sendRequest(statement, null, queryPlan, execution, retryCount, false); } else if (error instanceof QueryValidationException || error instanceof FunctionFailureException || error instanceof ProtocolError) { LOG.trace("[{}] Unrecoverable error, rethrowing", logPrefix); metricUpdater.incrementCounter(DefaultNodeMetric.OTHER_ERRORS, executionProfile.getName()); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - setFinalError(error, node, execution); + setFinalError(statement, error, node, execution); } else { - RetryDecision decision; + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryVerdict verdict; if (error instanceof ReadTimeoutException) { ReadTimeoutException readTimeout = (ReadTimeoutException) error; - decision = - retryPolicy.onReadTimeout( + verdict = + retryPolicy.onReadTimeoutVerdict( statement, readTimeout.getConsistencyLevel(), readTimeout.getBlockFor(), @@ -758,32 +776,32 @@ private void processErrorResponse(Error errorMessage) { retryCount); updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.READ_TIMEOUTS, DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT); } else if (error instanceof WriteTimeoutException) { WriteTimeoutException writeTimeout = (WriteTimeoutException) error; - decision = - isIdempotent - ? retryPolicy.onWriteTimeout( + verdict = + Conversions.resolveIdempotence(statement, context) + ? retryPolicy.onWriteTimeoutVerdict( statement, writeTimeout.getConsistencyLevel(), writeTimeout.getWriteType(), writeTimeout.getBlockFor(), writeTimeout.getReceived(), retryCount) - : RetryDecision.RETHROW; + : RetryVerdict.RETHROW; updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.WRITE_TIMEOUTS, DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT); } else if (error instanceof UnavailableException) { UnavailableException unavailable = (UnavailableException) error; - decision = - retryPolicy.onUnavailable( + verdict = + retryPolicy.onUnavailableVerdict( statement, unavailable.getConsistencyLevel(), unavailable.getRequired(), @@ -791,42 +809,54 @@ private void processErrorResponse(Error errorMessage) { retryCount); updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.UNAVAILABLES, DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, DefaultNodeMetric.IGNORES_ON_UNAVAILABLE); } else { - decision = - isIdempotent - ? retryPolicy.onErrorResponse(statement, error, retryCount) - : RetryDecision.RETHROW; + verdict = + Conversions.resolveIdempotence(statement, context) + ? retryPolicy.onErrorResponseVerdict(statement, error, retryCount) + : RetryVerdict.RETHROW; updateErrorMetrics( metricUpdater, - decision, + verdict, DefaultNodeMetric.OTHER_ERRORS, DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, DefaultNodeMetric.IGNORES_ON_OTHER_ERROR); } - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); } } - private void processRetryDecision(RetryDecision decision, Throwable error) { - LOG.trace("[{}] Processing retry decision {}", logPrefix, decision); - switch (decision) { + private void processRetryVerdict(RetryVerdict verdict, Throwable error) { + LOG.trace("[{}] Processing retry decision {}", logPrefix, verdict); + switch (verdict.getRetryDecision()) { case RETRY_SAME: recordError(node, error); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - sendRequest(node, queryPlan, execution, retryCount + 1, false); + sendRequest( + verdict.getRetryRequest(statement), + node, + queryPlan, + execution, + retryCount + 1, + false); break; case RETRY_NEXT: recordError(node, error); trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - sendRequest(null, queryPlan, execution, retryCount + 1, false); + sendRequest( + verdict.getRetryRequest(statement), + null, + queryPlan, + execution, + retryCount + 1, + false); break; case RETHROW: trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); - setFinalError(error, node, execution); + setFinalError(statement, error, node, execution); break; case IGNORE: setFinalResult(Void.INSTANCE, null, true, this); @@ -836,12 +866,12 @@ private void processRetryDecision(RetryDecision decision, Throwable error) { private void updateErrorMetrics( NodeMetricUpdater metricUpdater, - RetryDecision decision, + RetryVerdict verdict, DefaultNodeMetric error, DefaultNodeMetric retriesOnError, DefaultNodeMetric ignoresOnError) { metricUpdater.incrementCounter(error, executionProfile.getName()); - switch (decision) { + switch (verdict.getRetryDecision()) { case RETRY_SAME: case RETRY_NEXT: metricUpdater.incrementCounter(DefaultNodeMetric.RETRIES, executionProfile.getName()); @@ -863,24 +893,27 @@ public void onFailure(Throwable error) { return; } LOG.trace("[{}] Request failure, processing: {}", logPrefix, error); - RetryDecision decision; - if (!isIdempotent || error instanceof FrameTooLongException) { - decision = RetryDecision.RETHROW; + RetryVerdict verdict; + if (!Conversions.resolveIdempotence(statement, context) + || error instanceof FrameTooLongException) { + verdict = RetryVerdict.RETHROW; } else { try { - decision = retryPolicy.onRequestAborted(statement, error, retryCount); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + verdict = retryPolicy.onRequestAbortedVerdict(statement, error, retryCount); } catch (Throwable cause) { setFinalError( + statement, new IllegalStateException("Unexpected error while invoking the retry policy", cause), null, execution); return; } } - processRetryDecision(decision, error); + processRetryVerdict(verdict, error); updateErrorMetrics( ((DefaultNode) node).getMetricUpdater(), - decision, + verdict, DefaultNodeMetric.ABORTED_REQUESTS, DefaultNodeMetric.RETRIES_ON_ABORTED, DefaultNodeMetric.IGNORES_ON_ABORTED); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java index b988f66fce8..b9653bc158a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java @@ -102,6 +102,7 @@ public DefaultRetryPolicy( *

    Otherwise, the exception is rethrown. */ @Override + @Deprecated public RetryDecision onReadTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -135,6 +136,7 @@ public RetryDecision onReadTimeout( *

    Otherwise, the exception is rethrown. */ @Override + @Deprecated public RetryDecision onWriteTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -167,6 +169,7 @@ public RetryDecision onWriteTimeout( *

    Otherwise, the exception is rethrown. */ @Override + @Deprecated public RetryDecision onUnavailable( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -190,6 +193,7 @@ public RetryDecision onUnavailable( * (assuming a driver bug) in all other cases. */ @Override + @Deprecated public RetryDecision onRequestAborted( @NonNull Request request, @NonNull Throwable error, int retryCount) { @@ -212,6 +216,7 @@ public RetryDecision onRequestAborted( * node. */ @Override + @Deprecated public RetryDecision onErrorResponse( @NonNull Request request, @NonNull CoordinatorException error, int retryCount) { diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerRetryTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerRetryTest.java index 4241c091515..3f6af732f11 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerRetryTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerRetryTest.java @@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.when; import com.datastax.dse.driver.DseTestFixtures; import com.datastax.dse.driver.api.core.DseProtocolVersion; @@ -38,8 +39,8 @@ import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.DefaultWriteType; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; @@ -170,8 +171,8 @@ public void should_try_next_node_if_idempotent_and_retry_policy_decides_so( harnessBuilder.withResponse(node2, defaultFrameOf(DseTestFixtures.singleDseRow())); try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETRY_NEXT); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETRY_NEXT); ContinuousCqlRequestHandler handler = new ContinuousCqlRequestHandler( @@ -225,8 +226,8 @@ public void should_try_same_node_if_idempotent_and_retry_policy_decides_so( harnessBuilder.withResponse(node1, defaultFrameOf(DseTestFixtures.singleDseRow())); try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETRY_SAME); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETRY_SAME); ContinuousCqlRequestHandler handler = new ContinuousCqlRequestHandler( @@ -279,8 +280,8 @@ public void should_ignore_error_if_idempotent_and_retry_policy_decides_so( failureScenario.mockRequestError(harnessBuilder, node1); try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.IGNORE); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.IGNORE); ContinuousCqlRequestHandler handler = new ContinuousCqlRequestHandler( @@ -332,8 +333,8 @@ public void should_rethrow_error_if_idempotent_and_retry_policy_decides_so( try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETHROW); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETHROW); ContinuousCqlRequestHandler handler = new ContinuousCqlRequestHandler( @@ -384,8 +385,8 @@ public void should_rethrow_error_if_not_idempotent_and_error_unsafe_or_policy_re try (RequestHandlerTestHarness harness = harnessBuilder.build()) { if (shouldCallRetryPolicy) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETHROW); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETHROW); } ContinuousCqlRequestHandler handler = @@ -441,7 +442,7 @@ private abstract static class FailureScenario { abstract void mockRequestError(RequestHandlerTestHarness.Builder builder, Node node); - abstract void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision); + abstract void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict); } @DataProvider @@ -462,16 +463,15 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - Mockito.when( - policy.onReadTimeout( - any(SimpleStatement.class), - eq(DefaultConsistencyLevel.LOCAL_ONE), - eq(2), - eq(1), - eq(true), - eq(0))) - .thenReturn(decision); + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onReadTimeoutVerdict( + any(SimpleStatement.class), + eq(DefaultConsistencyLevel.LOCAL_ONE), + eq(2), + eq(1), + eq(true), + eq(0))) + .thenReturn(verdict); } }, new FailureScenario( @@ -493,16 +493,15 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - Mockito.when( - policy.onWriteTimeout( - any(SimpleStatement.class), - eq(DefaultConsistencyLevel.LOCAL_ONE), - eq(DefaultWriteType.SIMPLE), - eq(2), - eq(1), - eq(0))) - .thenReturn(decision); + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onWriteTimeoutVerdict( + any(SimpleStatement.class), + eq(DefaultConsistencyLevel.LOCAL_ONE), + eq(DefaultWriteType.SIMPLE), + eq(2), + eq(1), + eq(0))) + .thenReturn(verdict); } }, new FailureScenario( @@ -520,15 +519,14 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - Mockito.when( - policy.onUnavailable( - any(SimpleStatement.class), - eq(DefaultConsistencyLevel.LOCAL_ONE), - eq(2), - eq(1), - eq(0))) - .thenReturn(decision); + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onUnavailableVerdict( + any(SimpleStatement.class), + eq(DefaultConsistencyLevel.LOCAL_ONE), + eq(2), + eq(1), + eq(0))) + .thenReturn(verdict); } }, new FailureScenario( @@ -545,11 +543,10 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - Mockito.when( - policy.onErrorResponse( - any(SimpleStatement.class), any(ServerError.class), eq(0))) - .thenReturn(decision); + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onErrorResponseVerdict( + any(SimpleStatement.class), any(ServerError.class), eq(0))) + .thenReturn(verdict); } }, new FailureScenario( @@ -563,11 +560,10 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - Mockito.when( - policy.onRequestAborted( - any(SimpleStatement.class), any(HeartbeatException.class), eq(0))) - .thenReturn(decision); + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onRequestAbortedVerdict( + any(SimpleStatement.class), any(HeartbeatException.class), eq(0))) + .thenReturn(verdict); } }); } diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java index 63935dc7afb..a5d0c5934d8 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java @@ -85,7 +85,7 @@ public void should_return_paged_results(GraphProtocol graphProtocol) throws IOEx try (RequestHandlerTestHarness harness = builder.build()) { - GraphStatement graphStatement = + GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery").setExecutionProfileName(profileName); ContinuousGraphRequestHandler handler = @@ -158,7 +158,7 @@ public void should_honor_default_timeout() throws Exception { when(profile.getString(DseDriverOption.GRAPH_SUB_PROTOCOL)) .thenReturn(GraphProtocol.GRAPH_BINARY_1_0.toInternalCode()); - GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery"); + GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery"); // when ContinuousGraphRequestHandler handler = @@ -207,7 +207,7 @@ public void should_honor_statement_timeout() throws Exception { when(profile.getString(DseDriverOption.GRAPH_SUB_PROTOCOL)) .thenReturn(GraphProtocol.GRAPH_BINARY_1_0.toInternalCode()); - GraphStatement graphStatement = + GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery").setTimeout(statementTimeout); // when @@ -249,10 +249,7 @@ private void validateMetrics(String profileName, RequestHandlerTestHarness harne verify(harness.getSession().getMetricUpdater()) .updateTimer( - eq(DseSessionMetric.GRAPH_REQUESTS), - eq(profileName), - anyLong(), - eq(TimeUnit.NANOSECONDS)); + eq(DseSessionMetric.GRAPH_REQUESTS), eq(null), anyLong(), eq(TimeUnit.NANOSECONDS)); verifyNoMoreInteractions(harness.getSession().getMetricUpdater()); } } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java b/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java index 78c227816e9..e24c61e6585 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java @@ -40,27 +40,34 @@ protected RetryPolicyTestBase(RetryPolicy policy) { protected Assert assertOnReadTimeout( ConsistencyLevel cl, int blockFor, int received, boolean dataPresent, int retryCount) { return assertThat( - policy.onReadTimeout(request, cl, blockFor, received, dataPresent, retryCount)); + policy + .onReadTimeoutVerdict(request, cl, blockFor, received, dataPresent, retryCount) + .getRetryDecision()); } protected Assert assertOnWriteTimeout( ConsistencyLevel cl, WriteType writeType, int blockFor, int received, int retryCount) { return assertThat( - policy.onWriteTimeout(request, cl, writeType, blockFor, received, retryCount)); + policy + .onWriteTimeoutVerdict(request, cl, writeType, blockFor, received, retryCount) + .getRetryDecision()); } protected Assert assertOnUnavailable( ConsistencyLevel cl, int required, int alive, int retryCount) { - return assertThat(policy.onUnavailable(request, cl, required, alive, retryCount)); + return assertThat( + policy.onUnavailableVerdict(request, cl, required, alive, retryCount).getRetryDecision()); } protected Assert assertOnRequestAborted( Class errorClass, int retryCount) { - return assertThat(policy.onRequestAborted(request, mock(errorClass), retryCount)); + return assertThat( + policy.onRequestAbortedVerdict(request, mock(errorClass), retryCount).getRetryDecision()); } protected Assert assertOnErrorResponse( Class errorClass, int retryCount) { - return assertThat(policy.onErrorResponse(request, mock(errorClass), retryCount)); + return assertThat( + policy.onErrorResponseVerdict(request, mock(errorClass), retryCount).getRetryDecision()); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java index 3e0503bb1e0..0bafdb41305 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java @@ -31,8 +31,8 @@ import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.OverloadedException; import com.datastax.oss.driver.internal.core.channel.ResponseCallback; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -177,8 +177,8 @@ public void should_retry_initial_prepare_if_recoverable_error() { when(harness .getContext() .getRetryPolicy(anyString()) - .onErrorResponse(eq(PREPARE_REQUEST), any(OverloadedException.class), eq(0))) - .thenReturn(RetryDecision.RETRY_NEXT); + .onErrorResponseVerdict(eq(PREPARE_REQUEST), any(OverloadedException.class), eq(0))) + .thenReturn(RetryVerdict.RETRY_NEXT); CompletionStage prepareFuture = new CqlPrepareHandler(PREPARE_REQUEST, harness.getSession(), harness.getContext(), "test") @@ -210,8 +210,8 @@ public void should_not_retry_initial_prepare_if_unrecoverable_error() { when(harness .getContext() .getRetryPolicy(anyString()) - .onErrorResponse(eq(PREPARE_REQUEST), any(OverloadedException.class), eq(0))) - .thenReturn(RetryDecision.RETHROW); + .onErrorResponseVerdict(eq(PREPARE_REQUEST), any(OverloadedException.class), eq(0))) + .thenReturn(RetryVerdict.RETHROW); CompletionStage prepareFuture = new CqlPrepareHandler(PREPARE_REQUEST, harness.getSession(), harness.getContext(), "test") @@ -243,9 +243,9 @@ public void should_fail_if_retry_policy_ignores_error() { // Make node1's error unrecoverable, will rethrow RetryPolicy mockRetryPolicy = harness.getContext().getRetryPolicy(DriverExecutionProfile.DEFAULT_NAME); - when(mockRetryPolicy.onErrorResponse( + when(mockRetryPolicy.onErrorResponseVerdict( eq(PREPARE_REQUEST), any(OverloadedException.class), eq(0))) - .thenReturn(RetryDecision.IGNORE); + .thenReturn(RetryVerdict.IGNORE); CompletionStage prepareFuture = new CqlPrepareHandler(PREPARE_REQUEST, harness.getSession(), harness.getContext(), "test") diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java index ef04f814e94..06710e4c4c7 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java @@ -37,8 +37,8 @@ import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.core.retry.RetryDecision; import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; import com.datastax.oss.driver.api.core.servererrors.DefaultWriteType; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; @@ -152,8 +152,8 @@ public void should_try_next_node_if_idempotent_and_retry_policy_decides_so( harnessBuilder.withResponse(node2, defaultFrameOf(singleRow())); try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETRY_NEXT); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETRY_NEXT); CompletionStage resultSetFuture = new CqlRequestHandler(statement, harness.getSession(), harness.getContext(), "test") @@ -203,8 +203,8 @@ public void should_try_same_node_if_idempotent_and_retry_policy_decides_so( harnessBuilder.withResponse(node1, defaultFrameOf(singleRow())); try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETRY_SAME); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETRY_SAME); CompletionStage resultSetFuture = new CqlRequestHandler(statement, harness.getSession(), harness.getContext(), "test") @@ -253,8 +253,8 @@ public void should_ignore_error_if_idempotent_and_retry_policy_decides_so( failureScenario.mockRequestError(harnessBuilder, node1); try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.IGNORE); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.IGNORE); CompletionStage resultSetFuture = new CqlRequestHandler(statement, harness.getSession(), harness.getContext(), "test") @@ -302,8 +302,8 @@ public void should_rethrow_error_if_idempotent_and_retry_policy_decides_so( try (RequestHandlerTestHarness harness = harnessBuilder.build()) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETHROW); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETHROW); CompletionStage resultSetFuture = new CqlRequestHandler(statement, harness.getSession(), harness.getContext(), "test") @@ -349,8 +349,8 @@ public void should_rethrow_error_if_not_idempotent_and_error_unsafe_or_policy_re try (RequestHandlerTestHarness harness = harnessBuilder.build()) { if (shouldCallRetryPolicy) { - failureScenario.mockRetryPolicyDecision( - harness.getContext().getRetryPolicy(anyString()), RetryDecision.RETHROW); + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETHROW); } CompletionStage resultSetFuture = @@ -405,7 +405,7 @@ protected FailureScenario( abstract void mockRequestError(RequestHandlerTestHarness.Builder builder, Node node); - abstract void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision); + abstract void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict); } @DataProvider @@ -426,15 +426,15 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - when(policy.onReadTimeout( + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onReadTimeoutVerdict( any(Statement.class), eq(DefaultConsistencyLevel.LOCAL_ONE), eq(2), eq(1), eq(true), eq(0))) - .thenReturn(decision); + .thenReturn(verdict); } }, new FailureScenario( @@ -456,15 +456,15 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - when(policy.onWriteTimeout( + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onWriteTimeoutVerdict( any(Statement.class), eq(DefaultConsistencyLevel.LOCAL_ONE), eq(DefaultWriteType.SIMPLE), eq(2), eq(1), eq(0))) - .thenReturn(decision); + .thenReturn(verdict); } }, new FailureScenario( @@ -482,14 +482,14 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - when(policy.onUnavailable( + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onUnavailableVerdict( any(Statement.class), eq(DefaultConsistencyLevel.LOCAL_ONE), eq(2), eq(1), eq(0))) - .thenReturn(decision); + .thenReturn(verdict); } }, new FailureScenario( @@ -506,9 +506,9 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - when(policy.onErrorResponse(any(Statement.class), any(ServerError.class), eq(0))) - .thenReturn(decision); + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onErrorResponseVerdict(any(Statement.class), any(ServerError.class), eq(0))) + .thenReturn(verdict); } }, new FailureScenario( @@ -522,10 +522,10 @@ public void mockRequestError(RequestHandlerTestHarness.Builder builder, Node nod } @Override - public void mockRetryPolicyDecision(RetryPolicy policy, RetryDecision decision) { - when(policy.onRequestAborted( + public void mockRetryPolicyVerdict(RetryPolicy policy, RetryVerdict verdict) { + when(policy.onRequestAbortedVerdict( any(Statement.class), any(HeartbeatException.class), eq(0))) - .thenReturn(decision); + .thenReturn(verdict); } }); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/AllNodesFailedIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/AllNodesFailedIT.java index dfab751cb1a..a4453401d93 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/AllNodesFailedIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/AllNodesFailedIT.java @@ -86,6 +86,7 @@ public MultipleRetryPolicy(DriverContext context, String profileName) { } @Override + @Deprecated public RetryDecision onReadTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/MapBasedConfigLoaderIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/MapBasedConfigLoaderIT.java index 1dbb70602c0..859d6c567ad 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/MapBasedConfigLoaderIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/MapBasedConfigLoaderIT.java @@ -149,6 +149,7 @@ public IgnoreAllPolicy( } @Override + @Deprecated public RetryDecision onReadTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -160,6 +161,7 @@ public RetryDecision onReadTimeout( } @Override + @Deprecated public RetryDecision onWriteTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -171,6 +173,7 @@ public RetryDecision onWriteTimeout( } @Override + @Deprecated public RetryDecision onUnavailable( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -181,12 +184,14 @@ public RetryDecision onUnavailable( } @Override + @Deprecated public RetryDecision onRequestAborted( @NonNull Request request, @NonNull Throwable error, int retryCount) { return RetryDecision.IGNORE; } @Override + @Deprecated public RetryDecision onErrorResponse( @NonNull Request request, @NonNull CoordinatorException error, int retryCount) { return RetryDecision.IGNORE; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java index f8c5fb44d6f..c4f39711687 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java @@ -122,6 +122,7 @@ public AlwaysRetryAbortedPolicy(DriverContext context, String profileName) { } @Override + @Deprecated public RetryDecision onRequestAborted( @NonNull Request request, @NonNull Throwable error, int retryCount) { return RetryDecision.RETRY_NEXT; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java index 0b851f4b7f6..2e7665dcc6f 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java @@ -149,9 +149,11 @@ public void should_use_policy_from_config_when_not_configured_in_request_profile // A policy that simply rethrows always. public static class NoRetryPolicy implements RetryPolicy { + @SuppressWarnings("unused") public NoRetryPolicy(DriverContext context, String profileName) {} @Override + @Deprecated public RetryDecision onReadTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -163,6 +165,7 @@ public RetryDecision onReadTimeout( } @Override + @Deprecated public RetryDecision onWriteTimeout( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -174,6 +177,7 @@ public RetryDecision onWriteTimeout( } @Override + @Deprecated public RetryDecision onUnavailable( @NonNull Request request, @NonNull ConsistencyLevel cl, @@ -184,12 +188,14 @@ public RetryDecision onUnavailable( } @Override + @Deprecated public RetryDecision onRequestAborted( @NonNull Request request, @NonNull Throwable error, int retryCount) { return RetryDecision.RETHROW; } @Override + @Deprecated public RetryDecision onErrorResponse( @NonNull Request request, @NonNull CoordinatorException error, int retryCount) { return RetryDecision.RETHROW; diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 6b1536ad12c..51c0917f018 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -2,6 +2,30 @@ ### 4.10.0 +#### New `RetryVerdict` API + +[JAVA-2900](https://datastax-oss.atlassian.net/browse/JAVA-2900) introduced [`RetryVerdict`], a new +interface that allows custom retry policies to customize the request before it is retried. + +For this reason, the following methods in the `RetryPolicy` interface were added; they all return +a `RetryVerdict` instance: + +1. [`onReadTimeoutVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeoutVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) +2. [`onWriteTimeoutVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeoutVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) +3. [`onUnavailableVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onUnavailableVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-int-) +4. [`onRequestAbortedVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAbortedVerdict-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) +5. [`onErrorResponseVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponseVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) + +The following methods were deprecated: + +1. [`onReadTimeout`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) +2. [`onWriteTimeout`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) +3. [`onUnavailable`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onUnavailable-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-int-) +4. [`onRequestAborted`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAborted-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) +5. [`onErrorResponse`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponse-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) + +[`RetryVerdict`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryVerdict.html + #### Enhancements to the `Uuids` utility class [JAVA-2449](https://datastax-oss.atlassian.net/browse/JAVA-2449) modified the implementation of From d1b782e4509d818e035737564def296748eedeb2 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 30 Nov 2020 14:28:50 +0100 Subject: [PATCH 036/395] JAVA-2900: Re-introduce consistency downgrading retries --- changelog/README.md | 1 + .../driver/api/core/retry/RetryVerdict.java | 9 +- .../ConsistencyDowngradingRetryPolicy.java | 374 +++++ .../ConsistencyDowngradingRetryVerdict.java | 55 + .../core/retry/DefaultRetryPolicy.java | 4 +- .../core/retry/DefaultRetryVerdict.java | 40 + core/src/main/resources/reference.conf | 8 +- ...ConsistencyDowngradingRetryPolicyTest.java | 146 ++ .../core/retry/DefaultRetryPolicyTest.java | 52 +- .../api/core/retry/RetryPolicyTestBase.java | 56 +- .../examples/retry/DowngradingRetry.java | 12 +- faq/README.md | 45 +- .../ConsistencyDowngradingRetryPolicyIT.java | 1326 +++++++++++++++++ manual/core/retries/README.md | 128 +- upgrade_guide/README.md | 9 +- 15 files changed, 2153 insertions(+), 112 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryVerdict.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryVerdict.java create mode 100644 core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java diff --git a/changelog/README.md b/changelog/README.md index 86b2d3d04d3..8f740eb8870 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [new feature] JAVA-2900: Re-introduce consistency downgrading retries - [new feature] JAVA-2903: BlockHound integration - [improvement] JAVA-2877: Allow skipping validation for individual mapped entities - [improvement] JAVA-2871: Allow keyspace exclusions in the metadata, and exclude system keyspaces diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java index 735019aa80f..9a430e75445 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryVerdict.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.api.core.retry; import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.internal.core.retry.DefaultRetryVerdict; import edu.umd.cs.findbugs.annotations.NonNull; /** @@ -27,16 +28,16 @@ public interface RetryVerdict { /** A retry verdict that retries the same request on the same node. */ - RetryVerdict RETRY_SAME = () -> RetryDecision.RETRY_SAME; + RetryVerdict RETRY_SAME = new DefaultRetryVerdict(RetryDecision.RETRY_SAME); /** A retry verdict that retries the same request on the next node in the query plan. */ - RetryVerdict RETRY_NEXT = () -> RetryDecision.RETRY_NEXT; + RetryVerdict RETRY_NEXT = new DefaultRetryVerdict(RetryDecision.RETRY_NEXT); /** A retry verdict that ignores the error, returning and empty result set to the caller. */ - RetryVerdict IGNORE = () -> RetryDecision.IGNORE; + RetryVerdict IGNORE = new DefaultRetryVerdict(RetryDecision.IGNORE); /** A retry verdict that rethrows the execution error to the calling code. */ - RetryVerdict RETHROW = () -> RetryDecision.RETHROW; + RetryVerdict RETHROW = new DefaultRetryVerdict(RetryDecision.RETHROW); /** @return The retry decision to apply. */ @NonNull diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java new file mode 100644 index 00000000000..6364bb38592 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java @@ -0,0 +1,374 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.retry; + +import static com.datastax.oss.driver.api.core.servererrors.WriteType.BATCH; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.BATCH_LOG; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.SIMPLE; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.UNLOGGED_BATCH; + +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.connection.ClosedConnectionException; +import com.datastax.oss.driver.api.core.connection.HeartbeatException; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.retry.RetryDecision; +import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; +import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; +import com.datastax.oss.driver.api.core.servererrors.ReadFailureException; +import com.datastax.oss.driver.api.core.servererrors.WriteFailureException; +import com.datastax.oss.driver.api.core.servererrors.WriteType; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import edu.umd.cs.findbugs.annotations.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A retry policy that sometimes retries with a lower consistency level than the one initially + * requested. + * + *

    BEWARE: this policy may retry queries using a lower consistency level than the one + * initially requested. By doing so, it may break consistency guarantees. In other words, if you use + * this retry policy, there are cases (documented below) where a read at {@code QUORUM} may + * not see a preceding write at {@code QUORUM}. Furthermore, this policy doesn't always respect + * datacenter locality; for example, it may downgrade {@code LOCAL_QUORUM} to {@code ONE}, and thus + * could accidentally send a write that was intended for the local datacenter to another + * datacenter.Do not use this policy unless you have understood the cases where this can happen and + * are ok with that. + * + *

    This policy implements the same retries than the {@link DefaultRetryPolicy} policy. But on top + * of that, it also retries in the following cases: + * + *

      + *
    • On a read timeout: if the number of replicas that responded is greater than one, but lower + * than is required by the requested consistency level, the operation is retried at a lower + * consistency level. + *
    • On a write timeout: if the operation is a {@code WriteType.UNLOGGED_BATCH} and at least one + * replica acknowledged the write, the operation is retried at a lower consistency level. + * Furthermore, for other operations, if at least one replica acknowledged the write, the + * timeout is ignored. + *
    • On an unavailable exception: if at least one replica is alive, the operation is retried at + * a lower consistency level. + *
    + * + * The lower consistency level to use for retries is determined by the following rules: + * + *
      + *
    • if more than 3 replicas responded, use {@code THREE}. + *
    • if 1, 2 or 3 replicas responded, use the corresponding level {@code ONE}, {@code TWO} or + * {@code THREE}. + *
    + * + * Note that if the initial consistency level was {@code EACH_QUORUM}, Cassandra returns the number + * of live replicas in the datacenter that failed to reach consistency, not the overall + * number in the cluster. Therefore if this number is 0, we still retry at {@code ONE}, on the + * assumption that a host may still be up in another datacenter. + * + *

    The reasoning behind this retry policy is the following one. If, based on the information the + * Cassandra coordinator node returns, retrying the operation with the initially requested + * consistency has a chance to succeed, do it. Otherwise, if based on this information, we know that + * the initially requested consistency level cannot be achieved currently, then: + * + *

      + *
    • For writes, ignore the exception (thus silently failing the consistency requirement) if we + * know the write has been persisted on at least one replica. + *
    • For reads, try reading at a lower consistency level (thus silently failing the consistency + * requirement). + *
    + * + * In other words, this policy implements the idea that if the requested consistency level cannot be + * achieved, the next best thing for writes is to make sure the data is persisted, and that reading + * something is better than reading nothing, even if there is a risk of reading stale data. + */ +public class ConsistencyDowngradingRetryPolicy implements RetryPolicy { + + private static final Logger LOG = + LoggerFactory.getLogger(ConsistencyDowngradingRetryPolicy.class); + + @VisibleForTesting + public static final String VERDICT_ON_READ_TIMEOUT = + "[{}] Verdict on read timeout (consistency: {}, required responses: {}, " + + "received responses: {}, data retrieved: {}, retries: {}): {}"; + + @VisibleForTesting + public static final String VERDICT_ON_WRITE_TIMEOUT = + "[{}] Verdict on write timeout (consistency: {}, write type: {}, " + + "required acknowledgments: {}, received acknowledgments: {}, retries: {}): {}"; + + @VisibleForTesting + public static final String VERDICT_ON_UNAVAILABLE = + "[{}] Verdict on unavailable exception (consistency: {}, " + + "required replica: {}, alive replica: {}, retries: {}): {}"; + + @VisibleForTesting + public static final String VERDICT_ON_ABORTED = + "[{}] Verdict on aborted request (type: {}, message: '{}', retries: {}): {}"; + + @VisibleForTesting + public static final String VERDICT_ON_ERROR = + "[{}] Verdict on node error (type: {}, message: '{}', retries: {}): {}"; + + private final String logPrefix; + + @SuppressWarnings("unused") + public ConsistencyDowngradingRetryPolicy( + @NonNull DriverContext context, @NonNull String profileName) { + this(context.getSessionName() + "|" + profileName); + } + + public ConsistencyDowngradingRetryPolicy(@NonNull String logPrefix) { + this.logPrefix = logPrefix; + } + + /** + * {@inheritDoc} + * + *

    This implementation triggers a maximum of one retry. If less replicas responded than + * required by the consistency level (but at least one replica did respond), the operation is + * retried at a lower consistency level. If enough replicas responded but data was not retrieved, + * the operation is retried with the initial consistency level. Otherwise, an exception is thrown. + */ + @Override + public RetryVerdict onReadTimeoutVerdict( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + int blockFor, + int received, + boolean dataPresent, + int retryCount) { + RetryVerdict verdict; + if (retryCount != 0) { + verdict = RetryVerdict.RETHROW; + } else if (cl.isSerial()) { + // CAS reads are not all that useful in terms of visibility of the writes since CAS write + // supports the normal consistency levels on the committing phase. So the main use case for + // CAS reads is probably for when you've timed out on a CAS write and want to make sure what + // happened. Downgrading in that case would be always wrong so we just special-case to + // rethrow. + verdict = RetryVerdict.RETHROW; + } else if (received < blockFor) { + verdict = maybeDowngrade(received, cl); + } else if (!dataPresent) { + // Retry with same CL since this usually means that enough replica are alive to satisfy the + // consistency but the coordinator picked a dead one for data retrieval, not having detected + // that replica as dead yet. + verdict = RetryVerdict.RETRY_SAME; + } else { + // This usually means a digest mismatch, in which case it's pointless to retry since + // the inconsistency has to be repaired first. + verdict = RetryVerdict.RETHROW; + } + if (LOG.isTraceEnabled()) { + LOG.trace( + VERDICT_ON_READ_TIMEOUT, + logPrefix, + cl, + blockFor, + received, + dataPresent, + retryCount, + verdict); + } + return verdict; + } + + /** + * {@inheritDoc} + * + *

    This implementation triggers a maximum of one retry. If {@code writeType == + * WriteType.BATCH_LOG}, the write is retried with the initial consistency level. If {@code + * writeType == WriteType.UNLOGGED_BATCH} and at least one replica acknowledged, the write is + * retried with a lower consistency level (with unlogged batch, a write timeout can always + * mean that part of the batch haven't been persisted at all, even if {@code receivedAcks > 0}). + * For other write types ({@code WriteType.SIMPLE} and {@code WriteType.BATCH}), if we know the + * write has been persisted on at least one replica, we ignore the exception. Otherwise, an + * exception is thrown. + */ + @Override + public RetryVerdict onWriteTimeoutVerdict( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + @NonNull WriteType writeType, + int blockFor, + int received, + int retryCount) { + RetryVerdict verdict; + if (retryCount != 0) { + verdict = RetryVerdict.RETHROW; + } else if (SIMPLE.equals(writeType) || BATCH.equals(writeType)) { + // Since we provide atomicity, if at least one replica acknowledged the write, + // there is no point in retrying + verdict = received > 0 ? RetryVerdict.IGNORE : RetryVerdict.RETHROW; + } else if (UNLOGGED_BATCH.equals(writeType)) { + // Since only part of the batch could have been persisted, + // retry with whatever consistency should allow to persist all + verdict = maybeDowngrade(received, cl); + } else if (BATCH_LOG.equals(writeType)) { + verdict = RetryVerdict.RETRY_SAME; + } else { + verdict = RetryVerdict.RETHROW; + } + if (LOG.isTraceEnabled()) { + LOG.trace( + VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + cl, + writeType, + blockFor, + received, + retryCount, + verdict); + } + return verdict; + } + + /** + * {@inheritDoc} + * + *

    This implementation triggers a maximum of one retry. If at least one replica is known to be + * alive, the operation is retried at a lower consistency level. + */ + @Override + public RetryVerdict onUnavailableVerdict( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + int required, + int alive, + int retryCount) { + RetryVerdict verdict; + if (retryCount != 0) { + verdict = RetryVerdict.RETHROW; + } else if (cl.isSerial()) { + // JAVA-764: if the requested consistency level is serial, it means that the + // operation failed at the paxos phase of a LWT. + // Retry on the next host, on the assumption that the initial coordinator could be + // network-isolated. + verdict = RetryVerdict.RETRY_NEXT; + } else { + verdict = maybeDowngrade(alive, cl); + } + if (LOG.isTraceEnabled()) { + LOG.trace(VERDICT_ON_UNAVAILABLE, logPrefix, cl, required, alive, retryCount, verdict); + } + return verdict; + } + + @Override + public RetryVerdict onRequestAbortedVerdict( + @NonNull Request request, @NonNull Throwable error, int retryCount) { + RetryVerdict verdict = + error instanceof ClosedConnectionException || error instanceof HeartbeatException + ? RetryVerdict.RETRY_NEXT + : RetryVerdict.RETHROW; + if (LOG.isTraceEnabled()) { + LOG.trace( + VERDICT_ON_ABORTED, + logPrefix, + error.getClass().getSimpleName(), + error.getMessage(), + retryCount, + verdict); + } + return verdict; + } + + @Override + public RetryVerdict onErrorResponseVerdict( + @NonNull Request request, @NonNull CoordinatorException error, int retryCount) { + RetryVerdict verdict = + error instanceof WriteFailureException || error instanceof ReadFailureException + ? RetryVerdict.RETHROW + : RetryVerdict.RETRY_NEXT; + if (LOG.isTraceEnabled()) { + LOG.trace( + VERDICT_ON_ERROR, + logPrefix, + error.getClass().getSimpleName(), + error.getMessage(), + retryCount, + verdict); + } + return verdict; + } + + @Override + @Deprecated + public RetryDecision onReadTimeout( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + int blockFor, + int received, + boolean dataPresent, + int retryCount) { + throw new UnsupportedOperationException("onReadTimeout"); + } + + @Override + @Deprecated + public RetryDecision onWriteTimeout( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + @NonNull WriteType writeType, + int blockFor, + int received, + int retryCount) { + throw new UnsupportedOperationException("onWriteTimeout"); + } + + @Override + @Deprecated + public RetryDecision onUnavailable( + @NonNull Request request, + @NonNull ConsistencyLevel cl, + int required, + int alive, + int retryCount) { + throw new UnsupportedOperationException("onUnavailable"); + } + + @Override + @Deprecated + public RetryDecision onRequestAborted( + @NonNull Request request, @NonNull Throwable error, int retryCount) { + throw new UnsupportedOperationException("onRequestAborted"); + } + + @Override + @Deprecated + public RetryDecision onErrorResponse( + @NonNull Request request, @NonNull CoordinatorException error, int retryCount) { + throw new UnsupportedOperationException("onErrorResponse"); + } + + @Override + public void close() {} + + private RetryVerdict maybeDowngrade(int alive, ConsistencyLevel current) { + if (alive >= 3) { + return new ConsistencyDowngradingRetryVerdict(ConsistencyLevel.THREE); + } + if (alive == 2) { + return new ConsistencyDowngradingRetryVerdict(ConsistencyLevel.TWO); + } + // JAVA-1005: EACH_QUORUM does not report a global number of alive replicas + // so even if we get 0 alive replicas, there might be a node up in some other datacenter + if (alive == 1 || current.getProtocolCode() == ConsistencyLevel.EACH_QUORUM.getProtocolCode()) { + return new ConsistencyDowngradingRetryVerdict(ConsistencyLevel.ONE); + } + return RetryVerdict.RETHROW; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryVerdict.java b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryVerdict.java new file mode 100644 index 00000000000..cdb3cff4a6a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryVerdict.java @@ -0,0 +1,55 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.retry; + +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.retry.RetryDecision; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; +import com.datastax.oss.driver.api.core.session.Request; +import edu.umd.cs.findbugs.annotations.NonNull; + +public class ConsistencyDowngradingRetryVerdict implements RetryVerdict { + + private final ConsistencyLevel consistencyLevel; + + public ConsistencyDowngradingRetryVerdict(@NonNull ConsistencyLevel consistencyLevel) { + this.consistencyLevel = consistencyLevel; + } + + @NonNull + @Override + public RetryDecision getRetryDecision() { + return RetryDecision.RETRY_SAME; + } + + @NonNull + @Override + public RequestT getRetryRequest(@NonNull RequestT previous) { + if (previous instanceof Statement) { + Statement statement = (Statement) previous; + @SuppressWarnings("unchecked") + RequestT toRetry = (RequestT) statement.setConsistencyLevel(consistencyLevel); + return toRetry; + } + return previous; + } + + @Override + public String toString() { + return getRetryDecision() + " at consistency " + consistencyLevel; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java index b9653bc158a..790dbf2b0aa 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java @@ -83,9 +83,7 @@ public class DefaultRetryPolicy implements RetryPolicy { private final String logPrefix; - public DefaultRetryPolicy( - @SuppressWarnings("unused") DriverContext context, - @SuppressWarnings("unused") String profileName) { + public DefaultRetryPolicy(DriverContext context, String profileName) { this.logPrefix = (context != null ? context.getSessionName() : null) + "|" + profileName; } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryVerdict.java b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryVerdict.java new file mode 100644 index 00000000000..e813b89725a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryVerdict.java @@ -0,0 +1,40 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.retry; + +import com.datastax.oss.driver.api.core.retry.RetryDecision; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DefaultRetryVerdict implements RetryVerdict { + + private final RetryDecision decision; + + public DefaultRetryVerdict(@NonNull RetryDecision decision) { + this.decision = decision; + } + + @NonNull + @Override + public RetryDecision getRetryDecision() { + return decision; + } + + @Override + public String toString() { + return getRetryDecision().name(); + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 3ff88c024b0..e4090ae7481 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -516,7 +516,13 @@ datastax-java-driver { # The class of the policy. If it is not qualified, the driver assumes that it resides in the # package com.datastax.oss.driver.internal.core.retry. # - # The driver provides a single implementation out of the box: DefaultRetryPolicy. + # The driver provides two implementations out of the box: + # + # - DefaultRetryPolicy: the default policy, should almost always be the right choice. + # - ConsistencyDowngradingRetryPolicy: an alternative policy that weakens consistency guarantees + # as a trade-off to maximize the chance of success when retrying. Use with caution. + # + # Refer to the manual to understand how these policies work. # # You can also specify a custom class that implements RetryPolicy and has a public constructor # with two arguments: the DriverContext and a String representing the profile name. diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java new file mode 100644 index 00000000000..da93084804c --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java @@ -0,0 +1,146 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.retry; + +import static com.datastax.oss.driver.api.core.ConsistencyLevel.EACH_QUORUM; +import static com.datastax.oss.driver.api.core.ConsistencyLevel.ONE; +import static com.datastax.oss.driver.api.core.ConsistencyLevel.QUORUM; +import static com.datastax.oss.driver.api.core.ConsistencyLevel.SERIAL; +import static com.datastax.oss.driver.api.core.ConsistencyLevel.THREE; +import static com.datastax.oss.driver.api.core.ConsistencyLevel.TWO; +import static com.datastax.oss.driver.api.core.retry.RetryDecision.IGNORE; +import static com.datastax.oss.driver.api.core.retry.RetryDecision.RETHROW; +import static com.datastax.oss.driver.api.core.retry.RetryDecision.RETRY_NEXT; +import static com.datastax.oss.driver.api.core.retry.RetryDecision.RETRY_SAME; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.BATCH; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.BATCH_LOG; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.CAS; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.CDC; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.COUNTER; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.SIMPLE; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.UNLOGGED_BATCH; +import static com.datastax.oss.driver.api.core.servererrors.WriteType.VIEW; + +import com.datastax.oss.driver.api.core.connection.ClosedConnectionException; +import com.datastax.oss.driver.api.core.connection.HeartbeatException; +import com.datastax.oss.driver.api.core.servererrors.OverloadedException; +import com.datastax.oss.driver.api.core.servererrors.ReadFailureException; +import com.datastax.oss.driver.api.core.servererrors.ServerError; +import com.datastax.oss.driver.api.core.servererrors.TruncateException; +import com.datastax.oss.driver.api.core.servererrors.WriteFailureException; +import com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryPolicy; +import org.junit.Test; + +public class ConsistencyDowngradingRetryPolicyTest extends RetryPolicyTestBase { + + public ConsistencyDowngradingRetryPolicyTest() { + super(new ConsistencyDowngradingRetryPolicy("test")); + } + + @Test + public void should_process_read_timeouts() { + // retry count != 0 + assertOnReadTimeout(QUORUM, 2, 2, false, 1).hasDecision(RETHROW); + // serial CL + assertOnReadTimeout(SERIAL, 2, 2, false, 0).hasDecision(RETHROW); + // received < blockFor + assertOnReadTimeout(QUORUM, 4, 3, true, 0).hasDecision(RETRY_SAME).hasConsistency(THREE); + assertOnReadTimeout(QUORUM, 4, 3, false, 0).hasDecision(RETRY_SAME).hasConsistency(THREE); + assertOnReadTimeout(QUORUM, 3, 2, true, 0).hasDecision(RETRY_SAME).hasConsistency(TWO); + assertOnReadTimeout(QUORUM, 3, 2, false, 0).hasDecision(RETRY_SAME).hasConsistency(TWO); + assertOnReadTimeout(QUORUM, 2, 1, true, 0).hasDecision(RETRY_SAME).hasConsistency(ONE); + assertOnReadTimeout(QUORUM, 2, 1, false, 0).hasDecision(RETRY_SAME).hasConsistency(ONE); + assertOnReadTimeout(EACH_QUORUM, 2, 0, true, 0).hasDecision(RETRY_SAME).hasConsistency(ONE); + assertOnReadTimeout(EACH_QUORUM, 2, 0, false, 0).hasDecision(RETRY_SAME).hasConsistency(ONE); + assertOnReadTimeout(QUORUM, 2, 0, true, 0).hasDecision(RETHROW); + assertOnReadTimeout(QUORUM, 2, 0, false, 0).hasDecision(RETHROW); + // data present + assertOnReadTimeout(QUORUM, 2, 2, false, 0).hasDecision(RETRY_SAME); + assertOnReadTimeout(QUORUM, 2, 2, true, 0).hasDecision(RETHROW); + } + + @Test + public void should_process_write_timeouts() { + // retry count != 0 + assertOnWriteTimeout(QUORUM, BATCH_LOG, 2, 0, 1).hasDecision(RETHROW); + // SIMPLE + assertOnWriteTimeout(QUORUM, SIMPLE, 2, 1, 0).hasDecision(IGNORE); + assertOnWriteTimeout(QUORUM, SIMPLE, 2, 0, 0).hasDecision(RETHROW); + // BATCH + assertOnWriteTimeout(QUORUM, BATCH, 2, 1, 0).hasDecision(IGNORE); + assertOnWriteTimeout(QUORUM, BATCH, 2, 0, 0).hasDecision(RETHROW); + // UNLOGGED_BATCH + assertOnWriteTimeout(QUORUM, UNLOGGED_BATCH, 4, 3, 0) + .hasDecision(RETRY_SAME) + .hasConsistency(THREE); + assertOnWriteTimeout(QUORUM, UNLOGGED_BATCH, 3, 2, 0) + .hasDecision(RETRY_SAME) + .hasConsistency(TWO); + assertOnWriteTimeout(QUORUM, UNLOGGED_BATCH, 2, 1, 0) + .hasDecision(RETRY_SAME) + .hasConsistency(ONE); + assertOnWriteTimeout(EACH_QUORUM, UNLOGGED_BATCH, 2, 0, 0) + .hasDecision(RETRY_SAME) + .hasConsistency(ONE); + assertOnWriteTimeout(QUORUM, UNLOGGED_BATCH, 2, 0, 0).hasDecision(RETHROW); + // BATCH_LOG + assertOnWriteTimeout(QUORUM, BATCH_LOG, 2, 1, 0).hasDecision(RETRY_SAME); + // others + assertOnWriteTimeout(QUORUM, COUNTER, 2, 1, 0).hasDecision(RETHROW); + assertOnWriteTimeout(QUORUM, CAS, 2, 1, 0).hasDecision(RETHROW); + assertOnWriteTimeout(QUORUM, VIEW, 2, 1, 0).hasDecision(RETHROW); + assertOnWriteTimeout(QUORUM, CDC, 2, 1, 0).hasDecision(RETHROW); + } + + @Test + public void should_process_unavailable() { + // retry count != 0 + assertOnUnavailable(QUORUM, 2, 1, 1).hasDecision(RETHROW); + // SERIAL + assertOnUnavailable(SERIAL, 2, 1, 0).hasDecision(RETRY_NEXT); + // downgrade + assertOnUnavailable(QUORUM, 4, 3, 0).hasDecision(RETRY_SAME).hasConsistency(THREE); + assertOnUnavailable(QUORUM, 3, 2, 0).hasDecision(RETRY_SAME).hasConsistency(TWO); + assertOnUnavailable(QUORUM, 2, 1, 0).hasDecision(RETRY_SAME).hasConsistency(ONE); + assertOnUnavailable(EACH_QUORUM, 2, 0, 0).hasDecision(RETRY_SAME).hasConsistency(ONE); + assertOnUnavailable(QUORUM, 2, 0, 0).hasDecision(RETHROW); + } + + @Test + public void should_process_aborted_request() { + assertOnRequestAborted(ClosedConnectionException.class, 0).hasDecision(RETRY_NEXT); + assertOnRequestAborted(ClosedConnectionException.class, 1).hasDecision(RETRY_NEXT); + assertOnRequestAborted(HeartbeatException.class, 0).hasDecision(RETRY_NEXT); + assertOnRequestAborted(HeartbeatException.class, 1).hasDecision(RETRY_NEXT); + assertOnRequestAborted(Throwable.class, 0).hasDecision(RETHROW); + } + + @Test + public void should_process_error_response() { + assertOnErrorResponse(ReadFailureException.class, 0).hasDecision(RETHROW); + assertOnErrorResponse(ReadFailureException.class, 1).hasDecision(RETHROW); + assertOnErrorResponse(WriteFailureException.class, 0).hasDecision(RETHROW); + assertOnErrorResponse(WriteFailureException.class, 1).hasDecision(RETHROW); + assertOnErrorResponse(WriteFailureException.class, 1).hasDecision(RETHROW); + + assertOnErrorResponse(OverloadedException.class, 0).hasDecision(RETRY_NEXT); + assertOnErrorResponse(OverloadedException.class, 1).hasDecision(RETRY_NEXT); + assertOnErrorResponse(ServerError.class, 0).hasDecision(RETRY_NEXT); + assertOnErrorResponse(ServerError.class, 1).hasDecision(RETRY_NEXT); + assertOnErrorResponse(TruncateException.class, 0).hasDecision(RETRY_NEXT); + assertOnErrorResponse(TruncateException.class, 1).hasDecision(RETRY_NEXT); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java index dac4dcafe20..6e68f9fd199 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java @@ -40,48 +40,48 @@ public DefaultRetryPolicyTest() { @Test public void should_process_read_timeouts() { - assertOnReadTimeout(QUORUM, 2, 2, false, 0).isEqualTo(RETRY_SAME); - assertOnReadTimeout(QUORUM, 2, 2, false, 1).isEqualTo(RETHROW); - assertOnReadTimeout(QUORUM, 2, 2, true, 0).isEqualTo(RETHROW); - assertOnReadTimeout(QUORUM, 2, 1, true, 0).isEqualTo(RETHROW); - assertOnReadTimeout(QUORUM, 2, 1, false, 0).isEqualTo(RETHROW); + assertOnReadTimeout(QUORUM, 2, 2, false, 0).hasDecision(RETRY_SAME); + assertOnReadTimeout(QUORUM, 2, 2, false, 1).hasDecision(RETHROW); + assertOnReadTimeout(QUORUM, 2, 2, true, 0).hasDecision(RETHROW); + assertOnReadTimeout(QUORUM, 2, 1, true, 0).hasDecision(RETHROW); + assertOnReadTimeout(QUORUM, 2, 1, false, 0).hasDecision(RETHROW); } @Test public void should_process_write_timeouts() { - assertOnWriteTimeout(QUORUM, BATCH_LOG, 2, 0, 0).isEqualTo(RETRY_SAME); - assertOnWriteTimeout(QUORUM, BATCH_LOG, 2, 0, 1).isEqualTo(RETHROW); - assertOnWriteTimeout(QUORUM, SIMPLE, 2, 0, 0).isEqualTo(RETHROW); + assertOnWriteTimeout(QUORUM, BATCH_LOG, 2, 0, 0).hasDecision(RETRY_SAME); + assertOnWriteTimeout(QUORUM, BATCH_LOG, 2, 0, 1).hasDecision(RETHROW); + assertOnWriteTimeout(QUORUM, SIMPLE, 2, 0, 0).hasDecision(RETHROW); } @Test public void should_process_unavailable() { - assertOnUnavailable(QUORUM, 2, 1, 0).isEqualTo(RETRY_NEXT); - assertOnUnavailable(QUORUM, 2, 1, 1).isEqualTo(RETHROW); + assertOnUnavailable(QUORUM, 2, 1, 0).hasDecision(RETRY_NEXT); + assertOnUnavailable(QUORUM, 2, 1, 1).hasDecision(RETHROW); } @Test public void should_process_aborted_request() { - assertOnRequestAborted(ClosedConnectionException.class, 0).isEqualTo(RETRY_NEXT); - assertOnRequestAborted(ClosedConnectionException.class, 1).isEqualTo(RETRY_NEXT); - assertOnRequestAborted(HeartbeatException.class, 0).isEqualTo(RETRY_NEXT); - assertOnRequestAborted(HeartbeatException.class, 1).isEqualTo(RETRY_NEXT); - assertOnRequestAborted(Throwable.class, 0).isEqualTo(RETHROW); + assertOnRequestAborted(ClosedConnectionException.class, 0).hasDecision(RETRY_NEXT); + assertOnRequestAborted(ClosedConnectionException.class, 1).hasDecision(RETRY_NEXT); + assertOnRequestAborted(HeartbeatException.class, 0).hasDecision(RETRY_NEXT); + assertOnRequestAborted(HeartbeatException.class, 1).hasDecision(RETRY_NEXT); + assertOnRequestAborted(Throwable.class, 0).hasDecision(RETHROW); } @Test public void should_process_error_response() { - assertOnErrorResponse(ReadFailureException.class, 0).isEqualTo(RETHROW); - assertOnErrorResponse(ReadFailureException.class, 1).isEqualTo(RETHROW); - assertOnErrorResponse(WriteFailureException.class, 0).isEqualTo(RETHROW); - assertOnErrorResponse(WriteFailureException.class, 1).isEqualTo(RETHROW); - assertOnErrorResponse(WriteFailureException.class, 1).isEqualTo(RETHROW); + assertOnErrorResponse(ReadFailureException.class, 0).hasDecision(RETHROW); + assertOnErrorResponse(ReadFailureException.class, 1).hasDecision(RETHROW); + assertOnErrorResponse(WriteFailureException.class, 0).hasDecision(RETHROW); + assertOnErrorResponse(WriteFailureException.class, 1).hasDecision(RETHROW); + assertOnErrorResponse(WriteFailureException.class, 1).hasDecision(RETHROW); - assertOnErrorResponse(OverloadedException.class, 0).isEqualTo(RETRY_NEXT); - assertOnErrorResponse(OverloadedException.class, 1).isEqualTo(RETRY_NEXT); - assertOnErrorResponse(ServerError.class, 0).isEqualTo(RETRY_NEXT); - assertOnErrorResponse(ServerError.class, 1).isEqualTo(RETRY_NEXT); - assertOnErrorResponse(TruncateException.class, 0).isEqualTo(RETRY_NEXT); - assertOnErrorResponse(TruncateException.class, 1).isEqualTo(RETRY_NEXT); + assertOnErrorResponse(OverloadedException.class, 0).hasDecision(RETRY_NEXT); + assertOnErrorResponse(OverloadedException.class, 1).hasDecision(RETRY_NEXT); + assertOnErrorResponse(ServerError.class, 0).hasDecision(RETRY_NEXT); + assertOnErrorResponse(ServerError.class, 1).hasDecision(RETRY_NEXT); + assertOnErrorResponse(TruncateException.class, 0).hasDecision(RETRY_NEXT); + assertOnErrorResponse(TruncateException.class, 1).hasDecision(RETRY_NEXT); } } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java b/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java index e24c61e6585..3da2a7cc1b0 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java @@ -22,7 +22,8 @@ import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; import com.datastax.oss.driver.api.core.servererrors.WriteType; import com.datastax.oss.driver.api.core.session.Request; -import org.assertj.core.api.Assert; +import com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryVerdict; +import org.assertj.core.api.AbstractAssert; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -37,37 +38,52 @@ protected RetryPolicyTestBase(RetryPolicy policy) { this.policy = policy; } - protected Assert assertOnReadTimeout( + protected RetryVerdictAssert assertOnReadTimeout( ConsistencyLevel cl, int blockFor, int received, boolean dataPresent, int retryCount) { - return assertThat( - policy - .onReadTimeoutVerdict(request, cl, blockFor, received, dataPresent, retryCount) - .getRetryDecision()); + return new RetryVerdictAssert( + policy.onReadTimeoutVerdict(request, cl, blockFor, received, dataPresent, retryCount)); } - protected Assert assertOnWriteTimeout( + protected RetryVerdictAssert assertOnWriteTimeout( ConsistencyLevel cl, WriteType writeType, int blockFor, int received, int retryCount) { - return assertThat( - policy - .onWriteTimeoutVerdict(request, cl, writeType, blockFor, received, retryCount) - .getRetryDecision()); + return new RetryVerdictAssert( + policy.onWriteTimeoutVerdict(request, cl, writeType, blockFor, received, retryCount)); } - protected Assert assertOnUnavailable( + protected RetryVerdictAssert assertOnUnavailable( ConsistencyLevel cl, int required, int alive, int retryCount) { - return assertThat( - policy.onUnavailableVerdict(request, cl, required, alive, retryCount).getRetryDecision()); + return new RetryVerdictAssert( + policy.onUnavailableVerdict(request, cl, required, alive, retryCount)); } - protected Assert assertOnRequestAborted( + protected RetryVerdictAssert assertOnRequestAborted( Class errorClass, int retryCount) { - return assertThat( - policy.onRequestAbortedVerdict(request, mock(errorClass), retryCount).getRetryDecision()); + return new RetryVerdictAssert( + policy.onRequestAbortedVerdict(request, mock(errorClass), retryCount)); } - protected Assert assertOnErrorResponse( + protected RetryVerdictAssert assertOnErrorResponse( Class errorClass, int retryCount) { - return assertThat( - policy.onErrorResponseVerdict(request, mock(errorClass), retryCount).getRetryDecision()); + return new RetryVerdictAssert( + policy.onErrorResponseVerdict(request, mock(errorClass), retryCount)); + } + + public static class RetryVerdictAssert extends AbstractAssert { + RetryVerdictAssert(RetryVerdict actual) { + super(actual, RetryVerdictAssert.class); + } + + public RetryVerdictAssert hasDecision(RetryDecision decision) { + assertThat(actual.getRetryDecision()).isEqualTo(decision); + return this; + } + + public RetryVerdictAssert hasConsistency(ConsistencyLevel cl) { + assertThat(actual) + .isInstanceOf(ConsistencyDowngradingRetryVerdict.class) + .extracting("consistencyLevel") + .isEqualTo(cl); + return this; + } } } diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/retry/DowngradingRetry.java b/examples/src/main/java/com/datastax/oss/driver/examples/retry/DowngradingRetry.java index c83e2ef2296..2ed917fd449 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/retry/DowngradingRetry.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/retry/DowngradingRetry.java @@ -39,9 +39,15 @@ /** * This example illustrates how to implement a downgrading retry strategy from application code. * - *

    This was provided as a built-in policy in driver 3 ({@code - * DowngradingConsistencyRetryPolicy}), but has been removed from driver 4. See the FAQ. + *

    This strategy is equivalent to the logic implemented by the consistency downgrading retry + * policy, but we think that such a logic should be implemented at application level whenever + * possible. + * + *

    See the FAQ + * and the manual + * section on retries. * *

    Preconditions: * diff --git a/faq/README.md b/faq/README.md index 1b00a971567..842804431a2 100644 --- a/faq/README.md +++ b/faq/README.md @@ -43,24 +43,33 @@ use a fully asynchronous programming model (chaining callbacks instead of blocki At any rate, `CompletionStage` has a `toCompletableFuture()` method. In current JDK versions, every `CompletionStage` is a `CompletableFuture`, so the conversion has no performance overhead. -### Where is `DowngradingConsistencyRetryPolicy`? - -That retry policy was deprecated in driver 3.5.0, and does not exist anymore in 4.0.0. The main -motivation is that this behavior should be the application's concern, not the driver's. - -We recognize that there are use cases where downgrading is good -- for instance, a dashboard -application would present the latest information by reading at QUORUM, but it's acceptable for it to -display stale information by reading at ONE sometimes. - -But APIs provided by the driver should instead encourage idiomatic use of a distributed system like -Apache Cassandra, and a downgrading policy works against this. It suggests that an anti-pattern such -as "try to read at QUORUM, but fall back to ONE if that fails" is a good idea in general use cases, -when in reality it provides no better consistency guarantees than working directly at ONE, but with -higher latencies. - -We therefore urge users to carefully choose upfront the consistency level that works best for their -use cases. If there is a legitimate reason to downgrade and retry, that should be handled by the -application code. +### Where is `DowngradingConsistencyRetryPolicy` from driver 3? + +**As of driver 4.10, this retry policy was made available again as a built-in alternative to the +default retry policy**: see the [manual](../manual/core/retries) to understand how to use it. +For versions between 4.0 and 4.9 inclusive, there is no built-in equivalent of driver 3 +`DowngradingConsistencyRetryPolicy`. + +That retry policy was indeed removed in driver 4.0.0. The main motivation is that this behavior +should be the application's concern, not the driver's. APIs provided by the driver should instead +encourage idiomatic use of a distributed system like Apache Cassandra, and a downgrading policy +works against this. It suggests that an anti-pattern such as "try to read at QUORUM, but fall back +to ONE if that fails" is a good idea in general use cases, when in reality it provides no better +consistency guarantees than working directly at ONE, but with higher latencies. + +However, we recognize that there are use cases where downgrading is good -- for instance, a +dashboard application would present the latest information by reading at QUORUM, but it's acceptable +for it to display stale information by reading at ONE sometimes. + +Thanks to [JAVA-2900], an equivalent retry policy with downgrading behavior was re-introduced in +driver 4.10. Nonetheless, we urge users to avoid using it unless strictly required, and instead, +carefully choose upfront the consistency level that works best for their use cases. Even if there +is a legitimate reason to downgrade and retry, that should be preferably handled by the application +code. An example of downgrading retries implemented at application level can be found in the driver +[examples repository]. + +[JAVA-2900]: https://datastax-oss.atlassian.net/browse/JAVA-2900 +[examples repository]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/retry/DowngradingRetry.java ### I want to set a date on a bound statement, where did `setTimestamp()` go? diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java new file mode 100644 index 00000000000..2a34a7cd639 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java @@ -0,0 +1,1326 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.retry; + +import static com.datastax.oss.simulacron.common.codec.WriteType.BATCH_LOG; +import static com.datastax.oss.simulacron.common.codec.WriteType.UNLOGGED_BATCH; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.closeConnection; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.readFailure; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.readTimeout; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.serverError; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.unavailable; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.writeFailure; +import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.writeTimeout; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.after; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.connection.ClosedConnectionException; +import com.datastax.oss.driver.api.core.cql.ExecutionInfo; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; +import com.datastax.oss.driver.api.core.servererrors.DefaultWriteType; +import com.datastax.oss.driver.api.core.servererrors.ReadFailureException; +import com.datastax.oss.driver.api.core.servererrors.ReadTimeoutException; +import com.datastax.oss.driver.api.core.servererrors.ServerError; +import com.datastax.oss.driver.api.core.servererrors.UnavailableException; +import com.datastax.oss.driver.api.core.servererrors.WriteFailureException; +import com.datastax.oss.driver.api.core.servererrors.WriteTimeoutException; +import com.datastax.oss.driver.api.testinfra.loadbalancing.SortingLoadBalancingPolicy; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.api.testinfra.simulacron.QueryCounter; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryPolicy; +import com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryVerdict; +import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import com.datastax.oss.simulacron.common.codec.ConsistencyLevel; +import com.datastax.oss.simulacron.common.codec.WriteType; +import com.datastax.oss.simulacron.common.request.Query; +import com.datastax.oss.simulacron.common.request.Request; +import com.datastax.oss.simulacron.common.stubbing.CloseType; +import com.datastax.oss.simulacron.common.stubbing.DisconnectAction; +import com.datastax.oss.simulacron.server.BoundNode; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import java.net.SocketAddress; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; + +@RunWith(DataProviderRunner.class) +public class ConsistencyDowngradingRetryPolicyIT { + + @ClassRule + public static final SimulacronRule SIMULACRON_RULE = + new SimulacronRule(ClusterSpec.builder().withNodes(3)); + + public @Rule SessionRule sessionRule = + SessionRule.builder(SIMULACRON_RULE) + .withConfigLoader( + SessionUtils.configLoaderBuilder() + .withBoolean(DefaultDriverOption.REQUEST_DEFAULT_IDEMPOTENCE, true) + .withClass( + DefaultDriverOption.RETRY_POLICY_CLASS, + ConsistencyDowngradingRetryPolicy.class) + .withClass( + DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS, + SortingLoadBalancingPolicy.class) + .build()) + .build(); + + private static final String QUERY_STR = "irrelevant"; + + private static final Request QUERY_LOCAL_QUORUM = + new Query(QUERY_STR, ImmutableList.of(ConsistencyLevel.LOCAL_QUORUM), null, null); + + private static final Request QUERY_ONE = + new Query(QUERY_STR, ImmutableList.of(ConsistencyLevel.ONE), null, null); + + private static final Request QUERY_LOCAL_SERIAL = + new Query(QUERY_STR, ImmutableList.of(ConsistencyLevel.LOCAL_SERIAL), null, null); + + private static final SimpleStatement STATEMENT_LOCAL_QUORUM = + SimpleStatement.builder(QUERY_STR) + .setConsistencyLevel(DefaultConsistencyLevel.LOCAL_QUORUM) + .build(); + + private static final SimpleStatement STATEMENT_LOCAL_SERIAL = + SimpleStatement.builder(QUERY_STR) + .setConsistencyLevel(DefaultConsistencyLevel.LOCAL_SERIAL) + .build(); + + @SuppressWarnings("deprecation") + private final QueryCounter localQuorumCounter = + QueryCounter.builder(SIMULACRON_RULE.cluster()) + .withFilter( + (l) -> + l.getQuery().equals(QUERY_STR) + && l.getConsistency().equals(ConsistencyLevel.LOCAL_QUORUM)) + .build(); + + @SuppressWarnings("deprecation") + private final QueryCounter oneCounter = + QueryCounter.builder(SIMULACRON_RULE.cluster()) + .withFilter( + (l) -> + l.getQuery().equals(QUERY_STR) && l.getConsistency().equals(ConsistencyLevel.ONE)) + .build(); + + @SuppressWarnings("deprecation") + private final QueryCounter localSerialCounter = + QueryCounter.builder(SIMULACRON_RULE.cluster()) + .withFilter( + (l) -> + l.getQuery().equals(QUERY_STR) + && l.getConsistency().equals(ConsistencyLevel.LOCAL_SERIAL)) + .build(); + + private ArgumentCaptor loggingEventCaptor; + private Appender appender; + private Logger logger; + private Level oldLevel; + private String logPrefix; + private BoundNode node0; + private BoundNode node1; + + @Before + public void setup() { + loggingEventCaptor = ArgumentCaptor.forClass(ILoggingEvent.class); + @SuppressWarnings("unchecked") + Appender appender = (Appender) mock(Appender.class); + this.appender = appender; + logger = (Logger) LoggerFactory.getLogger(ConsistencyDowngradingRetryPolicy.class); + oldLevel = logger.getLevel(); + logger.setLevel(Level.TRACE); + logger.addAppender(appender); + // the log prefix we expect in retry logging messages. + logPrefix = sessionRule.session().getName() + "|default"; + // clear activity logs and primes between tests since simulacron instance is shared. + SIMULACRON_RULE.cluster().clearLogs(); + SIMULACRON_RULE.cluster().clearPrimes(true); + node0 = SIMULACRON_RULE.cluster().node(0); + node1 = SIMULACRON_RULE.cluster().node(1); + } + + @After + public void teardown() { + logger.detachAppender(appender); + logger.setLevel(oldLevel); + } + + @Test + public void should_rethrow_on_read_timeout_when_enough_responses_and_data_present() { + // given a node that will respond to query with a read timeout where data is present and enough + // replicas replied. + node0.prime( + when(QUERY_LOCAL_QUORUM).then(readTimeout(ConsistencyLevel.LOCAL_QUORUM, 2, 2, true))); + + try { + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("expected a ReadTimeoutException"); + } catch (ReadTimeoutException rte) { + // then an exception should have been thrown + assertThat(rte) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (timeout while waiting for repair of inconsistent replica)"); + assertThat(rte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rte.getReceived()).isEqualTo(2); + assertThat(rte.getBlockFor()).isEqualTo(2); + assertThat(rte.wasDataPresent()).isTrue(); + // should not have been retried + List> errors = rte.getExecutionInfo().getErrors(); + assertThat(errors).isEmpty(); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(rte.getExecutionInfo())).isEqualTo(node0.getAddress()); + } + + // there should have been no retry. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(0); + + // expect 1 message: RETHROW + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(1); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 2, + true, + 0, + RetryVerdict.RETHROW)); + } + + @Test + public void should_retry_on_same_on_read_timeout_when_enough_responses_but_data_not_present() { + // given a node that will respond to query with a read timeout where data is present. + node0.prime( + when(QUERY_LOCAL_QUORUM).then(readTimeout(ConsistencyLevel.LOCAL_QUORUM, 2, 2, false))); + + try { + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("expected a ReadTimeoutException"); + } catch (ReadTimeoutException rte) { + // then an exception should have been thrown + assertThat(rte) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (the replica queried for data didn't respond)"); + assertThat(rte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rte.getReceived()).isEqualTo(2); + assertThat(rte.getBlockFor()).isEqualTo(2); + assertThat(rte.wasDataPresent()).isFalse(); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(rte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM as well + List> errors = rte.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + ReadTimeoutException.class, + rte1 -> { + assertThat(rte1) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (the replica queried for data didn't respond)"); + assertThat(rte1.getConsistencyLevel()) + .isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rte1.getReceived()).isEqualTo(2); + assertThat(rte1.getBlockFor()).isEqualTo(2); + assertThat(rte1.wasDataPresent()).isFalse(); + }); + } + + // there should have been a retry, and it should have been executed on the same host, + // with same consistency. + localQuorumCounter.assertTotalCount(2); + localQuorumCounter.assertNodeCounts(2, 0, 0); + oneCounter.assertTotalCount(0); + + // expect 2 messages: RETRY_SAME, then RETHROW + verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(2); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 2, + false, + 0, + RetryVerdict.RETRY_SAME)); + assertThat(loggedEvents.get(1).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 2, + false, + 1, + RetryVerdict.RETHROW)); + } + + @Test + public void should_downgrade_on_read_timeout_when_not_enough_responses() { + // given a node that will respond to a query with a read timeout where 2 out of 3 responses are + // received. In this case, digest requests succeeded, but not the data request. + node0.prime( + when(QUERY_LOCAL_QUORUM).then(readTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, true))); + + ResultSet rs = sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(rs.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM + List> errors = rs.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + ReadTimeoutException.class, + rte -> { + assertThat(rte) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (2 responses were required but only 1 replica responded)"); + assertThat(rte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rte.getReceived()).isEqualTo(1); + assertThat(rte.getBlockFor()).isEqualTo(2); + assertThat(rte.wasDataPresent()).isTrue(); + }); + + // should have succeeded in second attempt at ONE + Statement request = (Statement) rs.getExecutionInfo().getRequest(); + assertThat(request.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ONE); + + // there should have been a retry, and it should have been executed on the same host, + // but with consistency ONE. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(1); + oneCounter.assertNodeCounts(1, 0, 0); + + // expect 1 message: RETRY_SAME with ONE + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(1); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 1, + true, + 0, + new ConsistencyDowngradingRetryVerdict(DefaultConsistencyLevel.ONE))); + } + + @Test + public void should_retry_on_read_timeout_when_enough_responses_and_data_not_present() { + // given a node that will respond to a query with a read timeout where 3 out of 3 responses are + // received, but data is not present. + node0.prime( + when(QUERY_LOCAL_QUORUM).then(readTimeout(ConsistencyLevel.LOCAL_QUORUM, 2, 2, false))); + + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected a ReadTimeoutException"); + } catch (ReadTimeoutException rte) { + // then a read timeout exception is thrown. + assertThat(rte) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (the replica queried for data didn't respond)"); + assertThat(rte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rte.getReceived()).isEqualTo(2); + assertThat(rte.getBlockFor()).isEqualTo(2); + assertThat(rte.wasDataPresent()).isFalse(); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(rte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM + List> errors = rte.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + ReadTimeoutException.class, + rte1 -> { + assertThat(rte) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (the replica queried for data didn't respond)"); + assertThat(rte1.getConsistencyLevel()) + .isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rte1.getReceived()).isEqualTo(2); + assertThat(rte1.getBlockFor()).isEqualTo(2); + assertThat(rte1.wasDataPresent()).isFalse(); + }); + } + + // there should have been a retry, and it should have been executed on the same host. + localQuorumCounter.assertTotalCount(2); + localQuorumCounter.assertNodeCounts(2, 0, 0); + oneCounter.assertTotalCount(0); + + // verify log events were emitted as expected + verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(2); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 2, + false, + 0, + RetryVerdict.RETRY_SAME)); + assertThat(loggedEvents.get(1).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 2, + false, + 1, + RetryVerdict.RETHROW)); + } + + @Test + public void should_only_retry_once_on_read_type() { + // given a node that will respond to a query with a read timeout at 2 CLs. + node0.prime( + when(QUERY_LOCAL_QUORUM).then(readTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, true))); + node0.prime(when(QUERY_ONE).then(readTimeout(ConsistencyLevel.ONE, 0, 1, false))); + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected a ReadTimeoutException"); + } catch (ReadTimeoutException wte) { + // then a read timeout exception is thrown + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during read query at consistency ONE (1 responses were required but only 0 replica responded)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ONE); + assertThat(wte.getReceived()).isEqualTo(0); + assertThat(wte.getBlockFor()).isEqualTo(1); + assertThat(wte.wasDataPresent()).isFalse(); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(wte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM as well + List> errors = wte.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + ReadTimeoutException.class, + wte1 -> { + assertThat(wte1) + .hasMessageContaining( + "Cassandra timeout during read query at consistency LOCAL_QUORUM (2 responses were required but only 1 replica responded)"); + assertThat(wte1.getConsistencyLevel()) + .isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte1.getReceived()).isEqualTo(1); + assertThat(wte1.getBlockFor()).isEqualTo(2); + assertThat(wte1.wasDataPresent()).isTrue(); + }); + } + + // should have been retried on same host, but at consistency ONE. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(1); + oneCounter.assertNodeCounts(1, 0, 0); + + // verify log events were emitted as expected + verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(2); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 1, + true, + 0, + new ConsistencyDowngradingRetryVerdict(DefaultConsistencyLevel.ONE))); + assertThat(loggedEvents.get(1).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_READ_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.ONE, + 1, + 0, + false, + 1, + RetryVerdict.RETHROW)); + } + + @Test + public void should_retry_on_write_timeout_if_write_type_batch_log() { + // given a node that will respond to query with a write timeout with write type of batch log. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, BATCH_LOG))); + + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("WriteTimeoutException expected"); + } catch (WriteTimeoutException wte) { + // then a write timeout exception is thrown + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during BATCH_LOG write query at consistency LOCAL_QUORUM (2 replica were required but only 1 acknowledged the write)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte.getReceived()).isEqualTo(1); + assertThat(wte.getBlockFor()).isEqualTo(2); + assertThat(wte.getWriteType()).isEqualTo(DefaultWriteType.BATCH_LOG); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(wte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM as well + List> errors = wte.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + WriteTimeoutException.class, + wte1 -> { + assertThat(wte1) + .hasMessageContaining( + "Cassandra timeout during BATCH_LOG write query at consistency LOCAL_QUORUM (2 replica were required but only 1 acknowledged the write)"); + assertThat(wte1.getConsistencyLevel()) + .isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte1.getReceived()).isEqualTo(1); + assertThat(wte1.getBlockFor()).isEqualTo(2); + assertThat(wte1.getWriteType()).isEqualTo(DefaultWriteType.BATCH_LOG); + }); + } + + // there should have been a retry, and it should have been executed on the same host. + localQuorumCounter.assertTotalCount(2); + localQuorumCounter.assertNodeCounts(2, 0, 0); + oneCounter.assertTotalCount(0); + + // verify log events were emitted as expected + verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(2); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + DefaultWriteType.BATCH_LOG, + 2, + 1, + 0, + RetryVerdict.RETRY_SAME)); + assertThat(loggedEvents.get(1).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + DefaultWriteType.BATCH_LOG, + 2, + 1, + 1, + RetryVerdict.RETHROW)); + } + + @Test + public void should_not_retry_on_write_timeout_if_write_type_batch_log_but_non_idempotent() { + // given a node that will respond to query with a write timeout with write type of batch log. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, BATCH_LOG))); + + try { + // when executing a non-idempotent query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM.setIdempotent(false)); + fail("WriteTimeoutException expected"); + } catch (WriteTimeoutException wte) { + // then a write timeout exception is thrown + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during BATCH_LOG write query at consistency LOCAL_QUORUM (2 replica were required but only 1 acknowledged the write)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte.getReceived()).isEqualTo(1); + assertThat(wte.getBlockFor()).isEqualTo(2); + assertThat(wte.getWriteType()).isEqualTo(DefaultWriteType.BATCH_LOG); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(wte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should not have been retried + List> errors = wte.getExecutionInfo().getErrors(); + assertThat(errors).isEmpty(); + } + + // should not have been retried. + localQuorumCounter.assertTotalCount(1); + oneCounter.assertTotalCount(0); + + // expect no logging messages since there was no retry + verify(appender, after(500).times(0)).doAppend(any(ILoggingEvent.class)); + } + + @DataProvider({"SIMPLE,SIMPLE", "BATCH,BATCH"}) + @Test + public void should_ignore_on_write_timeout_if_write_type_ignorable_and_at_least_one_ack_received( + WriteType writeType, DefaultWriteType driverWriteType) { + // given a node that will respond to query with a write timeout with write type that is either + // SIMPLE or BATCH. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, writeType))); + + // when executing a query. + ResultSet rs = sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + + // should have ignored the write timeout + assertThat(rs.all()).isEmpty(); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(rs.getExecutionInfo())).isEqualTo(node0.getAddress()); + assertThat(rs.getExecutionInfo().getErrors()).isEmpty(); + + // should not have been retried. + localQuorumCounter.assertTotalCount(1); + oneCounter.assertTotalCount(0); + + // verify log event was emitted for each host as expected + verify(appender, after(500)).doAppend(loggingEventCaptor.capture()); + // final log message should have 2 retries + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + driverWriteType, + 2, + 1, + 0, + RetryVerdict.IGNORE)); + } + + @DataProvider({"SIMPLE,SIMPLE", "BATCH,BATCH"}) + @Test + public void should_throw_on_write_timeout_if_write_type_ignorable_but_no_ack_received( + WriteType writeType, DefaultWriteType driverWriteType) { + // given a node that will respond to query with a write timeout with write type that is either + // SIMPLE or BATCH. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 0, 2, writeType))); + + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("WriteTimeoutException expected"); + } catch (WriteTimeoutException wte) { + // then a write timeout exception is thrown + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during " + + driverWriteType + + " write query at consistency LOCAL_QUORUM (2 replica were required but only 0 acknowledged the write)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte.getReceived()).isEqualTo(0); + assertThat(wte.getBlockFor()).isEqualTo(2); + assertThat(wte.getWriteType()).isEqualTo(driverWriteType); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(wte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should not have been retried + List> errors = wte.getExecutionInfo().getErrors(); + assertThat(errors).isEmpty(); + } + + // should not have been retried. + localQuorumCounter.assertTotalCount(1); + oneCounter.assertTotalCount(0); + + // verify log event was emitted for each host as expected + verify(appender, after(500)).doAppend(loggingEventCaptor.capture()); + // final log message should have 2 retries + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + driverWriteType, + 2, + 0, + 0, + RetryVerdict.RETHROW)); + } + + @Test + public void should_downgrade_on_write_timeout_if_write_type_unlogged_batch() { + // given a node that will respond to query with a write timeout with write type of batch log. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, UNLOGGED_BATCH))); + + // when executing a query. + ResultSet rs = sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(rs.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM + List> errors = rs.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + WriteTimeoutException.class, + wte -> { + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during UNLOGGED_BATCH write query at consistency LOCAL_QUORUM (2 replica were required but only 1 acknowledged the write)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte.getReceived()).isEqualTo(1); + assertThat(wte.getBlockFor()).isEqualTo(2); + assertThat(wte.getWriteType()).isEqualTo(DefaultWriteType.UNLOGGED_BATCH); + }); + + // should have succeeded in second attempt at ONE + Statement request = (Statement) rs.getExecutionInfo().getRequest(); + assertThat(request.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ONE); + + // there should have been a retry, and it should have been executed on the same host, + // but at consistency ONE. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(1); + oneCounter.assertNodeCounts(1, 0, 0); + + // verify 1 log event was emitted as expected + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(1); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + DefaultWriteType.UNLOGGED_BATCH, + 2, + 1, + 0, + new ConsistencyDowngradingRetryVerdict(DefaultConsistencyLevel.ONE))); + } + + @Test + public void + should_not_downgrade_on_write_timeout_if_write_type_unlogged_batch_and_non_idempotent() { + // given a node that will respond to query with a write timeout with write type UNLOGGED_BATCH. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, UNLOGGED_BATCH))); + + try { + // when executing a non-idempotent query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM.setIdempotent(false)); + fail("WriteTimeoutException expected"); + } catch (WriteTimeoutException wte) { + // then a write timeout exception is thrown + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during UNLOGGED_BATCH write query at consistency LOCAL_QUORUM (2 replica were required but only 1 acknowledged the write)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte.getReceived()).isEqualTo(1); + assertThat(wte.getBlockFor()).isEqualTo(2); + assertThat(wte.getWriteType()).isEqualTo(DefaultWriteType.UNLOGGED_BATCH); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(wte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should not have been retried + List> errors = wte.getExecutionInfo().getErrors(); + assertThat(errors).isEmpty(); + } + + // should not have been retried. + localQuorumCounter.assertTotalCount(1); + oneCounter.assertTotalCount(0); + + // expect no logging messages since there was no retry + verify(appender, after(500).times(0)).doAppend(any(ILoggingEvent.class)); + } + + @Test + public void should_only_retry_once_on_write_type() { + // given a node that will respond to a query with a write timeout at 2 CLs. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(writeTimeout(ConsistencyLevel.LOCAL_QUORUM, 1, 2, UNLOGGED_BATCH))); + node0.prime(when(QUERY_ONE).then(writeTimeout(ConsistencyLevel.ONE, 0, 1, UNLOGGED_BATCH))); + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected a WriteTimeoutException"); + } catch (WriteTimeoutException wte) { + // then a write timeout exception is thrown + assertThat(wte) + .hasMessageContaining( + "Cassandra timeout during UNLOGGED_BATCH write query at consistency ONE (1 replica were required but only 0 acknowledged the write)"); + assertThat(wte.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ONE); + assertThat(wte.getReceived()).isEqualTo(0); + assertThat(wte.getBlockFor()).isEqualTo(1); + assertThat(wte.getWriteType()).isEqualTo(DefaultWriteType.UNLOGGED_BATCH); + // the host that returned the response should be node 0. + assertThat(coordinatorAddress(wte.getExecutionInfo())).isEqualTo(node0.getAddress()); + // should have failed at first attempt at LOCAL_QUORUM as well + List> errors = wte.getExecutionInfo().getErrors(); + assertThat(errors).hasSize(1); + Entry error = errors.get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + WriteTimeoutException.class, + wte1 -> { + assertThat(wte1) + .hasMessageContaining( + "Cassandra timeout during UNLOGGED_BATCH write query at consistency LOCAL_QUORUM (2 replica were required but only 1 acknowledged the write)"); + assertThat(wte1.getConsistencyLevel()) + .isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wte1.getReceived()).isEqualTo(1); + assertThat(wte1.getBlockFor()).isEqualTo(2); + assertThat(wte1.getWriteType()).isEqualTo(DefaultWriteType.UNLOGGED_BATCH); + }); + } + + // should have been retried on same host, but at consistency ONE. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(1); + oneCounter.assertNodeCounts(1, 0, 0); + + // verify log events were emitted as expected + verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(2); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + DefaultWriteType.UNLOGGED_BATCH, + 2, + 1, + 0, + new ConsistencyDowngradingRetryVerdict(DefaultConsistencyLevel.ONE))); + assertThat(loggedEvents.get(1).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_WRITE_TIMEOUT, + logPrefix, + DefaultConsistencyLevel.ONE, + DefaultWriteType.UNLOGGED_BATCH, + 1, + 0, + 1, + RetryVerdict.RETHROW)); + } + + @Test + public void should_retry_on_next_host_on_unavailable_if_LWT() { + // given a node that will respond to a query with an unavailable. + node0.prime(when(QUERY_LOCAL_SERIAL).then(unavailable(ConsistencyLevel.LOCAL_SERIAL, 2, 1))); + + // when executing a query. + ResultSet result = sessionRule.session().execute(STATEMENT_LOCAL_SERIAL); + // then we should get a response, and the host that returned the response should be node 1. + assertThat(coordinatorAddress(result.getExecutionInfo())).isEqualTo(node1.getAddress()); + // the execution info on the result set indicates there was + // an error on the host that received the query. + assertThat(result.getExecutionInfo().getErrors()).hasSize(1); + Map.Entry error = result.getExecutionInfo().getErrors().get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + UnavailableException.class, + ue -> { + assertThat(ue) + .hasMessageContaining( + "Not enough replicas available for query at consistency LOCAL_SERIAL (2 required but only 1 alive)"); + assertThat(ue.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_SERIAL); + assertThat(ue.getAlive()).isEqualTo(1); + assertThat(ue.getRequired()).isEqualTo(2); + }); + + // should have been retried on another host. + localSerialCounter.assertTotalCount(2); + localSerialCounter.assertNodeCounts(1, 1, 0); + localQuorumCounter.assertTotalCount(0); + oneCounter.assertTotalCount(0); + + // verify log event was emitted as expected + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_UNAVAILABLE, + logPrefix, + DefaultConsistencyLevel.LOCAL_SERIAL, + 2, + 1, + 0, + RetryVerdict.RETRY_NEXT)); + } + + @Test + public void should_downgrade_on_unavailable() { + // given a node that will respond to a query with an unavailable. + node0.prime(when(QUERY_LOCAL_QUORUM).then(unavailable(ConsistencyLevel.LOCAL_QUORUM, 2, 1))); + + // when executing a query. + ResultSet rs = sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + // then we should get a response, and the host that returned the response should be node 0. + assertThat(coordinatorAddress(rs.getExecutionInfo())).isEqualTo(node0.getAddress()); + // the execution info on the result set indicates there was + // an error on the host that received the query. + assertThat(rs.getExecutionInfo().getErrors()).hasSize(1); + Map.Entry error = rs.getExecutionInfo().getErrors().get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + UnavailableException.class, + ue -> { + assertThat(ue) + .hasMessageContaining( + "Not enough replicas available for query at consistency LOCAL_QUORUM (2 required but only 1 alive)"); + assertThat(ue.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(ue.getAlive()).isEqualTo(1); + assertThat(ue.getRequired()).isEqualTo(2); + }); + + // should have succeeded in second attempt at ONE + Statement request = (Statement) rs.getExecutionInfo().getRequest(); + assertThat(request.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ONE); + + // should have been retried on the same host, but at ONE. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(1); + oneCounter.assertNodeCounts(1, 0, 0); + + // verify log event was emitted as expected + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_UNAVAILABLE, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 1, + 0, + new ConsistencyDowngradingRetryVerdict(DefaultConsistencyLevel.ONE))); + } + + @Test + public void should_only_retry_once_on_unavailable() { + // given two nodes that will respond to a query with an unavailable. + node0.prime(when(QUERY_LOCAL_QUORUM).then(unavailable(ConsistencyLevel.LOCAL_QUORUM, 2, 1))); + node0.prime(when(QUERY_ONE).then(unavailable(ConsistencyLevel.ONE, 1, 0))); + + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected an UnavailableException"); + } catch (UnavailableException ue) { + // then we should get an unavailable exception with the host being node 1 (since it was second + // tried). + assertThat(ue) + .hasMessageContaining( + "Not enough replicas available for query at consistency ONE (1 required but only 0 alive)"); + assertThat(ue.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ONE); + assertThat(ue.getRequired()).isEqualTo(1); + assertThat(ue.getAlive()).isEqualTo(0); + assertThat(ue.getExecutionInfo().getErrors()).hasSize(1); + Map.Entry error = ue.getExecutionInfo().getErrors().get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()) + .isInstanceOfSatisfying( + UnavailableException.class, + ue1 -> { + assertThat(ue1) + .hasMessageContaining( + "Not enough replicas available for query at consistency LOCAL_QUORUM (2 required but only 1 alive)"); + assertThat(ue1.getConsistencyLevel()) + .isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(ue1.getRequired()).isEqualTo(2); + assertThat(ue1.getAlive()).isEqualTo(1); + }); + } + + // should have been retried on same host, but at ONE. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(1); + oneCounter.assertNodeCounts(1, 0, 0); + + // verify log events were emitted as expected + verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + List loggedEvents = loggingEventCaptor.getAllValues(); + assertThat(loggedEvents).hasSize(2); + assertThat(loggedEvents.get(0).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_UNAVAILABLE, + logPrefix, + DefaultConsistencyLevel.LOCAL_QUORUM, + 2, + 1, + 0, + new ConsistencyDowngradingRetryVerdict(DefaultConsistencyLevel.ONE))); + assertThat(loggedEvents.get(1).getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_UNAVAILABLE, + logPrefix, + DefaultConsistencyLevel.ONE, + 1, + 0, + 1, + RetryVerdict.RETHROW)); + } + + @Test + public void should_retry_on_next_host_on_connection_error_if_idempotent() { + // given a node that will close its connection as result of receiving a query. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(closeConnection(DisconnectAction.Scope.CONNECTION, CloseType.DISCONNECT))); + + // when executing a query. + ResultSet result = sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + // then we should get a response, and the execution info on the result set indicates there was + // an error on the host that received the query. + assertThat(result.getExecutionInfo().getErrors()).hasSize(1); + Map.Entry error = result.getExecutionInfo().getErrors().get(0); + assertThat(error.getKey().getEndPoint().resolve()).isEqualTo(node0.getAddress()); + assertThat(error.getValue()).isInstanceOf(ClosedConnectionException.class); + // the host that returned the response should be node 1. + assertThat(coordinatorAddress(result.getExecutionInfo())).isEqualTo(node1.getAddress()); + + // should have been retried. + localQuorumCounter.assertTotalCount(2); + // expected query on node 0, and retry on node 2. + localQuorumCounter.assertNodeCounts(1, 1, 0); + oneCounter.assertTotalCount(0); + + // verify log event was emitted as expected + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_ABORTED, + logPrefix, + ClosedConnectionException.class.getSimpleName(), + error.getValue().getMessage(), + 0, + RetryVerdict.RETRY_NEXT)); + } + + @Test + public void should_keep_retrying_on_next_host_on_connection_error() { + // given a request for which every node will close its connection upon receiving it. + SIMULACRON_RULE + .cluster() + .prime( + when(QUERY_LOCAL_QUORUM) + .then(closeConnection(DisconnectAction.Scope.CONNECTION, CloseType.DISCONNECT))); + + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("AllNodesFailedException expected"); + } catch (AllNodesFailedException ex) { + // then an AllNodesFailedException should be raised indicating that all nodes failed the + // request. + assertThat(ex.getAllErrors()).hasSize(3); + } + + // should have been tried on all nodes. + // should have been retried. + localQuorumCounter.assertTotalCount(3); + // expected query on node 0, and retry on node 2 and 3. + localQuorumCounter.assertNodeCounts(1, 1, 1); + oneCounter.assertTotalCount(0); + + // verify log event was emitted for each host as expected + verify(appender, after(500).times(3)).doAppend(loggingEventCaptor.capture()); + // final log message should have 2 retries + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_ABORTED, + logPrefix, + ClosedConnectionException.class.getSimpleName(), + "Lost connection to remote peer", + 2, + RetryVerdict.RETRY_NEXT)); + } + + @Test + public void should_not_retry_on_connection_error_if_non_idempotent() { + // given a node that will close its connection as result of receiving a query. + node0.prime( + when(QUERY_LOCAL_QUORUM) + .then(closeConnection(DisconnectAction.Scope.CONNECTION, CloseType.DISCONNECT))); + + try { + // when executing a non-idempotent query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM.setIdempotent(false)); + fail("ClosedConnectionException expected"); + } catch (ClosedConnectionException ex) { + // then a ClosedConnectionException should be raised, indicating that the connection closed + // while handling the request on that node. + // this clearly indicates that the request wasn't retried. + // Exception should indicate that node 0 was the failing node. + // FIXME JAVA-2908 + // Node coordinator = ex.getExecutionInfo().getCoordinator(); + // assertThat(coordinator).isNotNull(); + // assertThat(coordinator.getEndPoint().resolve()) + // .isEqualTo(SIMULACRON_RULE.cluster().node(0).getAddress()); + } + + // should not have been retried. + localQuorumCounter.assertTotalCount(1); + oneCounter.assertTotalCount(0); + + // expect no logging messages since there was no retry + verify(appender, after(500).times(0)).doAppend(any(ILoggingEvent.class)); + } + + @Test + public void should_keep_retrying_on_next_host_on_error_response() { + // given every node responding with a server error. + SIMULACRON_RULE + .cluster() + .prime(when(QUERY_LOCAL_QUORUM).then(serverError("this is a server error"))); + + try { + // when executing a query. + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected an AllNodesFailedException"); + } catch (AllNodesFailedException e) { + // then we should get an all nodes failed exception, indicating the query was tried each node. + assertThat(e.getAllErrors()).hasSize(3); + for (List nodeErrors : e.getAllErrors().values()) { + for (Throwable nodeError : nodeErrors) { + assertThat(nodeError).isInstanceOf(ServerError.class); + assertThat(nodeError).hasMessage("this is a server error"); + } + } + } + + // should have been tried on all nodes. + localQuorumCounter.assertTotalCount(3); + localQuorumCounter.assertNodeCounts(1, 1, 1); + + // verify log event was emitted for each host as expected + verify(appender, after(500).times(3)).doAppend(loggingEventCaptor.capture()); + // final log message should have 2 retries + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_ERROR, + logPrefix, + ServerError.class.getSimpleName(), + "this is a server error", + 2, + RetryVerdict.RETRY_NEXT)); + } + + @Test + public void should_not_retry_on_next_host_on_error_response_if_write_failure() { + // given every node responding with a write failure. + SIMULACRON_RULE + .cluster() + .prime( + when(QUERY_LOCAL_QUORUM) + .then( + writeFailure( + ConsistencyLevel.LOCAL_QUORUM, 1, 2, ImmutableMap.of(), WriteType.SIMPLE))); + try { + // when executing a query + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected a WriteFailureException"); + } catch (WriteFailureException wfe) { + // then we should get a write failure exception with the host being node 1 (since it was + // second tried). + assertThat(wfe) + .hasMessageContaining( + "Cassandra failure during write query at consistency LOCAL_QUORUM (2 responses were required but only 1 replica responded, 0 failed)"); + assertThat(wfe.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(wfe.getBlockFor()).isEqualTo(2); + assertThat(wfe.getReceived()).isEqualTo(1); + assertThat(wfe.getWriteType()).isEqualTo(DefaultWriteType.SIMPLE); + assertThat(wfe.getReasonMap()).isEmpty(); + } + + // should only have been tried on first node. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(0); + + // verify log event was emitted as expected + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_ERROR, + logPrefix, + WriteFailureException.class.getSimpleName(), + "Cassandra failure during write query at consistency LOCAL_QUORUM (2 responses were required but only 1 replica responded, 0 failed)", + 0, + RetryVerdict.RETHROW)); + } + + @Test + public void should_not_retry_on_next_host_on_error_response_if_read_failure() { + // given every node responding with a read failure. + SIMULACRON_RULE + .cluster() + .prime( + when(QUERY_LOCAL_QUORUM) + .then(readFailure(ConsistencyLevel.LOCAL_QUORUM, 1, 2, ImmutableMap.of(), true))); + try { + // when executing a query + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM); + fail("Expected a ReadFailureException"); + } catch (ReadFailureException rfe) { + // then we should get a read failure exception with the host being node 1 (since it was + // second tried). + assertThat(rfe) + .hasMessageContaining( + "Cassandra failure during read query at consistency LOCAL_QUORUM (2 responses were required but only 1 replica responded, 0 failed)"); + assertThat(rfe.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_QUORUM); + assertThat(rfe.getBlockFor()).isEqualTo(2); + assertThat(rfe.getReceived()).isEqualTo(1); + assertThat(rfe.wasDataPresent()).isTrue(); + assertThat(rfe.getReasonMap()).isEmpty(); + } + + // should only have been tried on first node. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(0); + + // verify log event was emitted as expected + verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getValue().getFormattedMessage()) + .isEqualTo( + expectedMessage( + ConsistencyDowngradingRetryPolicy.VERDICT_ON_ERROR, + logPrefix, + ReadFailureException.class.getSimpleName(), + "Cassandra failure during read query at consistency LOCAL_QUORUM (2 responses were required but only 1 replica responded, 0 failed)", + 0, + RetryVerdict.RETHROW)); + } + + @Test + public void should_not_retry_on_next_host_on_error_response_if_non_idempotent() { + // given every node responding with a server error. + SIMULACRON_RULE + .cluster() + .prime(when(QUERY_LOCAL_QUORUM).then(serverError("this is a server error"))); + + try { + // when executing a query that is not idempotent + sessionRule.session().execute(STATEMENT_LOCAL_QUORUM.setIdempotent(false)); + fail("Expected a ServerError"); + } catch (ServerError e) { + // then should get a server error from first host. + assertThat(e.getMessage()).isEqualTo("this is a server error"); + } + + // should only have been tried on first node. + localQuorumCounter.assertTotalCount(1); + localQuorumCounter.assertNodeCounts(1, 0, 0); + oneCounter.assertTotalCount(0); + + // expect no logging messages since there was no retry + verify(appender, after(500).times(0)).doAppend(any(ILoggingEvent.class)); + } + + private String expectedMessage(String template, Object... args) { + return MessageFormatter.arrayFormat(template, args).getMessage(); + } + + private SocketAddress coordinatorAddress(ExecutionInfo executionInfo) { + Node coordinator = executionInfo.getCoordinator(); + assertThat(coordinator).isNotNull(); + return coordinator.getEndPoint().resolve(); + } +} diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index 8c6190f36b1..fbcd8e92720 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -7,25 +7,56 @@ What to do when a request failed on a node: retry (same or other node), rethrow, * `advanced.retry-policy` in the configuration. Default policy retries at most once, in cases that have a high chance of success; you can also write your own. * can have per-profile policies. -* only kicks in if the query is idempotent. +* only kicks in if the query is [idempotent](../idempotence). ----- When a query fails, it sometimes makes sense to retry it: the error might be temporary, or the query might work on a different node. The driver uses a *retry policy* to determine when and how to retry. -It is defined in the [configuration](../configuration/): - + +### Built-in retry policies + +The driver ships with two retry policies: `DefaultRetryPolicy` –– the default –– and +`ConsistencyDowngradingRetryPolicy`. + +The default retry policy should be preferred in most cases as it only retries when *it is perfectly +safe to do so*, and when *the chances of success are high enough* to warrant a retry. + +`ConsistencyDowngradingRetryPolicy` is provided for cases where the application can tolerate a +temporary degradation of its consistency guarantees. Its general behavior is as follows: if, based +on the information the coordinator returns, retrying the operation with the initially requested +consistency has a chance to succeed, do it. Otherwise, if based on this information, we know that +the initially requested consistency level *cannot be achieved currently*, then: + +* For writes, ignore the exception *if we know the write has been persisted on at least one + replica*. +* For reads, try reading again at a weaker consistency level. + +Keep in mind that this may break invariants! For example, if your application relies on immediate +write visibility by writing and reading at QUORUM only, downgrading a write to ONE could cause that +write to go unnoticed by subsequent reads at QUORUM. Furthermore, this policy doesn't always respect +datacenter locality; for example, it may downgrade LOCAL_QUORUM to ONE, and thus could accidentally +send a write that was intended for the local datacenter to another datacenter. In summary: **only +use this retry policy if you understand the consequences.** + +Since `DefaultRetryPolicy` is already the driver's default retry policy, no special configuration +is required to activate it. To use `ConsistencyDowngradingRetryPolicy` instead, the following +option must be declared in the driver [configuration](../configuration/): + ``` -datastax-java-driver.advanced.retry-policy { - class = DefaultRetryPolicy -} +datastax-java-driver.advanced.retry-policy.class = ConsistencyDowngradingRetryPolicy ``` -The behavior of the default policy will be detailed in the sections below. You can also use your -own policy by specifying the fully-qualified name of a class that implements [RetryPolicy]. +You can also use your own policy by specifying for the above option the fully-qualified name of a +class that implements [RetryPolicy]. + +### Behavior -The policy has several methods that cover different error cases. Each method returns a decision to -indicate what to do next: +The behavior of both policies will be detailed in the sections below. + +The policy has several methods that cover different error cases. Each method returns a +[RetryVerdict]. A retry verdict essentially provides the driver with a [RetryDecision] to indicate +what to do next. There are four possible retry decisions: * retry on the same node; * retry on the next node in the [query plan](../load_balancing/) for this statement; @@ -33,7 +64,7 @@ indicate what to do next: using the asynchronous API); * ignore the exception. That is, mark the request as successful, and return an empty result set. -### onUnavailable +#### `onUnavailableVerdict` A request reached the coordinator, but there weren't enough live replicas to achieve the requested consistency level. The coordinator replied with an `UNAVAILABLE` error. @@ -48,7 +79,14 @@ rationale is that the first coordinator might have been network-isolated from al (thinking they're down), but still able to communicate with the client; in that case, retrying on the same node has almost no chance of success, but moving to the next node might solve the issue. -### onReadTimeout +`ConsistencyDowngradingRetryPolicy` also triggers a maximum of one retry, but instead of trying the +next node, it will downgrade the initial consistency level, if possible, and retry *the same node*. +Note that if it is not possible to downgrade, this policy will rethrow the exception. For example, +if the original consistency level was QUORUM, and 2 replicas were required to achieve a quorum, but +only one replica is alive, then the query will be retried with consistency ONE. If no replica was +alive however, there is no point in downgrading, and the policy will rethrow. + +#### `onReadTimeoutVerdict` A read request reached the coordinator, which initially believed that there were enough live replicas to process it. But one or several replicas were too slow to answer within the predefined @@ -73,7 +111,12 @@ retrieval, not having detected that replica as dead yet. The reasoning is that b the timeout, the dead replica will likely have been detected as dead and the retry has a high chance of success. -### onWriteTimeout +`ConsistencyDowngradingRetryPolicy` behaves like the default policy when enough replicas responded. +If not enough replicas responded however, it will attempt to downgrade the initial consistency +level, and retry *the same node*. If it is not possible to downgrade, this policy will rethrow the +exception. + +#### `onWriteTimeoutVerdict` This is similar to `onReadTimeout`, but for write operations. The reason reads and writes are handled separately is because a read is obviously a non mutating operation, whereas a write is @@ -91,7 +134,20 @@ small subset of nodes in the local datacenter; a timeout usually means that none alive but the coordinator hadn't detected them as dead yet. By the time we get the timeout, the dead nodes will likely have been detected as dead, and the retry has a high chance of success. -### onRequestAborted +`ConsistencyDowngradingRetryPolicy` also triggers a maximum of one retry, but behaves differently: + +* For `SIMPLE` and `BATCH` write types: if at least one replica acknowledged the write, the policy + will assume that the write will be eventually replicated, and decide to ignore the error; in other + words, it will consider that the write already succeeded, albeit with weaker consistency + guarantees: retrying is therefore useless. If no replica acknowledged the write, the policy will + rethrow the error. +* For `UNLOGGED_BATCH` write type: since only part of the batch could have been persisted, the + policy will attempt to downgrade the consistency level and retry *on the same node*. If + downgrading is not possible, the policy will rethrow. +* For `BATCH_LOG` write type: the policy will retry the same node, for the reasons explained above. +* For other write types: the policy will always rethrow. + +#### `onRequestAbortedVerdict` The request was aborted before we could get a response from the coordinator. This can happen in two cases: @@ -104,10 +160,10 @@ cases: This method is only invoked for [idempotent](../idempotence/) statements. Otherwise, the driver bypasses the retry policy and always rethrows the error. -The default policy retries on the next node if the connection was closed, and rethrows (assuming a -driver bug) in all other cases. +Both the default policy and `ConsistencyDowngradingRetryPolicy` retry on the next node if the +connection was closed, and rethrow (assuming a driver bug) in all other cases. -### onErrorResponse +#### `onErrorResponseVerdict` The coordinator replied with an error other than `READ_TIMEOUT`, `WRITE_TIMEOUT` or `UNAVAILABLE`. Namely, this covers [OverloadedException], [ServerError], [TruncateException], @@ -116,7 +172,8 @@ Namely, this covers [OverloadedException], [ServerError], [TruncateException], This method is only invoked for [idempotent](../idempotence/) statements. Otherwise, the driver bypasses the retry policy and always rethrows the error. -The default policy rethrows read and write failures, and retries other errors on the next node. +Both the default policy and `ConsistencyDowngradingRetryPolicy` rethrow read and write failures, +and retry other errors on the next node. ### Hard-coded rules @@ -174,20 +231,21 @@ configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html -[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/DriverTimeoutException.html -[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html -[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/connection/HeartbeatException.html -[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html -[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html -[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html -[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html -[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html -[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/retry/RetryDecision.html -[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/retry/RetryPolicy.html -[ServerError]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/ServerError.html -[TruncateException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/TruncateException.html -[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html -[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html -[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html +[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/DriverTimeoutException.html +[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html +[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/HeartbeatException.html +[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html +[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html +[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html +[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html +[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html +[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryDecision.html +[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html +[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[ServerError]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ServerError.html +[TruncateException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/TruncateException.html +[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html +[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html +[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 51c0917f018..88ba4cd8332 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -16,7 +16,7 @@ a `RetryVerdict` instance: 4. [`onRequestAbortedVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAbortedVerdict-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) 5. [`onErrorResponseVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponseVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) -The following methods were deprecated: +The following methods were deprecated and will be removed in the next major version: 1. [`onReadTimeout`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) 2. [`onWriteTimeout`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) @@ -24,6 +24,11 @@ The following methods were deprecated: 4. [`onRequestAborted`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAborted-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) 5. [`onErrorResponse`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponse-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) +Driver 4.10.0 also re-introduced a retry policy whose behavior is equivalent to the +`DowngradingConsistencyRetryPolicy` from driver 3.x. See this +[FAQ entry](https://docs.datastax.com/en/developer/java-driver/latest/faq/#where-is-downgrading-consistency-retry-policy) +for more information. + [`RetryVerdict`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryVerdict.html #### Enhancements to the `Uuids` utility class @@ -33,7 +38,7 @@ The following methods were deprecated: implementation, but instead re-implements random UUID generation using the non-cryptographic random number generator `java.util.Random`. -For most users, non cryptographic strength is enough and this change should translate into better +For most users, non-cryptographic strength is enough and this change should translate into better performance when generating UUIDs for database insertion. However, in the unlikely case where your application requires cryptographic strength for UUID generation, you should update your code to use `java.util.UUID.randomUUID()` instead of `com.datastax.oss.driver.api.core.uuid.Uuids.random()` From db803e84b98a13c40d4c37b598221fbde924d20e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 12:01:15 +0100 Subject: [PATCH 037/395] JAVA-2899: Re-introduce cross-DC failover in driver 4 (#1518) --- changelog/README.md | 1 + .../ContinuousRequestHandlerBase.java | 4 +- .../core/graph/GraphRequestHandler.java | 4 +- .../api/core/config/DefaultDriverOption.java | 15 + .../driver/api/core/config/OptionsMap.java | 2 + .../api/core/config/TypedDriverOption.java | 13 + .../core/ConsistencyLevelRegistry.java | 2 + .../core/DefaultConsistencyLevelRegistry.java | 5 + .../internal/core/cql/CqlRequestHandler.java | 4 +- .../BasicLoadBalancingPolicy.java | 210 ++++++-- .../DefaultLoadBalancingPolicy.java | 13 +- .../helper/DefaultNodeFilterHelper.java | 9 +- .../helper/OptionalLocalDcHelper.java | 29 +- .../nodeset/DcAgnosticNodeSet.java | 52 ++ .../loadbalancing/nodeset/MultiDcNodeSet.java | 93 ++++ .../core/loadbalancing/nodeset/NodeSet.java | 69 +++ .../nodeset/SingleDcNodeSet.java | 71 +++ .../util/collection/CompositeQueryPlan.java | 86 +++ .../core/util/collection/EmptyQueryPlan.java | 43 ++ .../core/util/collection/LazyQueryPlan.java | 56 ++ .../core/util/collection/QueryPlan.java | 86 ++- .../core/util/collection/QueryPlanBase.java | 73 +++ .../core/util/collection/SimpleQueryPlan.java | 45 ++ core/src/main/resources/reference.conf | 113 +++- ...asicLoadBalancingPolicyDcAgnosticTest.java | 56 ++ ...asicLoadBalancingPolicyDcFailoverTest.java | 153 ++++++ .../BasicLoadBalancingPolicyDistanceTest.java | 220 ++++++++ .../BasicLoadBalancingPolicyEventsTest.java | 22 +- .../BasicLoadBalancingPolicyInitTest.java | 39 +- ...BasicLoadBalancingPolicyQueryPlanTest.java | 33 +- ...ringLoadBalancingPolicyDcFailoverTest.java | 87 +++ ...erringLoadBalancingPolicyDistanceTest.java | 62 +++ ...nferringLoadBalancingPolicyEventsTest.java | 2 +- ...cInferringLoadBalancingPolicyInitTest.java | 14 +- ...rringLoadBalancingPolicyQueryPlanTest.java | 2 +- ...aultLoadBalancingPolicyDcFailoverTest.java | 87 +++ ...efaultLoadBalancingPolicyDistanceTest.java | 61 +++ .../DefaultLoadBalancingPolicyEventsTest.java | 2 +- .../DefaultLoadBalancingPolicyInitTest.java | 16 +- ...faultLoadBalancingPolicyQueryPlanTest.java | 7 +- ...LoadBalancingPolicyRequestTrackerTest.java | 3 +- ....java => LoadBalancingPolicyTestBase.java} | 11 +- .../nodeset/DcAgnosticNodeSetTest.java | 59 ++ .../nodeset/MultiDcNodeSetTest.java | 81 +++ .../nodeset/SingleDcNodeSetTest.java | 71 +++ .../collection/CompositeQueryPlanTest.java | 40 ++ .../util/collection/LazyQueryPlanTest.java | 34 ++ ...ryPlanTest.java => QueryPlanTestBase.java} | 55 +- .../util/collection/SimpleQueryPlanTest.java | 29 + examples/pom.xml | 5 + .../failover/CrossDatacenterFailover.java | 456 ++++++++++++++++ faq/README.md | 14 + .../AllLoadBalancingPoliciesSimulacronIT.java | 503 ++++++++++++++++++ manual/core/load_balancing/README.md | 155 +++++- pom.xml | 2 +- upgrade_guide/README.md | 9 + 56 files changed, 3230 insertions(+), 258 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/NodeSet.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlan.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/EmptyQueryPlan.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlan.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanBase.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlan.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcAgnosticTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcFailoverTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java rename core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/{DefaultLoadBalancingPolicyTestBase.java => LoadBalancingPolicyTestBase.java} (85%) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSetTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSetTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSetTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlanTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlanTest.java rename core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/{QueryPlanTest.java => QueryPlanTestBase.java} (58%) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlanTest.java create mode 100644 examples/src/main/java/com/datastax/oss/driver/examples/failover/CrossDatacenterFailover.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/AllLoadBalancingPoliciesSimulacronIT.java diff --git a/changelog/README.md b/changelog/README.md index 8f740eb8870..4c7cf9fbf4d 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [new feature] JAVA-2899: Re-introduce cross-DC failover in driver 4 - [new feature] JAVA-2900: Re-introduce consistency downgrading retries - [new feature] JAVA-2903: BlockHound integration - [improvement] JAVA-2877: Allow skipping validation for individual mapped entities diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java index c7784c2b2d3..f97bc684e37 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java @@ -62,7 +62,7 @@ import com.datastax.oss.driver.internal.core.session.DefaultSession; import com.datastax.oss.driver.internal.core.session.RepreparePayload; import com.datastax.oss.driver.internal.core.util.Loggers; -import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; +import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.protocol.internal.Frame; import com.datastax.oss.protocol.internal.Message; @@ -194,7 +194,7 @@ public ContinuousRequestHandlerBase( Conversions.resolveExecutionProfile(statement, context); this.queryPlan = statement.getNode() != null - ? new QueryPlan(statement.getNode()) + ? new SimpleQueryPlan(statement.getNode()) : context .getLoadBalancingPolicyWrapper() .newQueryPlan(statement, executionProfile.getName(), session); diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java index b193805a2c6..ca84f1c634a 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java @@ -57,7 +57,7 @@ import com.datastax.oss.driver.internal.core.tracker.NoopRequestTracker; import com.datastax.oss.driver.internal.core.tracker.RequestLogger; import com.datastax.oss.driver.internal.core.util.Loggers; -import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; +import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import com.datastax.oss.protocol.internal.Frame; import com.datastax.oss.protocol.internal.Message; import com.datastax.oss.protocol.internal.response.Error; @@ -190,7 +190,7 @@ public void onThrottleReady(boolean wasDelayed) { } Queue queryPlan = initialStatement.getNode() != null - ? new QueryPlan(initialStatement.getNode()) + ? new SimpleQueryPlan(initialStatement.getNode()) : context .getLoadBalancingPolicyWrapper() .newQueryPlan(initialStatement, executionProfile.getName(), session); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 55e50ed9069..d9bc504bea4 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -823,6 +823,21 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: {@link String} */ METRICS_FACTORY_CLASS("advanced.metrics.factory.class"), + + /** + * The maximum number of nodes from remote DCs to include in query plans. + * + *

    Value-Type: int + */ + LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC( + "advanced.load-balancing-policy.dc-failover.max-nodes-per-remote-dc"), + /** + * Whether to consider nodes from remote DCs if the request's consistency level is local. + * + *

    Value-Type: boolean + */ + LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS( + "advanced.load-balancing-policy.dc-failover.allow-for-local-consistency-levels"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 2b4a767e29d..c5eb7829deb 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -370,6 +370,8 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.NETTY_TIMER_TICK_DURATION, Duration.ofMillis(100)); map.put(TypedDriverOption.NETTY_TIMER_TICKS_PER_WHEEL, 2048); map.put(TypedDriverOption.COALESCER_INTERVAL, Duration.of(10, ChronoUnit.MICROS)); + map.put(TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC, 0); + map.put(TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, false); } @Immutable diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index c7c80fb9bf4..bf4223bf45c 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -709,6 +709,19 @@ public String toString() { public static final TypedDriverOption METRICS_FACTORY_CLASS = new TypedDriverOption<>(DefaultDriverOption.METRICS_FACTORY_CLASS, GenericType.STRING); + /** The maximum number of nodes from remote DCs to include in query plans. */ + public static final TypedDriverOption + LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC = + new TypedDriverOption<>( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC, + GenericType.INTEGER); + /** Whether to consider nodes from remote DCs if the request's consistency level is local. */ + public static final TypedDriverOption + LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS = + new TypedDriverOption<>( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, + GenericType.BOOLEAN); + private static Iterable> introspectBuiltInValues() { try { ImmutableList.Builder> result = ImmutableList.builder(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ConsistencyLevelRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ConsistencyLevelRegistry.java index c9353df9b55..54f06840412 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ConsistencyLevelRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ConsistencyLevelRegistry.java @@ -29,6 +29,8 @@ public interface ConsistencyLevelRegistry { int nameToCode(String name); + ConsistencyLevel nameToLevel(String name); + /** @return all the values known to this driver instance. */ Iterable getValues(); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultConsistencyLevelRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultConsistencyLevelRegistry.java index ba833674292..8357ef6d023 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultConsistencyLevelRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultConsistencyLevelRegistry.java @@ -46,6 +46,11 @@ public int nameToCode(String name) { return NAME_TO_CODE.get(name); } + @Override + public ConsistencyLevel nameToLevel(String name) { + return DefaultConsistencyLevel.valueOf(name); + } + @Override public Iterable getValues() { return VALUES; diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java index 166563b3160..743d11c9ad4 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java @@ -55,7 +55,7 @@ import com.datastax.oss.driver.internal.core.tracker.NoopRequestTracker; import com.datastax.oss.driver.internal.core.tracker.RequestLogger; import com.datastax.oss.driver.internal.core.util.Loggers; -import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; +import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import com.datastax.oss.protocol.internal.Frame; import com.datastax.oss.protocol.internal.Message; import com.datastax.oss.protocol.internal.ProtocolConstants; @@ -187,7 +187,7 @@ public void onThrottleReady(boolean wasDelayed) { } Queue queryPlan = this.initialStatement.getNode() != null - ? new QueryPlan(this.initialStatement.getNode()) + ? new SimpleQueryPlan(this.initialStatement.getNode()) : context .getLoadBalancingPolicyWrapper() .newQueryPlan(initialStatement, executionProfile.getName(), session); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java index 23b921a6eb9..dd9b4145b18 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java @@ -15,9 +15,12 @@ */ package com.datastax.oss.driver.internal.core.loadbalancing; +import com.datastax.oss.driver.api.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; import com.datastax.oss.driver.api.core.metadata.Node; @@ -29,19 +32,25 @@ import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.loadbalancing.helper.DefaultNodeFilterHelper; import com.datastax.oss.driver.internal.core.loadbalancing.helper.OptionalLocalDcHelper; +import com.datastax.oss.driver.internal.core.loadbalancing.nodeset.DcAgnosticNodeSet; +import com.datastax.oss.driver.internal.core.loadbalancing.nodeset.MultiDcNodeSet; +import com.datastax.oss.driver.internal.core.loadbalancing.nodeset.NodeSet; +import com.datastax.oss.driver.internal.core.loadbalancing.nodeset.SingleDcNodeSet; import com.datastax.oss.driver.internal.core.util.ArrayUtils; +import com.datastax.oss.driver.internal.core.util.collection.CompositeQueryPlan; +import com.datastax.oss.driver.internal.core.util.collection.LazyQueryPlan; import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; -import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Queue; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntUnaryOperator; import java.util.function.Predicate; @@ -88,36 +97,58 @@ public class BasicLoadBalancingPolicy implements LoadBalancingPolicy { private static final Logger LOG = LoggerFactory.getLogger(BasicLoadBalancingPolicy.class); protected static final IntUnaryOperator INCREMENT = i -> (i == Integer.MAX_VALUE) ? 0 : i + 1; + private static final Object[] EMPTY_NODES = new Object[0]; @NonNull protected final InternalDriverContext context; @NonNull protected final DriverExecutionProfile profile; @NonNull protected final String logPrefix; protected final AtomicInteger roundRobinAmount = new AtomicInteger(); - protected final CopyOnWriteArraySet liveNodes = new CopyOnWriteArraySet<>(); + + private final int maxNodesPerRemoteDc; + private final boolean allowDcFailoverForLocalCl; + private final ConsistencyLevel defaultConsistencyLevel; // private because they should be set in init() and never be modified after private volatile DistanceReporter distanceReporter; private volatile Predicate filter; private volatile String localDc; + private volatile NodeSet liveNodes; public BasicLoadBalancingPolicy(@NonNull DriverContext context, @NonNull String profileName) { this.context = (InternalDriverContext) context; profile = context.getConfig().getProfile(profileName); logPrefix = context.getSessionName() + "|" + profileName; - } - - /** @return The local datacenter, if known; empty otherwise. */ - public Optional getLocalDatacenter() { - return Optional.ofNullable(localDc); + maxNodesPerRemoteDc = + profile.getInt(DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC); + allowDcFailoverForLocalCl = + profile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS); + defaultConsistencyLevel = + this.context + .getConsistencyLevelRegistry() + .nameToLevel(profile.getString(DefaultDriverOption.REQUEST_CONSISTENCY)); } /** - * @return An immutable copy of the nodes currently considered as live; if the local datacenter is - * known, this set will contain only nodes belonging to that datacenter. + * Returns the local datacenter name, if known; empty otherwise. + * + *

    When this method returns null, then datacenter awareness is completely disabled. All + * non-ignored nodes will be considered "local" regardless of their actual datacenters, and will + * have equal chances of being selected for query plans. + * + *

    After the policy is {@linkplain #init(Map, DistanceReporter) initialized} this method will + * return the local datacenter that was discovered by calling {@link #discoverLocalDc(Map)}. + * Before initialization, this method always returns null. */ - public Set getLiveNodes() { - return ImmutableSet.copyOf(liveNodes); + @Nullable + protected String getLocalDatacenter() { + return localDc; + } + + /** @return The nodes currently considered as live. */ + protected NodeSet getLiveNodes() { + return liveNodes; } @Override @@ -125,17 +156,18 @@ public void init(@NonNull Map nodes, @NonNull DistanceReporter dista this.distanceReporter = distanceReporter; localDc = discoverLocalDc(nodes).orElse(null); filter = createNodeFilter(localDc, nodes); + liveNodes = + localDc == null + ? new DcAgnosticNodeSet() + : maxNodesPerRemoteDc <= 0 ? new SingleDcNodeSet(localDc) : new MultiDcNodeSet(); for (Node node : nodes.values()) { - if (filter.test(node)) { - distanceReporter.setDistance(node, NodeDistance.LOCAL); - if (node.getState() != NodeState.DOWN) { - // This includes state == UNKNOWN. If the node turns out to be unreachable, this will be - // detected when we try to open a pool to it, it will get marked down and this will be - // signaled back to this policy - liveNodes.add(node); - } - } else { - distanceReporter.setDistance(node, NodeDistance.IGNORED); + NodeDistance distance = computeNodeDistance(node); + distanceReporter.setDistance(node, distance); + if (distance != NodeDistance.IGNORED && node.getState() != NodeState.DOWN) { + // This includes state == UNKNOWN. If the node turns out to be unreachable, this will be + // detected when we try to open a pool to it, it will get marked down and this will be + // signaled back to this policy, which will then remove it from the live set. + liveNodes.add(node); } } } @@ -151,6 +183,10 @@ public void init(@NonNull Map nodes, @NonNull DistanceReporter dista * Optional#empty empty}, if they require a local datacenter to be defined in order to operate * properly. * + *

    If this method returns empty, then datacenter awareness will be completely disabled. All + * non-ignored nodes will be considered "local" regardless of their actual datacenters, and will + * have equal chances of being selected for query plans. + * * @param nodes All the nodes that were known to exist in the cluster (regardless of their state) * when the load balancing policy was initialized. This argument is provided in case * implementors need to inspect the cluster topology to discover the local datacenter. @@ -187,7 +223,7 @@ protected Predicate createNodeFilter( @Override public Queue newQueryPlan(@Nullable Request request, @Nullable Session session) { // Take a snapshot since the set is concurrent: - Object[] currentNodes = liveNodes.toArray(); + Object[] currentNodes = liveNodes.dc(localDc).toArray(); Set allReplicas = getReplicas(request, session); int replicaCount = 0; // in currentNodes @@ -216,7 +252,8 @@ public Queue newQueryPlan(@Nullable Request request, @Nullable Session ses currentNodes.length - replicaCount, roundRobinAmount.getAndUpdate(INCREMENT)); - return new QueryPlan(currentNodes); + QueryPlan plan = currentNodes.length == 0 ? QueryPlan.EMPTY : new SimpleQueryPlan(currentNodes); + return maybeAddDcFailover(request, plan); } @NonNull @@ -233,9 +270,9 @@ protected Set getReplicas(@Nullable Request request, @Nullable Session ses // Note: we're on the hot path and the getXxx methods are potentially more than simple getters, // so we only call each method when strictly necessary (which is why the code below looks a bit // weird). - CqlIdentifier keyspace = null; - Token token = null; - ByteBuffer key = null; + CqlIdentifier keyspace; + Token token; + ByteBuffer key; try { keyspace = request.getKeyspace(); if (keyspace == null) { @@ -265,34 +302,79 @@ protected Set getReplicas(@Nullable Request request, @Nullable Session ses : tokenMap.getReplicas(keyspace, key); } + @NonNull + protected Queue maybeAddDcFailover(@Nullable Request request, @NonNull Queue local) { + if (maxNodesPerRemoteDc <= 0 || localDc == null) { + return local; + } + if (!allowDcFailoverForLocalCl && request instanceof Statement) { + Statement statement = (Statement) request; + ConsistencyLevel consistency = statement.getConsistencyLevel(); + if (consistency == null) { + consistency = defaultConsistencyLevel; + } + if (consistency.isDcLocal()) { + return local; + } + } + QueryPlan remote = + new LazyQueryPlan() { + + @Override + protected Object[] computeNodes() { + Object[] dcs = liveNodes.dcs().toArray(); + if (dcs.length <= 1) { + return EMPTY_NODES; + } + Object[] remoteNodes = new Object[(dcs.length - 1) * maxNodesPerRemoteDc]; + int remoteNodesLength = 0; + for (Object dc : dcs) { + if (!dc.equals(localDc)) { + Object[] remoteNodesInDc = liveNodes.dc((String) dc).toArray(); + for (int i = 0; i < maxNodesPerRemoteDc && i < remoteNodesInDc.length; i++) { + remoteNodes[remoteNodesLength++] = remoteNodesInDc[i]; + } + } + } + if (remoteNodesLength == 0) { + return EMPTY_NODES; + } + shuffleHead(remoteNodes, remoteNodesLength); + if (remoteNodes.length == remoteNodesLength) { + return remoteNodes; + } + Object[] trimmedRemoteNodes = new Object[remoteNodesLength]; + System.arraycopy(remoteNodes, 0, trimmedRemoteNodes, 0, remoteNodesLength); + return trimmedRemoteNodes; + } + }; + + return new CompositeQueryPlan(local, remote); + } + /** Exposed as a protected method so that it can be accessed by tests */ - protected void shuffleHead(Object[] currentNodes, int replicaCount) { - ArrayUtils.shuffleHead(currentNodes, replicaCount); + protected void shuffleHead(Object[] currentNodes, int headLength) { + ArrayUtils.shuffleHead(currentNodes, headLength); } @Override public void onAdd(@NonNull Node node) { - if (filter.test(node)) { - LOG.debug("[{}] {} was added, setting distance to LOCAL", logPrefix, node); - // Setting to a non-ignored distance triggers the session to open a pool, which will in turn - // set the node UP when the first channel gets opened. - distanceReporter.setDistance(node, NodeDistance.LOCAL); - } else { - distanceReporter.setDistance(node, NodeDistance.IGNORED); - } + NodeDistance distance = computeNodeDistance(node); + // Setting to a non-ignored distance triggers the session to open a pool, which will in turn + // set the node UP when the first channel gets opened, then #onUp will be called, and the + // node will be eventually added to the live set. + distanceReporter.setDistance(node, distance); + LOG.debug("[{}] {} was added, setting distance to {}", logPrefix, node, distance); } @Override public void onUp(@NonNull Node node) { - if (filter.test(node)) { - // Normally this is already the case, but the filter could be dynamic and have ignored the - // node previously. - distanceReporter.setDistance(node, NodeDistance.LOCAL); - if (liveNodes.add(node)) { - LOG.debug("[{}] {} came back UP, added to live set", logPrefix, node); - } - } else { - distanceReporter.setDistance(node, NodeDistance.IGNORED); + NodeDistance distance = computeNodeDistance(node); + if (node.getDistance() != distance) { + distanceReporter.setDistance(node, distance); + } + if (distance != NodeDistance.IGNORED && liveNodes.add(node)) { + LOG.debug("[{}] {} came back UP, added to live set", logPrefix, node); } } @@ -310,6 +392,42 @@ public void onRemove(@NonNull Node node) { } } + /** + * Computes the distance of the given node. + * + *

    This method is called during {@linkplain #init(Map, DistanceReporter) initialization}, when + * a node {@linkplain #onAdd(Node) is added}, and when a node {@linkplain #onUp(Node) is back UP}. + */ + protected NodeDistance computeNodeDistance(@NonNull Node node) { + // We interrogate the filter every time since it could be dynamic + // and change its verdict between two invocations of this method. + if (!filter.test(node)) { + return NodeDistance.IGNORED; + } + // no local DC is defined, all nodes accepted by the filter are LOCAL. + if (localDc == null) { + return NodeDistance.LOCAL; + } + // the node is LOCAL if its datacenter is the local datacenter. + if (Objects.equals(node.getDatacenter(), localDc)) { + return NodeDistance.LOCAL; + } + // otherwise the node will be either REMOTE or IGNORED, depending + // on how many remote nodes we accept per DC. + if (maxNodesPerRemoteDc > 0) { + Object[] remoteNodes = liveNodes.dc(node.getDatacenter()).toArray(); + for (int i = 0; i < maxNodesPerRemoteDc; i++) { + if (i == remoteNodes.length) { + // there is still room for one more REMOTE node in this DC + return NodeDistance.REMOTE; + } else if (remoteNodes[i] == node) { + return NodeDistance.REMOTE; + } + } + } + return NodeDistance.IGNORED; + } + @Override public void close() { // nothing to do diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java index bc609c2ece3..175f9556eaf 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java @@ -31,6 +31,7 @@ import com.datastax.oss.driver.internal.core.session.DefaultSession; import com.datastax.oss.driver.internal.core.util.ArrayUtils; import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; +import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.BitSet; @@ -126,7 +127,7 @@ public Queue newQueryPlan(@Nullable Request request, @Nullable Session ses } // Take a snapshot since the set is concurrent: - Object[] currentNodes = liveNodes.toArray(); + Object[] currentNodes = getLiveNodes().dc(getLocalDatacenter()).toArray(); Set allReplicas = getReplicas(request, session); int replicaCount = 0; // in currentNodes @@ -157,6 +158,7 @@ public Queue newQueryPlan(@Nullable Request request, @Nullable Session ses long now = nanoTime(); for (int i = 0; i < replicaCount; i++) { Node node = (Node) currentNodes[i]; + assert node != null; Long upTimeNanos = upTimes.get(node); if (upTimeNanos != null && now - upTimeNanos - NEWLY_UP_INTERVAL_NANOS < 0 @@ -225,7 +227,8 @@ > getInFlight((Node) currentNodes[1], session)) { currentNodes.length - replicaCount, roundRobinAmount.getAndUpdate(INCREMENT)); - return new QueryPlan(currentNodes); + QueryPlan plan = currentNodes.length == 0 ? QueryPlan.EMPTY : new SimpleQueryPlan(currentNodes); + return maybeAddDcFailover(request, plan); } @Override @@ -249,12 +252,6 @@ public void onNodeError( updateResponseTimes(node); } - /** Exposed as a protected method so that it can be accessed by tests */ - @Override - protected void shuffleHead(Object[] currentNodes, int replicaCount) { - super.shuffleHead(currentNodes, replicaCount); - } - /** Exposed as a protected method so that it can be accessed by tests */ protected long nanoTime() { return System.nanoTime(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java index 10630e58fad..9eae21589ed 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java @@ -62,14 +62,7 @@ public Predicate createNodeFilter( @Nullable String localDc, @NonNull Map nodes) { Predicate filterFromConfig = nodeFilterFromConfig(); return node -> { - if (localDc != null && !localDc.equals(node.getDatacenter())) { - LOG.debug( - "[{}] Ignoring {} because it doesn't belong to the local DC {}", - logPrefix, - node, - localDc); - return false; - } else if (!filterFromConfig.test(node)) { + if (!filterFromConfig.test(node)) { LOG.debug( "[{}] Ignoring {} because it doesn't match the user-provided predicate", logPrefix, diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java index e513b2b8b83..4c67803127e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java @@ -74,6 +74,7 @@ public Optional discoverLocalDc(@NonNull Map nodes) { checkLocalDatacenterCompatibility(localDc, context.getMetadataManager().getContactPoints()); return Optional.of(localDc); } else { + LOG.debug("[{}] Local DC not set, DC awareness will be disabled", logPrefix); return Optional.empty(); } } @@ -83,26 +84,28 @@ public Optional discoverLocalDc(@NonNull Map nodes) { * configuration, or programmatically. * *

    The default implementation logs a warning when a contact point reports a datacenter - * different from the local one. + * different from the local one, and only for the default profile. * * @param localDc The local datacenter, as specified in the config, or programmatically. * @param contactPoints The contact points provided when creating the session. */ protected void checkLocalDatacenterCompatibility( @NonNull String localDc, Set contactPoints) { - Set badContactPoints = new LinkedHashSet<>(); - for (Node node : contactPoints) { - if (!Objects.equals(localDc, node.getDatacenter())) { - badContactPoints.add(node); + if (profile.getName().equals(DriverExecutionProfile.DEFAULT_NAME)) { + Set badContactPoints = new LinkedHashSet<>(); + for (Node node : contactPoints) { + if (!Objects.equals(localDc, node.getDatacenter())) { + badContactPoints.add(node); + } + } + if (!badContactPoints.isEmpty()) { + LOG.warn( + "[{}] You specified {} as the local DC, but some contact points are from a different DC: {}; " + + "please provide the correct local DC, or check your contact points", + logPrefix, + localDc, + formatNodesAndDcs(badContactPoints)); } - } - if (!badContactPoints.isEmpty()) { - LOG.warn( - "[{}] You specified {} as the local DC, but some contact points are from a different DC: {}; " - + "please provide the correct local DC, or check your contact points", - logPrefix, - localDc, - formatNodesAndDcs(badContactPoints)); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java new file mode 100644 index 00000000000..d9cf67fb7c0 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java @@ -0,0 +1,52 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public class DcAgnosticNodeSet implements NodeSet { + + @VisibleForTesting final Set nodes = new CopyOnWriteArraySet<>(); + + @Override + public boolean add(@NonNull Node node) { + return nodes.add(node); + } + + @Override + public boolean remove(@NonNull Node node) { + return nodes.remove(node); + } + + @Override + @NonNull + public Set dc(@Nullable String dc) { + return nodes; + } + + @Override + public Set dcs() { + return Collections.emptySet(); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java new file mode 100644 index 00000000000..5c3d425ba69 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java @@ -0,0 +1,93 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicBoolean; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public class MultiDcNodeSet implements NodeSet { + + private static final String UNKNOWN_DC = ""; + + @VisibleForTesting final Map> nodes = new ConcurrentHashMap<>(); + + @Override + public boolean add(@NonNull Node node) { + AtomicBoolean added = new AtomicBoolean(); + nodes.compute( + getMapKey(node), + (key, current) -> { + if (current == null) { + // We use CopyOnWriteArraySet because we need + // 1) to preserve insertion order, and + // 2) a "snapshot"-style toArray() implementation + current = new CopyOnWriteArraySet<>(); + } + if (current.add(node)) { + added.set(true); + } + return current; + }); + return added.get(); + } + + @Override + public boolean remove(@NonNull Node node) { + AtomicBoolean removed = new AtomicBoolean(); + nodes.compute( + getMapKey(node), + (key, current) -> { + if (current != null) { + if (current.remove(node)) { + removed.set(true); + } + } + return current; + }); + return removed.get(); + } + + @Override + @NonNull + public Set dc(@Nullable String dc) { + return nodes.getOrDefault(getMapKey(dc), Collections.emptySet()); + } + + @Override + public Set dcs() { + return nodes.keySet(); + } + + @NonNull + private String getMapKey(@NonNull Node node) { + return getMapKey(node.getDatacenter()); + } + + @NonNull + private String getMapKey(@Nullable String dc) { + return dc == null ? UNKNOWN_DC : dc; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/NodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/NodeSet.java new file mode 100644 index 00000000000..2b66642d198 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/NodeSet.java @@ -0,0 +1,69 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import com.datastax.oss.driver.api.core.metadata.Node; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Set; +import net.jcip.annotations.ThreadSafe; + +/** + * A thread-safe abstraction around a map of nodes per datacenter, to facilitate node management by + * load balancing policies. + */ +@ThreadSafe +public interface NodeSet { + + /** + * Adds the given node to this set. + * + *

    If this set was initialized with datacenter awareness, the node will be added to its + * datacenter's specific set; otherwise, the node is added to a general set containing all nodes + * in the cluster. + * + * @param node The node to add. + * @return true if the node was added, false otherwise (because it was already present). + */ + boolean add(@NonNull Node node); + + /** + * Removes the node from the set. + * + * @param node The node to remove. + * @return true if the node was removed, false otherwise (because it was not present). + */ + boolean remove(@NonNull Node node); + + /** + * Returns the current nodes in the given datacenter. + * + *

    If this set was initialized with datacenter awareness, the returned set will contain only + * nodes pertaining to the given datacenter; otherwise, the given datacenter name is ignored and + * the returned set will contain all nodes in the cluster. + * + * @param dc The datacenter name, or null if the datacenter name is not known, or irrelevant. + * @return the current nodes in the given datacenter. + */ + @NonNull + Set dc(@Nullable String dc); + + /** + * Returns the current datacenter names known to this set. If datacenter awareness has been + * disabled, this method returns an empty set. + */ + Set dcs(); +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java new file mode 100644 index 00000000000..e638913edfd --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java @@ -0,0 +1,71 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public class SingleDcNodeSet implements NodeSet { + + @VisibleForTesting final Set nodes = new CopyOnWriteArraySet<>(); + + private final String dc; + private final Set dcs; + + public SingleDcNodeSet(@NonNull String dc) { + this.dc = dc; + dcs = ImmutableSet.of(dc); + } + + @Override + public boolean add(@NonNull Node node) { + if (Objects.equals(node.getDatacenter(), dc)) { + return nodes.add(node); + } + return false; + } + + @Override + public boolean remove(@NonNull Node node) { + if (Objects.equals(node.getDatacenter(), dc)) { + return nodes.remove(node); + } + return false; + } + + @Override + @NonNull + public Set dc(@Nullable String dc) { + if (Objects.equals(this.dc, dc)) { + return nodes; + } + return Collections.emptySet(); + } + + @Override + public Set dcs() { + return dcs; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlan.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlan.java new file mode 100644 index 00000000000..3992e14a4d7 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlan.java @@ -0,0 +1,86 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.AbstractQueue; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicInteger; +import net.jcip.annotations.ThreadSafe; + +/** A query plan that encompasses many child plans, and consumes them one by one. */ +@ThreadSafe +public class CompositeQueryPlan extends AbstractQueue implements QueryPlan { + + private final Queue[] plans; + private final AtomicInteger currentPlan = new AtomicInteger(0); + + @SafeVarargs + public CompositeQueryPlan(@NonNull Queue... plans) { + if (plans.length == 0) { + throw new IllegalArgumentException("at least one child plan must be provided"); + } + for (Queue plan : plans) { + if (plan == null) { + throw new NullPointerException("child plan cannot be null"); + } + } + this.plans = plans; + } + + @Nullable + @Override + public Node poll() { + while (true) { + int current = currentPlan.get(); + Queue plan = plans[current]; + Node n = plan.poll(); + if (n != null) { + return n; + } + int next = current + 1; + if (next == plans.length) { + return null; + } + currentPlan.compareAndSet(current, next); + } + } + + @NonNull + @Override + public Iterator iterator() { + List> its = new ArrayList<>(plans.length); + for (Queue plan : plans) { + its.add(plan.iterator()); + } + return Iterators.concat(its.iterator()); + } + + @Override + public int size() { + int size = 0; + for (Queue plan : plans) { + size += plan.size(); + } + return size; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/EmptyQueryPlan.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/EmptyQueryPlan.java new file mode 100644 index 00000000000..8149084480e --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/EmptyQueryPlan.java @@ -0,0 +1,43 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.AbstractQueue; +import java.util.Collections; +import java.util.Iterator; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +class EmptyQueryPlan extends AbstractQueue implements QueryPlan { + + @Override + public Node poll() { + return null; + } + + @NonNull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + @Override + public int size() { + return 0; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlan.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlan.java new file mode 100644 index 00000000000..cbbe6fb9d0c --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlan.java @@ -0,0 +1,56 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import net.jcip.annotations.ThreadSafe; + +/** + * A query plan where nodes are computed lazily, when the plan is consumed for the first time. + * + *

    This class can be useful when a query plan computation is heavy but the plan has a low chance + * of ever being consumed, e.g. the last query plan in a {@link CompositeQueryPlan}. + */ +@ThreadSafe +public abstract class LazyQueryPlan extends QueryPlanBase { + + private volatile Object[] nodes; + + /** + * Computes and returns the nodes to use for this query plan. + * + *

    For efficiency, the declared return type is {@code Object[]} but all elements must be + * instances of {@link Node}. See {@link #getNodes()} for details. + * + *

    This method is guaranteed to be invoked only once, at the first call to {@link #poll()}. + * + *

    Implementors must avoid blocking calls in this method as it will be invoked on the driver's + * hot path. + */ + protected abstract Object[] computeNodes(); + + @Override + protected Object[] getNodes() { + if (nodes == null) { + synchronized (this) { + if (nodes == null) { + nodes = computeNodes(); + } + } + } + return nodes; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlan.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlan.java index dfe2a45757f..858b856210d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlan.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlan.java @@ -15,98 +15,76 @@ */ package com.datastax.oss.driver.internal.core.util.collection; -import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.Session; -import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy; -import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.Nullable; -import java.util.AbstractCollection; -import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; import java.util.Queue; -import java.util.concurrent.atomic.AtomicInteger; import net.jcip.annotations.ThreadSafe; /** - * A specialized, thread-safe queue implementation for {@link - * LoadBalancingPolicy#newQueryPlan(Request, Session)}. + * A specialized, thread-safe node queue for use when creating {@linkplain + * com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy#newQueryPlan(Request, Session) + * query plans}. * - *

    All nodes must be provided at construction time. After that, the only valid mutation operation - * is {@link #poll()}, other methods throw. + *

    This interface and its built-in implementations are not general-purpose queues; they are + * tailored for the specific use case of creating query plans in the driver. They make a few + * unconventional API choices for the sake of performance. * - *

    This class is not a general-purpose implementation, it is tailored for a specific use case in - * the driver. It makes a few unconventional API choices for the sake of performance (see {@link - * #QueryPlan(Object...)}. It can be reused for custom load balancing policies; if you plan to do - * so, study the source code of {@link DefaultLoadBalancingPolicy}. + *

    Furthermore, the driver only consumes query plans through calls to its {@link #poll()} method; + * therefore, this method is the only valid mutation operation for a query plan, other mutating + * methods throw. + * + *

    Both {@link #size()} and {@link #iterator()} are supported and never throw, even if called + * concurrently. These methods are implemented for reporting purposes only, the driver itself does + * not use them. + * + *

    All built-in {@link QueryPlan} implementations can be safely reused for custom load balancing + * policies; if you plan to do so, study the source code of {@link + * com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy} or {@link + * com.datastax.oss.driver.internal.core.loadbalancing.BasicLoadBalancingPolicy}. + * + * @see QueryPlanBase */ @ThreadSafe -public class QueryPlan extends AbstractCollection implements Queue { - - private final Object[] nodes; - private final AtomicInteger nextIndex = new AtomicInteger(); - - /** - * @param nodes the nodes to initially fill the queue with. For efficiency, there is no defensive - * copy, the provided array is used directly. The declared type is {@code Object[]} because of - * implementation details of {@link DefaultLoadBalancingPolicy}, but all elements must be - * instances of {@link Node}, otherwise instance methods will fail later. - */ - public QueryPlan(@NonNull Object... nodes) { - this.nodes = nodes; - } +public interface QueryPlan extends Queue { - @Nullable - @Override - public Node poll() { - // We don't handle overflow. In practice it won't be an issue, since the driver stops polling - // once the query plan is empty. - int i = nextIndex.getAndIncrement(); - return (i >= nodes.length) ? null : (Node) nodes[i]; - } + QueryPlan EMPTY = new EmptyQueryPlan(); /** * {@inheritDoc} * - *

    The returned iterator reflects the state of the queue at the time of the call, and is not - * affected by further modifications. + *

    Implementation note: query plan iterators are snapshots that reflect the contents of the + * queue at the time of the call, and are not affected by further modifications. Successive calls + * to this method will return different objects. */ @NonNull @Override - public Iterator iterator() { - int i = nextIndex.get(); - if (i >= nodes.length) { - return Collections.emptyList().iterator(); - } else { - return Iterators.forArray(Arrays.copyOfRange(nodes, i, nodes.length, Node[].class)); - } - } + Iterator iterator(); @Override - public int size() { - return Math.max(nodes.length - nextIndex.get(), 0); + default boolean offer(Node node) { + throw new UnsupportedOperationException("Not implemented"); } @Override - public boolean offer(Node node) { + default Node peek() { throw new UnsupportedOperationException("Not implemented"); } @Override - public Node remove() { + default boolean add(Node node) { throw new UnsupportedOperationException("Not implemented"); } @Override - public Node element() { + default Node remove() { throw new UnsupportedOperationException("Not implemented"); } @Override - public Node peek() { + default Node element() { throw new UnsupportedOperationException("Not implemented"); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanBase.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanBase.java new file mode 100644 index 00000000000..a82a450eb9f --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanBase.java @@ -0,0 +1,73 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.AbstractQueue; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public abstract class QueryPlanBase extends AbstractQueue implements QueryPlan { + + private final AtomicInteger nextIndex = new AtomicInteger(); + + /** + * Returns the nodes in this query plan; the returned array should stay the same across + * invocations. + * + *

    The declared return type is {@code Object[]} because of implementation details of {@link + * com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy + * DefaultLoadBalancingPolicy} and {@link + * com.datastax.oss.driver.internal.core.loadbalancing.BasicLoadBalancingPolicy + * BasicLoadBalancingPolicy}, but all elements must be instances of {@link Node}, otherwise + * instance methods will fail later. + */ + protected abstract Object[] getNodes(); + + @Nullable + @Override + public Node poll() { + // We don't handle overflow. In practice it won't be an issue, since the driver stops polling + // once the query plan is empty. + int i = nextIndex.getAndIncrement(); + Object[] nodes = getNodes(); + return (i >= nodes.length) ? null : (Node) nodes[i]; + } + + @NonNull + @Override + public Iterator iterator() { + int i = nextIndex.get(); + Object[] nodes = getNodes(); + if (i >= nodes.length) { + return Collections.emptyIterator(); + } else { + return Iterators.forArray(Arrays.copyOfRange(nodes, i, nodes.length, Node[].class)); + } + } + + @Override + public int size() { + return Math.max(getNodes().length - nextIndex.get(), 0); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlan.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlan.java new file mode 100644 index 00000000000..0130744de51 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlan.java @@ -0,0 +1,45 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import edu.umd.cs.findbugs.annotations.NonNull; +import net.jcip.annotations.ThreadSafe; + +/** Query plan where nodes must be provided at construction time. */ +@ThreadSafe +public class SimpleQueryPlan extends QueryPlanBase { + + private final Object[] nodes; + + /** + * Creates a new query plan with the given nodes. + * + *

    For efficiency, there is no defensive copy, the provided array is used directly. The + * declared type is {@code Object[]} but all elements must be instances of {@link Node}. See + * {@link #getNodes()} for details. + * + * @param nodes the nodes to initially fill the queue with. + */ + public SimpleQueryPlan(@NonNull Object... nodes) { + this.nodes = nodes; + } + + @Override + protected Object[] getNodes() { + return nodes; + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index e4090ae7481..23e3fc2d14e 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -155,7 +155,25 @@ datastax-java-driver { # - com.datastax.oss.driver.internal.core.loadbalancing. # - com.datastax.dse.driver.internal.core.loadbalancing. # - # The driver provides a single implementation out of the box: DefaultLoadBalancingPolicy. + # The driver provides three implementations out of the box: + # + # - `DefaultLoadBalancingPolicy`: should almost always be used; it requires a local datacenter + # to be specified either programmatically when creating the session, or via the configuration + # option: datastax-java-driver.basic.load-balancing-policy.local-datacenter. It can also + # use a highly efficient slow replica avoidance mechanism, which is by default enabled – see + # the option: datastax-java-driver.basic.load-balancing-policy.slow-replica-avoidance. + # - `DcInferringLoadBalancingPolicy`: similar to `DefaultLoadBalancingPolicy`, but does not + # require a local datacenter to be defined, in which case it will attempt to infer the local + # datacenter from the provided contact points, if possible; if that fails, it will throw an + # error during session initialization. This policy is intended mostly for ETL tools and + # should not be used by normal applications. + # - `BasicLoadBalancingPolicy`: similar to `DefaultLoadBalancingPolicy`, but does not have + # the slow replica avoidance mechanism. More importantly, it is the only policy capable of + # operating without local datacenter defined, in which case it will consider nodes in the + # cluster in a datacenter-agnostic way. Beware that this could cause spikes in + # cross-datacenter traffic! This policy is provided mostly as a starting point for users + # wishing to implement their own load balancing policy; it should not be used as is in normal + # applications. # # You can also specify a custom class that implements LoadBalancingPolicy and has a public # constructor with two arguments: the DriverContext and a String representing the profile name. @@ -390,25 +408,42 @@ datastax-java-driver { set-keyspace-timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} # The driver maintains a connection pool to each node, according to the distance assigned to it - # by the load balancing policy. If the distance is IGNORED, no connections are maintained. + # by the load balancing policy. + # If the distance is LOCAL, then local.size connections are opened; if the distance is REMOTE, + # then remote.size connections are opened. If the distance is IGNORED, no connections at all + # are maintained. pool { - local { - # The number of connections in the pool. - # - # Each connection can handle many concurrent requests, so 1 is generally a good place to - # start. You should only need higher values in very high performance scenarios, where - # connections might start maxing out their I/O thread (see the driver's online manual for - # more tuning instructions). - # - # Required: yes - # Modifiable at runtime: yes; when the change is detected, all active pools will be notified - # and will adjust their size. - # Overridable in a profile: no - size = 1 - } - remote { - size = 1 - } + # The number of connections in the pool for a node whose distance is LOCAL, that is, a node + # that belongs to the local datacenter, as inferred by the load balancing or defined by the + # option: datastax-java-driver.basic.load-balancing-policy.local-datacenter. + # + # Each connection can handle many concurrent requests, so 1 is generally a good place to + # start. You should only need higher values in very high performance scenarios, where + # connections might start maxing out their I/O thread (see the driver's online manual for + # more tuning instructions). + # + # Required: yes + # Modifiable at runtime: yes; when the change is detected, all active pools will be notified + # and will adjust their size. + # Overridable in a profile: no + local.size = 1 + + # The number of connections in the pool for a node whose distance is REMOTE, that is, a node + # that does not belong to the local datacenter. + # + # Note: by default, the built-in load-balancing policies will never assign the REMOTE distance + # to any node, to avoid cross-datacenter network traffic. If you want to change this behavior + # and understand the consequences, configure your policy to accept nodes in remote + # datacenters by adjusting the following advanced options: + # + # - datastax-java-driver.advanced.load-balancing-policy.dc-failover.max-nodes-per-remote-dc + # - datastax-java-driver.advanced.load-balancing-policy.dc-failover.allow-for-local-consistency-levels + # + # Required: yes + # Modifiable at runtime: yes; when the change is detected, all active pools will be notified + # and will adjust their size. + # Overridable in a profile: no + remote.size = 1 } # The maximum number of requests that can be executed concurrently on a connection. This must be @@ -464,6 +499,46 @@ datastax-java-driver { warn-on-init-error = true } + # Advanced options for the built-in load-balancing policies. + advanced.load-balancing-policy { + # Cross-datacenter failover configuration: configure the load-balancing policies to use nodes + # in remote datacenters. + dc-failover { + # The maximum number of nodes to contact in each remote datacenter. + # + # By default, this number is zero, to avoid cross-datacenter network traffic. When this + # number is greater than zero: + # + # - The load policies will assign the REMOTE distance to that many nodes in each remote + # datacenter. + # - The driver will then attempt to open connections to those nodes. The actual number of + # connections to open to each one of those nodes is configurable via the option: + # datastax-java-driver.advanced.connection.pool.remote.size. + # - The load-balancing policies will include those remote nodes (and only those) in query + # plans, effectively enabling cross-datacenter failover. + # + # Beware that enabling such failover can result in cross-datacenter network traffic spikes, + # if the local datacenter is down or experiencing high latencies! + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: yes + max-nodes-per-remote-dc = 0 + + # Whether cross-datacenter failover should be allowed for requests executed with local + # consistency levels (LOCAL_ONE, LOCAL_QUORUM and LOCAL_SERIAL). + # + # This is disabled by default. Enabling this feature may have unexpected results, since a + # local consistency level may have different semantics depending on the replication factor in + # use in each datacenter. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: yes + allow-for-local-consistency-levels = false + } + } + # Whether to schedule reconnection attempts if all contact points are unreachable on the first # initialization attempt. # diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcAgnosticTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcAgnosticTest.java new file mode 100644 index 00000000000..3004ea36931 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcAgnosticTest.java @@ -0,0 +1,56 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import java.util.Optional; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class BasicLoadBalancingPolicyDcAgnosticTest extends BasicLoadBalancingPolicyQueryPlanTest { + + @Before + @Override + public void setup() { + super.setup(); + when(defaultProfile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) + .thenReturn(false); + when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1)); + when(metadataManager.getMetadata()).thenReturn(metadata); + when(metadata.getTokenMap()).thenAnswer(invocation -> Optional.of(this.tokenMap)); + + // since there is no local datacenter defined, the policy should behave with DC awareness + // disabled and pick nodes regardless of their datacenters; we therefore expect all tests of + // BasicLoadBalancingPolicyQueryPlanTest to pass even with the below DC distribution. + when(node1.getDatacenter()).thenReturn("dc1"); + when(node2.getDatacenter()).thenReturn("dc2"); + when(node3.getDatacenter()).thenReturn("dc3"); + when(node4.getDatacenter()).thenReturn("dc4"); + when(node5.getDatacenter()).thenReturn(null); + + policy = createAndInitPolicy(); + + assertThat(policy.getLiveNodes().dc(null)).containsExactly(node1, node2, node3, node4, node5); + assertThat(policy.getLiveNodes().dcs()).isEmpty(); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcFailoverTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcFailoverTest.java new file mode 100644 index 00000000000..9ad2f8503a0 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDcFailoverTest.java @@ -0,0 +1,153 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.internal.core.metadata.DefaultNode; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import java.util.Map; +import java.util.UUID; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class BasicLoadBalancingPolicyDcFailoverTest extends BasicLoadBalancingPolicyQueryPlanTest { + + @Mock protected DefaultNode node6; + @Mock protected DefaultNode node7; + @Mock protected DefaultNode node8; + @Mock protected DefaultNode node9; + + @Test + @Override + public void should_prioritize_single_replica() { + when(request.getRoutingKeyspace()).thenReturn(KEYSPACE); + when(request.getRoutingKey()).thenReturn(ROUTING_KEY); + when(tokenMap.getReplicas(KEYSPACE, ROUTING_KEY)).thenReturn(ImmutableSet.of(node3)); + + // node3 always first, round-robin on the rest, then remote nodes + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node3, node1, node2, node4, node5, node7, node8); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node3, node2, node1, node4, node5, node7, node8); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node3, node1, node2, node4, node5, node7, node8); + + // Should not shuffle replicas since there is only one + verify(policy, never()).shuffleHead(any(), eq(1)); + // But should shuffle remote nodes + verify(policy, times(3)).shuffleHead(any(), eq(4)); + } + + @Test + @Override + public void should_prioritize_and_shuffle_replicas() { + when(request.getRoutingKeyspace()).thenReturn(KEYSPACE); + when(request.getRoutingKey()).thenReturn(ROUTING_KEY); + when(tokenMap.getReplicas(KEYSPACE, ROUTING_KEY)) + .thenReturn(ImmutableSet.of(node2, node3, node5, node8)); + + // node 5 and 8 being in a remote DC, they don't get a boost for being a replica + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node2, node3, node1, node4, node5, node7, node8); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node2, node3, node1, node4, node5, node7, node8); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node2, node3, node1, node4, node5, node7, node8); + + // should shuffle replicas + verify(policy, times(3)).shuffleHead(any(), eq(2)); + // should shuffle remote nodes + verify(policy, times(3)).shuffleHead(any(), eq(4)); + // No power of two choices with only two replicas + verify(session, never()).getPools(); + } + + @Override + protected void assertRoundRobinQueryPlans() { + // nodes 4 to 9 being in a remote DC, they always appear after nodes 1, 2, 3 + for (int i = 0; i < 3; i++) { + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node1, node2, node3, node4, node5, node7, node8); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node2, node3, node1, node4, node5, node7, node8); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly(node3, node1, node2, node4, node5, node7, node8); + } + // should shuffle remote nodes + verify(policy, atLeast(1)).shuffleHead(any(), eq(4)); + } + + @Override + protected BasicLoadBalancingPolicy createAndInitPolicy() { + when(node4.getDatacenter()).thenReturn("dc2"); + when(node5.getDatacenter()).thenReturn("dc2"); + when(node6.getDatacenter()).thenReturn("dc2"); + when(node7.getDatacenter()).thenReturn("dc3"); + when(node8.getDatacenter()).thenReturn("dc3"); + when(node9.getDatacenter()).thenReturn("dc3"); + // Accept 2 nodes per remote DC + when(defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .thenReturn(2); + when(defaultProfile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS)) + .thenReturn(false); + // Use a subclass to disable shuffling, we just spy to make sure that the shuffling method was + // called (makes tests easier) + BasicLoadBalancingPolicy policy = + spy( + new BasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME) { + @Override + protected void shuffleHead(Object[] currentNodes, int headLength) { + // nothing (keep in same order) + } + }); + Map nodes = + ImmutableMap.builder() + .put(UUID.randomUUID(), node1) + .put(UUID.randomUUID(), node2) + .put(UUID.randomUUID(), node3) + .put(UUID.randomUUID(), node4) + .put(UUID.randomUUID(), node5) + .put(UUID.randomUUID(), node6) + .put(UUID.randomUUID(), node7) + .put(UUID.randomUUID(), node8) + .put(UUID.randomUUID(), node9) + .build(); + policy.init(nodes, distanceReporter); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node4, node5); // only 2 allowed + assertThat(policy.getLiveNodes().dc("dc3")).containsExactly(node7, node8); // only 2 allowed + return policy; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java new file mode 100644 index 00000000000..762720ac014 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java @@ -0,0 +1,220 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.UUID; +import java.util.function.Predicate; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class BasicLoadBalancingPolicyDistanceTest extends LoadBalancingPolicyTestBase { + + @Mock private Predicate filter; + + private ImmutableMap nodes; + + @Before + @Override + public void setup() { + super.setup(); + when(filter.test(node1)).thenReturn(true); + when(filter.test(node2)).thenReturn(true); + when(filter.test(node3)).thenReturn(true); + when(filter.test(node4)).thenReturn(true); + when(context.getNodeFilter(DriverExecutionProfile.DEFAULT_NAME)).thenReturn(filter); + when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2, node3)); + nodes = + ImmutableMap.of( + UUID.randomUUID(), node1, UUID.randomUUID(), node2, UUID.randomUUID(), node3); + } + + @Test + public void should_report_IGNORED_when_excluded_by_filter() { + // Given + given(filter.test(node1)).willReturn(false); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.IGNORED); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node2, node3); + } + + @Test + public void should_report_LOCAL_when_dc_agnostic() { + // Given + given(defaultProfile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) + .willReturn(false); + given(node1.getDatacenter()).willReturn(null); + given(node2.getDatacenter()).willReturn("dc1"); + given(node3.getDatacenter()).willReturn("dc2"); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); + assertThat(policy.getLiveNodes().dc(null)).containsExactly(node1, node2, node3); + } + + @Test + public void should_report_LOCAL_when_node_in_local_dc() { + // Given + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); + } + + @Test + public void should_report_IGNORED_when_node_not_in_local_dc() { + // Given + given(node1.getDatacenter()).willReturn(null); + given(node2.getDatacenter()).willReturn("dc2"); + given(node3.getDatacenter()).willReturn("dc3"); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + // Then + // Note: driver 3 would have reported LOCAL for node1 since its datacenter is null + verify(distanceReporter).setDistance(node1, NodeDistance.IGNORED); + verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); + verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); + assertThat(policy.getLiveNodes().dc(null)).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc1")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc2")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc3")).isEmpty(); + } + + @Test + public void should_report_REMOTE_when_node_not_in_local_dc_and_dc_failover_enabled() { + // Given + given(node1.getDatacenter()).willReturn("dc2"); + given(node2.getDatacenter()).willReturn("dc3"); + given(node3.getDatacenter()).willReturn("dc4"); + given( + defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .willReturn(1); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node2, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node3, NodeDistance.REMOTE); + assertThat(policy.getLiveNodes().dc("dc1")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node1); + assertThat(policy.getLiveNodes().dc("dc3")).containsExactly(node2); + assertThat(policy.getLiveNodes().dc("dc4")).containsExactly(node3); + } + + @Test + public void should_report_IGNORED_when_node_not_in_local_dc_and_too_many_nodes_for_dc_failover() { + // Given + given(node1.getDatacenter()).willReturn("dc2"); + given(node2.getDatacenter()).willReturn("dc2"); + given(node3.getDatacenter()).willReturn("dc2"); + given( + defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .willReturn(2); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node2, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); + assertThat(policy.getLiveNodes().dc("dc1")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node1, node2); + } + + @Test + public void should_report_REMOTE_when_remote_node_up_and_dc_failover() { + // Given + given(node1.getDatacenter()).willReturn("dc2"); + given(node2.getDatacenter()).willReturn("dc2"); + given(node3.getDatacenter()).willReturn("dc2"); + given(node4.getDatacenter()).willReturn("dc2"); + given( + defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .willReturn(4); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + policy.onUp(node4); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node2, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node3, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node4, NodeDistance.REMOTE); + assertThat(policy.getLiveNodes().dc("dc1")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node1, node2, node3, node4); + } + + @Test + public void should_report_IGNORED_when_remote_node_up_and_too_many_nodes_for_dc_failover() { + // Given + given(node1.getDatacenter()).willReturn("dc2"); + given(node2.getDatacenter()).willReturn("dc2"); + given(node3.getDatacenter()).willReturn("dc2"); + given(node4.getDatacenter()).willReturn("dc2"); + given( + defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .willReturn(3); + BasicLoadBalancingPolicy policy = createPolicy(); + // When + policy.init(nodes, distanceReporter); + policy.onUp(node4); + // Then + verify(distanceReporter).setDistance(node1, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node2, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node3, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node4, NodeDistance.IGNORED); + assertThat(policy.getLiveNodes().dc("dc1")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node1, node2, node3); + } + + @NonNull + protected BasicLoadBalancingPolicy createPolicy() { + return new BasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java index f8dee137d64..6640b2b946c 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java @@ -39,7 +39,7 @@ // TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) @RunWith(MockitoJUnitRunner.Silent.class) -public class BasicLoadBalancingPolicyEventsTest extends DefaultLoadBalancingPolicyTestBase { +public class BasicLoadBalancingPolicyEventsTest extends LoadBalancingPolicyTestBase { @Mock private Predicate filter; @@ -62,7 +62,7 @@ public void should_remove_down_node_from_live_set() { policy.onDown(node2); // Then - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); verify(distanceReporter, never()).setDistance(eq(node2), any(NodeDistance.class)); // should have been called only once, during initialization, but not during onDown verify(filter).test(node2); @@ -74,7 +74,7 @@ public void should_remove_removed_node_from_live_set() { policy.onRemove(node2); // Then - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); verify(distanceReporter, never()).setDistance(eq(node2), any(NodeDistance.class)); // should have been called only once, during initialization, but not during onRemove verify(filter).test(node2); @@ -89,7 +89,7 @@ public void should_set_added_node_to_local() { verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); verify(filter).test(node3); // Not added to the live set yet, we're waiting for the pool to open - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); } @Test @@ -102,7 +102,7 @@ public void should_ignore_added_node_when_filtered() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); } @Test @@ -115,7 +115,8 @@ public void should_ignore_added_node_when_remote_dc() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); + assertThat(policy.getLiveNodes().dc("dc2")).isEmpty(); } @Test @@ -126,7 +127,7 @@ public void should_add_up_node_to_live_set() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); verify(filter).test(node3); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2, node3); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); } @Test @@ -140,7 +141,7 @@ public void should_ignore_up_node_when_filtered() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); verify(filter).test(node3); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); } @Test @@ -153,7 +154,8 @@ public void should_ignore_up_node_when_remote_dc() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); + assertThat(policy.getLiveNodes().dc("dc2")).isEmpty(); } @NonNull @@ -162,7 +164,7 @@ protected BasicLoadBalancingPolicy createAndInitPolicy() { new BasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME); policy.init( ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), distanceReporter); - assertThat(policy.liveNodes).containsExactlyInAnyOrder(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); return policy; } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java index b4bca1638a6..56caff5c0aa 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java @@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.filter; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -39,14 +38,7 @@ // TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) @RunWith(MockitoJUnitRunner.Silent.class) -public class BasicLoadBalancingPolicyInitTest extends DefaultLoadBalancingPolicyTestBase { - - @Override - public void setup() { - super.setup(); - reset(defaultProfile); - when(defaultProfile.getName()).thenReturn(DriverExecutionProfile.DEFAULT_NAME); - } +public class BasicLoadBalancingPolicyInitTest extends LoadBalancingPolicyTestBase { @Test public void should_use_local_dc_if_provided_via_config() { @@ -63,7 +55,7 @@ public void should_use_local_dc_if_provided_via_config() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); } @Test @@ -79,7 +71,7 @@ public void should_use_local_dc_if_provided_via_context() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); verify(defaultProfile, never()) .getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, null); } @@ -89,15 +81,22 @@ public void should_not_infer_local_dc_if_not_provided() { // Given when(defaultProfile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) .thenReturn(false); + when(node1.getDatacenter()).thenReturn("dc1"); + when(node2.getDatacenter()).thenReturn("dc2"); + when(node3.getDatacenter()).thenReturn("dc3"); BasicLoadBalancingPolicy policy = new BasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME) {}; // When policy.init( - ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), distanceReporter); + ImmutableMap.of( + UUID.randomUUID(), node1, UUID.randomUUID(), node2, UUID.randomUUID(), node3), + distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).isEmpty(); + assertThat(policy.getLocalDatacenter()).isNull(); + // should not warn about contact points not being in the same DC + verify(appender, never()).doAppend(loggingEventCaptor.capture()); } @Test @@ -148,13 +147,12 @@ public void should_include_nodes_from_local_dc_if_local_dc_set() { verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); // But only include UP or UNKNOWN nodes in the live set - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node3); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node3); } @Test public void should_ignore_nodes_from_remote_dcs_if_local_dc_set() { // Given - when(context.getLocalDatacenter(DriverExecutionProfile.DEFAULT_NAME)).thenReturn("dc1"); when(node2.getDatacenter()).thenReturn("dc2"); when(node3.getDatacenter()).thenReturn("dc3"); when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2)); @@ -170,12 +168,17 @@ public void should_ignore_nodes_from_remote_dcs_if_local_dc_set() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); } @Test public void should_not_ignore_nodes_from_remote_dcs_if_local_dc_not_set() { // Given + when(defaultProfile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) + .thenReturn(false); + when(node2.getDatacenter()).thenReturn("dc2"); + when(node3.getDatacenter()).thenReturn("dc3"); + when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2)); BasicLoadBalancingPolicy policy = createPolicy(); // When @@ -188,7 +191,7 @@ public void should_not_ignore_nodes_from_remote_dcs_if_local_dc_not_set() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node2, node3); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); } @Test @@ -209,7 +212,7 @@ public void should_ignore_nodes_excluded_by_filter() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); } @NonNull diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyQueryPlanTest.java index f5c68e79c2b..518203e57c7 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyQueryPlanTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyQueryPlanTest.java @@ -31,7 +31,6 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Metadata; import com.datastax.oss.driver.api.core.metadata.TokenMap; import com.datastax.oss.driver.api.core.metadata.token.Token; @@ -52,7 +51,7 @@ // TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) @RunWith(MockitoJUnitRunner.Silent.class) -public class BasicLoadBalancingPolicyQueryPlanTest extends DefaultLoadBalancingPolicyTestBase { +public class BasicLoadBalancingPolicyQueryPlanTest extends LoadBalancingPolicyTestBase { protected static final CqlIdentifier KEYSPACE = CqlIdentifier.fromInternal("ks"); protected static final ByteBuffer ROUTING_KEY = Bytes.fromHexString("0xdeadbeef"); @@ -74,10 +73,6 @@ public void setup() { when(metadata.getTokenMap()).thenAnswer(invocation -> Optional.of(this.tokenMap)); policy = createAndInitPolicy(); - - // Note: this test relies on the fact that the policy uses a CopyOnWriteArraySet which preserves - // insertion order. - assertThat(policy.liveNodes).containsExactly(node1, node2, node3, node4, node5); } @Test @@ -186,7 +181,7 @@ public void should_use_round_robin_when_token_map_absent() { } @Test - public void should_round_robin_and_log_error_when_request_throws() { + public void should_use_round_robin_and_log_error_when_request_throws() { // Given given(request.getKeyspace()).willThrow(new NullPointerException()); // When @@ -197,7 +192,7 @@ public void should_round_robin_and_log_error_when_request_throws() { .contains("Unexpected error while trying to compute query plan"); } - private void assertRoundRobinQueryPlans() { + protected void assertRoundRobinQueryPlans() { for (int i = 0; i < 3; i++) { assertThat(policy.newQueryPlan(request, session)) .containsExactly(node1, node2, node3, node4, node5); @@ -253,8 +248,14 @@ public void should_prioritize_and_shuffle_replicas() { protected BasicLoadBalancingPolicy createAndInitPolicy() { // Use a subclass to disable shuffling, we just spy to make sure that the shuffling method was // called (makes tests easier) - NonShufflingBasicLoadBalancingPolicy policy = - spy(new NonShufflingBasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME)); + BasicLoadBalancingPolicy policy = + spy( + new BasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME) { + @Override + protected void shuffleHead(Object[] currentNodes, int headLength) { + // nothing (keep in same order) + } + }); policy.init( ImmutableMap.of( UUID.randomUUID(), node1, @@ -263,17 +264,7 @@ protected BasicLoadBalancingPolicy createAndInitPolicy() { UUID.randomUUID(), node4, UUID.randomUUID(), node5), distanceReporter); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3, node4, node5); return policy; } - - static class NonShufflingBasicLoadBalancingPolicy extends BasicLoadBalancingPolicy { - NonShufflingBasicLoadBalancingPolicy(DriverContext context, String profileName) { - super(context, profileName); - } - - @Override - protected void shuffleHead(Object[] currentNodes, int replicaCount) { - // nothing (keep in same order) - } - } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java new file mode 100644 index 00000000000..38faf7d1beb --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java @@ -0,0 +1,87 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import java.util.Map; +import java.util.UUID; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class DcInferringLoadBalancingPolicyDcFailoverTest + extends BasicLoadBalancingPolicyDcFailoverTest { + + @Override + @Before + public void setup() { + given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); + super.setup(); + } + + @Override + protected DcInferringLoadBalancingPolicy createAndInitPolicy() { + when(node4.getDatacenter()).thenReturn("dc2"); + when(node5.getDatacenter()).thenReturn("dc2"); + when(node6.getDatacenter()).thenReturn("dc2"); + when(node7.getDatacenter()).thenReturn("dc3"); + when(node8.getDatacenter()).thenReturn("dc3"); + when(node9.getDatacenter()).thenReturn("dc3"); + // Accept 2 nodes per remote DC + when(defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .thenReturn(2); + when(defaultProfile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS)) + .thenReturn(false); + // Use a subclass to disable shuffling, we just spy to make sure that the shuffling method was + // called (makes tests easier) + DcInferringLoadBalancingPolicy policy = + spy( + new DcInferringLoadBalancingPolicy(context, DEFAULT_NAME) { + @Override + protected void shuffleHead(Object[] array, int n) {} + }); + Map nodes = + ImmutableMap.builder() + .put(UUID.randomUUID(), node1) + .put(UUID.randomUUID(), node2) + .put(UUID.randomUUID(), node3) + .put(UUID.randomUUID(), node4) + .put(UUID.randomUUID(), node5) + .put(UUID.randomUUID(), node6) + .put(UUID.randomUUID(), node7) + .put(UUID.randomUUID(), node8) + .put(UUID.randomUUID(), node9) + .build(); + policy.init(nodes, distanceReporter); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node4, node5); // only 2 allowed + assertThat(policy.getLiveNodes().dc("dc3")).containsExactly(node7, node8); // only 2 allowed + return policy; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java new file mode 100644 index 00000000000..6d644edcf2a --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java @@ -0,0 +1,62 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.BDDMockito.given; + +import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import edu.umd.cs.findbugs.annotations.NonNull; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class DcInferringLoadBalancingPolicyDistanceTest + extends BasicLoadBalancingPolicyDistanceTest { + + @Override + @Before + public void setup() { + given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); + super.setup(); + } + + @Override + public void should_report_LOCAL_when_dc_agnostic() { + // This policy cannot operate when contact points are from different DCs + Throwable error = catchThrowable(super::should_report_LOCAL_when_dc_agnostic); + assertThat(error) + .isInstanceOfSatisfying( + IllegalStateException.class, + ise -> + assertThat(ise) + .hasMessageContaining( + "No local DC was provided, but the contact points are from different DCs") + .hasMessageContaining("node1=null") + .hasMessageContaining("node2=dc1") + .hasMessageContaining("node3=dc2")); + } + + @NonNull + @Override + protected BasicLoadBalancingPolicy createPolicy() { + return new DcInferringLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java index 7535e8c8fce..aa01ff08acf 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java @@ -42,7 +42,7 @@ protected BasicLoadBalancingPolicy createAndInitPolicy() { new DcInferringLoadBalancingPolicy(context, DEFAULT_NAME); policy.init( ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), distanceReporter); - assertThat(policy.getLiveNodes()).containsOnly(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsOnly(node1, node2); reset(distanceReporter); return policy; } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java index c0355ea5198..b57f0050985 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java @@ -38,7 +38,7 @@ import org.junit.Before; import org.junit.Test; -public class DcInferringLoadBalancingPolicyInitTest extends DefaultLoadBalancingPolicyTestBase { +public class DcInferringLoadBalancingPolicyInitTest extends LoadBalancingPolicyTestBase { @Override @Before @@ -58,7 +58,7 @@ public void should_use_local_dc_if_provided_via_config() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); } @Test @@ -74,7 +74,7 @@ public void should_use_local_dc_if_provided_via_context() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); verify(defaultProfile, never()) .getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, null); } @@ -91,7 +91,7 @@ public void should_infer_local_dc_from_contact_points() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); } @Test @@ -190,7 +190,7 @@ public void should_include_nodes_from_local_dc() { verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); // But only include UP or UNKNOWN nodes in the live set - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node3); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node3); } @Test @@ -211,7 +211,7 @@ public void should_ignore_nodes_from_remote_dcs() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); } @Test @@ -233,7 +233,7 @@ public void should_ignore_nodes_excluded_by_filter() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); } @NonNull diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyQueryPlanTest.java index 1c2b8f09e67..f60ed95697e 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyQueryPlanTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyQueryPlanTest.java @@ -25,7 +25,7 @@ public class DcInferringLoadBalancingPolicyQueryPlanTest extends DefaultLoadBalancingPolicyQueryPlanTest { @Override - protected DefaultLoadBalancingPolicy createAndInitPolicy() { + protected DcInferringLoadBalancingPolicy createAndInitPolicy() { DcInferringLoadBalancingPolicy policy = spy( new DcInferringLoadBalancingPolicy(context, DEFAULT_NAME) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java new file mode 100644 index 00000000000..34302a196e7 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java @@ -0,0 +1,87 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import java.util.Map; +import java.util.UUID; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class DefaultLoadBalancingPolicyDcFailoverTest + extends BasicLoadBalancingPolicyDcFailoverTest { + + @Override + @Before + public void setup() { + given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); + super.setup(); + } + + @Override + protected DefaultLoadBalancingPolicy createAndInitPolicy() { + when(node4.getDatacenter()).thenReturn("dc2"); + when(node5.getDatacenter()).thenReturn("dc2"); + when(node6.getDatacenter()).thenReturn("dc2"); + when(node7.getDatacenter()).thenReturn("dc3"); + when(node8.getDatacenter()).thenReturn("dc3"); + when(node9.getDatacenter()).thenReturn("dc3"); + // Accept 2 nodes per remote DC + when(defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .thenReturn(2); + when(defaultProfile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS)) + .thenReturn(false); + // Use a subclass to disable shuffling, we just spy to make sure that the shuffling method was + // called (makes tests easier) + DefaultLoadBalancingPolicy policy = + spy( + new DefaultLoadBalancingPolicy(context, DEFAULT_NAME) { + @Override + protected void shuffleHead(Object[] array, int n) {} + }); + Map nodes = + ImmutableMap.builder() + .put(UUID.randomUUID(), node1) + .put(UUID.randomUUID(), node2) + .put(UUID.randomUUID(), node3) + .put(UUID.randomUUID(), node4) + .put(UUID.randomUUID(), node5) + .put(UUID.randomUUID(), node6) + .put(UUID.randomUUID(), node7) + .put(UUID.randomUUID(), node8) + .put(UUID.randomUUID(), node9) + .build(); + policy.init(nodes, distanceReporter); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node4, node5); // only 2 allowed + assertThat(policy.getLiveNodes().dc("dc3")).containsExactly(node7, node8); // only 2 allowed + return policy; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java new file mode 100644 index 00000000000..8db9d0d1019 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java @@ -0,0 +1,61 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.BDDMockito.given; + +import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import edu.umd.cs.findbugs.annotations.NonNull; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +// TODO fix unnecessary stubbing of config option in parent class (and stop using "silent" runner) +@RunWith(MockitoJUnitRunner.Silent.class) +public class DefaultLoadBalancingPolicyDistanceTest extends BasicLoadBalancingPolicyDistanceTest { + + @Override + @Before + public void setup() { + given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); + super.setup(); + } + + @Override + public void should_report_LOCAL_when_dc_agnostic() { + // This policy cannot operate in dc-agnostic mode + Throwable error = catchThrowable(super::should_report_LOCAL_when_dc_agnostic); + assertThat(error) + .isInstanceOfSatisfying( + IllegalStateException.class, + ise -> + assertThat(ise) + .hasMessageContaining("the local DC must be explicitly set") + .hasMessageContaining("node1=null") + .hasMessageContaining("node2=dc1") + .hasMessageContaining("node3=dc2") + .hasMessageContaining("Current DCs in this cluster are: dc1, dc2")); + } + + @NonNull + @Override + protected BasicLoadBalancingPolicy createPolicy() { + return new DefaultLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java index 5c0f1b8c581..22f80b1f36d 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java @@ -41,7 +41,7 @@ protected DefaultLoadBalancingPolicy createAndInitPolicy() { DefaultLoadBalancingPolicy policy = new DefaultLoadBalancingPolicy(context, DEFAULT_NAME); policy.init( ImmutableMap.of(UUID.randomUUID(), node1, UUID.randomUUID(), node2), distanceReporter); - assertThat(policy.getLiveNodes()).containsOnly(node1, node2); + assertThat(policy.getLiveNodes().dc("dc1")).containsOnly(node1, node2); reset(distanceReporter); return policy; } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java index 2c5cd8eb0fe..c6202c3432b 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java @@ -38,7 +38,7 @@ import org.junit.Before; import org.junit.Test; -public class DefaultLoadBalancingPolicyInitTest extends DefaultLoadBalancingPolicyTestBase { +public class DefaultLoadBalancingPolicyInitTest extends LoadBalancingPolicyTestBase { @Override @Before @@ -58,7 +58,7 @@ public void should_use_local_dc_if_provided_via_config() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); } @Test @@ -74,7 +74,7 @@ public void should_use_local_dc_if_provided_via_context() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); verify(defaultProfile, never()) .getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, null); } @@ -92,7 +92,7 @@ public void should_infer_local_dc_if_no_explicit_contact_points() { policy.init(ImmutableMap.of(UUID.randomUUID(), node1), distanceReporter); // Then - assertThat(policy.getLocalDatacenter()).contains("dc1"); + assertThat(policy.getLocalDatacenter()).isEqualTo("dc1"); } @Test @@ -158,7 +158,7 @@ public void should_include_nodes_from_local_dc() { verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); // But only include UP or UNKNOWN nodes in the live set - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1, node3); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node3); } @Test @@ -179,7 +179,9 @@ public void should_ignore_nodes_from_remote_dcs() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); + assertThat(policy.getLiveNodes().dc("dc2")).isEmpty(); + assertThat(policy.getLiveNodes().dc("dc3")).isEmpty(); } @Test @@ -201,7 +203,7 @@ public void should_ignore_nodes_excluded_by_filter() { verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes()).containsExactlyInAnyOrder(node1); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); } @NonNull diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java index b3e65fdd4f2..207a5b409b7 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java @@ -78,9 +78,10 @@ public void setup() { given(metadata.getTokenMap()).willAnswer(invocation -> Optional.of(tokenMap)); super.setup(); dsePolicy = (DefaultLoadBalancingPolicy) policy; - // Note: tests in this class rely on the fact that the policy uses a CopyOnWriteArraySet which - // preserves insertion order, which is why we can use containsExactly() throughout this class. - assertThat(dsePolicy.getLiveNodes()).containsExactly(node1, node2, node3, node4, node5); + // Note: this assertion relies on the fact that policy.getLiveNodes() implementation preserves + // insertion order. + assertThat(dsePolicy.getLiveNodes().dc("dc1")) + .containsExactly(node1, node2, node3, node4, node5); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java index 76517fc2c0c..f87f5b38f43 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java @@ -29,8 +29,7 @@ import org.junit.Test; import org.mockito.Mock; -public class DefaultLoadBalancingPolicyRequestTrackerTest - extends DefaultLoadBalancingPolicyTestBase { +public class DefaultLoadBalancingPolicyRequestTrackerTest extends LoadBalancingPolicyTestBase { @Mock Request request; @Mock DriverExecutionProfile profile; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/LoadBalancingPolicyTestBase.java similarity index 85% rename from core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java rename to core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/LoadBalancingPolicyTestBase.java index c98ee523d02..33eb0697321 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/LoadBalancingPolicyTestBase.java @@ -26,6 +26,7 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.internal.core.DefaultConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metadata.DefaultNode; import com.datastax.oss.driver.internal.core.metadata.MetadataManager; @@ -40,7 +41,7 @@ import org.slf4j.LoggerFactory; @RunWith(MockitoJUnitRunner.class) -public abstract class DefaultLoadBalancingPolicyTestBase { +public abstract class LoadBalancingPolicyTestBase { @Mock protected DefaultNode node1; @Mock protected DefaultNode node2; @@ -71,6 +72,13 @@ public void setup() { .thenReturn("dc1"); when(defaultProfile.getBoolean(DefaultDriverOption.LOAD_BALANCING_POLICY_SLOW_AVOIDANCE, true)) .thenReturn(true); + when(defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .thenReturn(0); + when(defaultProfile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS)) + .thenReturn(false); + when(defaultProfile.getString(DefaultDriverOption.REQUEST_CONSISTENCY)).thenReturn("ONE"); when(context.getMetadataManager()).thenReturn(metadataManager); @@ -83,6 +91,7 @@ public void setup() { } when(context.getLocalDatacenter(anyString())).thenReturn(null); + when(context.getConsistencyLevelRegistry()).thenReturn(new DefaultConsistencyLevelRegistry()); } @After diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSetTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSetTest.java new file mode 100644 index 00000000000..80268c037b4 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSetTest.java @@ -0,0 +1,59 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +import com.datastax.oss.driver.api.core.metadata.Node; +import org.junit.Test; + +public class DcAgnosticNodeSetTest { + + @Test + public void should_add_node() { + DcAgnosticNodeSet set = new DcAgnosticNodeSet(); + Node node = mock(Node.class); + assertThat(set.add(node)).isTrue(); + assertThat(set.add(node)).isFalse(); + } + + @Test + public void should_remove_node() { + DcAgnosticNodeSet set = new DcAgnosticNodeSet(); + Node node = mock(Node.class); + set.add(node); + assertThat(set.remove(node)).isTrue(); + assertThat(set.remove(node)).isFalse(); + } + + @Test + public void should_return_all_nodes() { + DcAgnosticNodeSet set = new DcAgnosticNodeSet(); + Node node1 = mock(Node.class); + set.add(node1); + Node node2 = mock(Node.class); + set.add(node2); + assertThat(set.dc(null)).contains(node1, node2); + assertThat(set.dc("irrelevant")).contains(node1, node2); + } + + @Test + public void should_return_empty_dcs() { + DcAgnosticNodeSet set = new DcAgnosticNodeSet(); + assertThat(set.dcs()).isEmpty(); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSetTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSetTest.java new file mode 100644 index 00000000000..4a021a3e838 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSetTest.java @@ -0,0 +1,81 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.metadata.Node; +import org.junit.Test; + +public class MultiDcNodeSetTest { + + @Test + public void should_add_node() { + MultiDcNodeSet set = new MultiDcNodeSet(); + Node node1 = mockNode("dc1"); + assertThat(set.add(node1)).isTrue(); + assertThat(set.add(node1)).isFalse(); + Node node2 = mockNode("dc2"); + assertThat(set.add(node2)).isTrue(); + assertThat(set.add(node2)).isFalse(); + } + + @Test + public void should_remove_node() { + MultiDcNodeSet set = new MultiDcNodeSet(); + Node node1 = mockNode("dc1"); + set.add(node1); + assertThat(set.remove(node1)).isTrue(); + assertThat(set.remove(node1)).isFalse(); + Node node2 = mockNode("dc2"); + set.add(node2); + assertThat(set.remove(node2)).isTrue(); + assertThat(set.remove(node2)).isFalse(); + } + + @Test + public void should_return_all_nodes_in_dc() { + MultiDcNodeSet set = new MultiDcNodeSet(); + Node node1 = mockNode("dc1"); + set.add(node1); + Node node2 = mockNode("dc1"); + set.add(node2); + Node node3 = mockNode("dc2"); + set.add(node3); + assertThat(set.dc("dc1")).contains(node1, node2); + assertThat(set.dc("dc2")).contains(node3); + assertThat(set.dc("dc3")).isEmpty(); + assertThat(set.dc(null)).isEmpty(); + } + + @Test + public void should_return_all_dcs() { + MultiDcNodeSet set = new MultiDcNodeSet(); + Node node1 = mockNode("dc1"); + set.add(node1); + Node node2 = mockNode("dc2"); + set.add(node2); + assertThat(set.dcs()).contains("dc1", "dc2"); + } + + private Node mockNode(String dc) { + Node node = mock(Node.class); + when(node.getDatacenter()).thenReturn(dc); + return node; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSetTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSetTest.java new file mode 100644 index 00000000000..336d18a66ed --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSetTest.java @@ -0,0 +1,71 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.metadata.Node; +import org.junit.Test; + +public class SingleDcNodeSetTest { + + @Test + public void should_add_node() { + SingleDcNodeSet set = new SingleDcNodeSet("dc1"); + Node node1 = mockNode("dc1"); + assertThat(set.add(node1)).isTrue(); + assertThat(set.add(node1)).isFalse(); + Node node2 = mockNode("dc2"); + assertThat(set.add(node2)).isFalse(); + } + + @Test + public void should_remove_node() { + SingleDcNodeSet set = new SingleDcNodeSet("dc1"); + Node node = mockNode("dc1"); + set.add(node); + assertThat(set.remove(node)).isTrue(); + assertThat(set.remove(node)).isFalse(); + } + + @Test + public void should_return_all_nodes_if_local_dc() { + SingleDcNodeSet set = new SingleDcNodeSet("dc1"); + Node node1 = mockNode("dc1"); + set.add(node1); + Node node2 = mockNode("dc1"); + set.add(node2); + Node node3 = mockNode("dc2"); + set.add(node3); + assertThat(set.dc("dc1")).contains(node1, node2); + assertThat(set.dc("dc2")).isEmpty(); + assertThat(set.dc(null)).isEmpty(); + } + + @Test + public void should_return_only_local_dc() { + SingleDcNodeSet set = new SingleDcNodeSet("dc1"); + assertThat(set.dcs()).contains("dc1"); + } + + private Node mockNode(String dc) { + Node node = mock(Node.class); + when(node.getDatacenter()).thenReturn(dc); + return node; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlanTest.java new file mode 100644 index 00000000000..c460ecaaeec --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/CompositeQueryPlanTest.java @@ -0,0 +1,40 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class CompositeQueryPlanTest extends QueryPlanTestBase { + + @Override + protected QueryPlan newQueryPlan(Node... nodes) { + Object[] n1 = new Object[nodes.length / 2]; + Object[] n2 = new Object[nodes.length - n1.length]; + System.arraycopy(nodes, 0, n1, 0, n1.length); + System.arraycopy(nodes, n1.length, n2, 0, n2.length); + return new CompositeQueryPlan( + new SimpleQueryPlan(n1), + new LazyQueryPlan() { + @Override + protected Object[] computeNodes() { + return n2; + } + }); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlanTest.java new file mode 100644 index 00000000000..b6a7cbf39e7 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/LazyQueryPlanTest.java @@ -0,0 +1,34 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class LazyQueryPlanTest extends QueryPlanTestBase { + + @Override + protected QueryPlan newQueryPlan(Node... nodes) { + return new LazyQueryPlan() { + @Override + protected Object[] computeNodes() { + return nodes; + } + }; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanTestBase.java similarity index 58% rename from core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanTest.java rename to core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanTestBase.java index 8157a2662ee..8c9f4d7b9ff 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/QueryPlanTestBase.java @@ -16,16 +16,21 @@ package com.datastax.oss.driver.internal.core.util.collection; import static com.datastax.oss.driver.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.datastax.oss.driver.api.core.metadata.Node; +import java.util.Comparator; import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class QueryPlanTest { +public abstract class QueryPlanTestBase { @Mock private Node node1; @Mock private Node node2; @@ -33,7 +38,7 @@ public class QueryPlanTest { @Test public void should_poll_elements() { - QueryPlan queryPlan = new QueryPlan(node1, node2, node3); + QueryPlan queryPlan = newQueryPlan(node1, node2, node3); assertThat(queryPlan.poll()).isSameAs(node1); assertThat(queryPlan.poll()).isSameAs(node2); assertThat(queryPlan.poll()).isSameAs(node3); @@ -41,9 +46,49 @@ public void should_poll_elements() { assertThat(queryPlan.poll()).isNull(); } + @Test + public void should_poll_elements_concurrently() throws InterruptedException { + for (int runs = 0; runs < 5; runs++) { + Node[] nodes = new Node[1000]; + for (int i = 0; i < 1000; i++) { + nodes[i] = mock(Node.class, "node" + i); + when(nodes[i].getOpenConnections()).thenReturn(i); + } + QueryPlan queryPlan = newQueryPlan(nodes); + Set actual = + new ConcurrentSkipListSet<>(Comparator.comparingInt(Node::getOpenConnections)); + Thread[] threads = new Thread[5]; + for (int i = 0; i < 5; i++) { + threads[i] = + new Thread( + () -> { + while (true) { + Node node = queryPlan.poll(); + if (node == null) { + return; + } + actual.add(node); + } + }); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + assertThat(actual).hasSize(1000); + Iterator iterator = actual.iterator(); + for (int i = 0; iterator.hasNext(); i++) { + Node node = iterator.next(); + assertThat(node.getOpenConnections()).isEqualTo(i); + } + } + } + @Test public void should_return_size() { - QueryPlan queryPlan = new QueryPlan(node1, node2, node3); + QueryPlan queryPlan = newQueryPlan(node1, node2, node3); assertThat(queryPlan.size()).isEqualTo(3); queryPlan.poll(); assertThat(queryPlan.size()).isEqualTo(2); @@ -57,7 +102,7 @@ public void should_return_size() { @Test public void should_return_iterator() { - QueryPlan queryPlan = new QueryPlan(node1, node2, node3); + QueryPlan queryPlan = newQueryPlan(node1, node2, node3); Iterator iterator3 = queryPlan.iterator(); queryPlan.poll(); Iterator iterator2 = queryPlan.iterator(); @@ -74,4 +119,6 @@ public void should_return_iterator() { assertThat(iterator0).toIterable().isEmpty(); assertThat(iterator00).toIterable().isEmpty(); } + + protected abstract QueryPlan newQueryPlan(Node... nodes); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlanTest.java new file mode 100644 index 00000000000..d8ee2cdd506 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/collection/SimpleQueryPlanTest.java @@ -0,0 +1,29 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util.collection; + +import com.datastax.oss.driver.api.core.metadata.Node; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SimpleQueryPlanTest extends QueryPlanTestBase { + + @Override + protected QueryPlan newQueryPlan(Node... nodes) { + return new SimpleQueryPlan((Object[]) nodes); + } +} diff --git a/examples/pom.xml b/examples/pom.xml index f2124c8c3f3..3255b92e6ae 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -135,6 +135,11 @@ bcrypt 0.8.0 + + + io.projectreactor + reactor-core + diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/failover/CrossDatacenterFailover.java b/examples/src/main/java/com/datastax/oss/driver/examples/failover/CrossDatacenterFailover.java new file mode 100644 index 00000000000..19d6b98d9d6 --- /dev/null +++ b/examples/src/main/java/com/datastax/oss/driver/examples/failover/CrossDatacenterFailover.java @@ -0,0 +1,456 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.examples.failover; + +import com.datastax.dse.driver.api.core.cql.reactive.ReactiveRow; +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.DriverException; +import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.NoNodeAvailableException; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.config.OptionsMap; +import com.datastax.oss.driver.api.core.config.TypedDriverOption; +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; +import com.datastax.oss.driver.api.core.servererrors.QueryConsistencyException; +import com.datastax.oss.driver.api.core.servererrors.UnavailableException; +import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import reactor.core.publisher.Flux; + +/** + * This example illustrates how to implement a cross-datacenter failover strategy from application + * code. + * + *

    Starting with driver 4.10, cross-datacenter failover is also provided as a configuration + * option for built-in load balancing policies. See Load + * balancing in the manual. + * + *

    This example demonstrates how to achieve the same effect in application code, which confers + * more fained-grained control over which statements should be retried and where. + * + *

    The logic that decides whether or not a cross-DC failover should be attempted is presented in + * the {@link #shouldFailover(DriverException)} method below; study it carefully and adapt it to + * your needs if necessary. + * + *

    The actual request execution and failover code is presented in 3 different programming styles: + * + *

      + *
    1. Synchronous: see the {@link #writeSync()} method below; + *
    2. Asynchronous: see the {@link #writeAsync()} method below; + *
    3. Reactive (using Reactor): see the {@link + * #writeReactive()} method below. + *
    + * + * The 3 styles are identical in terms of failover effect; they are all included merely to help + * programmers pick the variant that is closest to the style they use. + * + *

    Preconditions: + * + *

      + *
    • An Apache Cassandra(R) cluster with two datacenters, dc1 and dc2, containing at least 3 + * nodes in each datacenter, is running and accessible through the contact point: + * 127.0.0.1:9042. + *
    + * + *

    Side effects: + * + *

      + *
    1. Creates a new keyspace {@code failover} in the cluster, with replication factor 3 in both + * datacenters. If a keyspace with this name already exists, it will be reused; + *
    2. Creates a new table {@code failover.orders}. If a table with that name exists already, it + * will be reused; + *
    3. Tries to write a row in the table using the local datacenter dc1; + *
    4. If the local datacenter dc1 is down, retries the write in the remote datacenter dc2. + *
    + * + * @see Java driver online + * manual + */ +public class CrossDatacenterFailover { + + public static void main(String[] args) throws Exception { + + CrossDatacenterFailover client = new CrossDatacenterFailover(); + + try { + + // Note: when this example is executed, at least the local DC must be available + // since the driver will try to reach contact points in that DC. + + client.connect(); + client.createSchema(); + + // To fully exercise this example, try to stop the entire dc1 here; then observe how + // the writes executed below will first fail in dc1, then be diverted to dc2, where they will + // succeed. + + client.writeSync(); + client.writeAsync(); + client.writeReactive(); + + } finally { + client.close(); + } + } + + private CqlSession session; + + private CrossDatacenterFailover() {} + + /** Initiates a connection to the cluster. */ + private void connect() { + + // For simplicity, this example uses a 100% in-memory configuration loader, but the same + // configuration can be achieved with the more traditional file-based approach. + // Simply put the below snippet in your application.conf file to get the same config: + + /* + datastax-java-driver { + basic.contact-points = [ "127.0.0.1:9042" ] + basic.load-balancing-policy.local-datacenter = "dc1" + basic.request.consistency = LOCAL_QUORUM + profiles { + remote { + basic.load-balancing-policy.local-datacenter = "dc2" + basic.request.consistency = LOCAL_ONE + } + } + } + */ + + OptionsMap options = OptionsMap.driverDefaults(); + // set the datacenter to dc1 in the default profile; this makes dc1 the local datacenter + options.put(TypedDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, "dc1"); + // set the datacenter to dc2 in the "remote" profile + options.put("remote", TypedDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, "dc2"); + // make sure to provide a contact point belonging to dc1, not dc2! + options.put(TypedDriverOption.CONTACT_POINTS, Collections.singletonList("127.0.0.1:9042")); + // in this example, the default consistency level is LOCAL_QUORUM + options.put(TypedDriverOption.REQUEST_CONSISTENCY, "LOCAL_QUORUM"); + // but when failing over, the consistency level will be automatically downgraded to LOCAL_ONE + options.put("remote", TypedDriverOption.REQUEST_CONSISTENCY, "LOCAL_ONE"); + + session = CqlSession.builder().withConfigLoader(DriverConfigLoader.fromMap(options)).build(); + + System.out.println("Connected to cluster with session: " + session.getName()); + } + + /** Creates the schema (keyspace) and table for this example. */ + private void createSchema() { + + session.execute( + "CREATE KEYSPACE IF NOT EXISTS failover WITH replication " + + "= {'class':'NetworkTopologyStrategy', 'dc1':3, 'dc2':3}"); + + session.execute( + "CREATE TABLE IF NOT EXISTS failover.orders (" + + "product_id uuid," + + "timestamp timestamp," + + "price double," + + "PRIMARY KEY (product_id,timestamp)" + + ")"); + } + + /** Inserts data synchronously using the local DC, retrying if necessary in a remote DC. */ + private void writeSync() { + + System.out.println("------- DC failover (sync) ------- "); + + Statement statement = + SimpleStatement.newInstance( + "INSERT INTO failover.orders " + + "(product_id, timestamp, price) " + + "VALUES (" + + "756716f7-2e54-4715-9f00-91dcbea6cf50," + + "'2018-02-26T13:53:46.345+01:00'," + + "2.34)"); + + try { + + // try the statement using the default profile, which targets the local datacenter dc1. + session.execute(statement); + + System.out.println("Write succeeded"); + + } catch (DriverException e) { + + if (shouldFailover(e)) { + + System.out.println("Write failed in local DC, retrying in remote DC"); + + try { + + // try the statement using the remote profile, which targets the remote datacenter dc2. + session.execute(statement.setExecutionProfileName("remote")); + + System.out.println("Write succeeded"); + + } catch (DriverException e2) { + + System.out.println("Write failed in remote DC"); + + e2.printStackTrace(); + } + } + } + // let other errors propagate + } + + /** Inserts data asynchronously using the local DC, retrying if necessary in a remote DC. */ + private void writeAsync() throws ExecutionException, InterruptedException { + + System.out.println("------- DC failover (async) ------- "); + + Statement statement = + SimpleStatement.newInstance( + "INSERT INTO failover.orders " + + "(product_id, timestamp, price) " + + "VALUES (" + + "756716f7-2e54-4715-9f00-91dcbea6cf50," + + "'2018-02-26T13:53:46.345+01:00'," + + "2.34)"); + + CompletionStage result = + // try the statement using the default profile, which targets the local datacenter dc1. + session + .executeAsync(statement) + .handle( + (rs, error) -> { + if (error == null) { + return CompletableFuture.completedFuture(rs); + } else { + if (error instanceof DriverException + && shouldFailover((DriverException) error)) { + System.out.println("Write failed in local DC, retrying in remote DC"); + // try the statement using the remote profile, which targets the remote + // datacenter dc2. + return session.executeAsync(statement.setExecutionProfileName("remote")); + } + // let other errors propagate + return CompletableFutures.failedFuture(error); + } + }) + // unwrap (flatmap) the nested future + .thenCompose(future -> future) + .whenComplete( + (rs, error) -> { + if (error == null) { + System.out.println("Write succeeded"); + } else { + System.out.println("Write failed in remote DC"); + error.printStackTrace(); + } + }); + + // for the sake of this example, wait for the operation to finish + result.toCompletableFuture().get(); + } + + /** Inserts data reactively using the local DC, retrying if necessary in a remote DC. */ + private void writeReactive() { + + System.out.println("------- DC failover (reactive) ------- "); + + Statement statement = + SimpleStatement.newInstance( + "INSERT INTO failover.orders " + + "(product_id, timestamp, price) " + + "VALUES (" + + "756716f7-2e54-4715-9f00-91dcbea6cf50," + + "'2018-02-26T13:53:46.345+01:00'," + + "2.34)"); + + Flux result = + // try the statement using the default profile, which targets the local datacenter dc1. + Flux.from(session.executeReactive(statement)) + .onErrorResume( + DriverException.class, + error -> { + if (shouldFailover(error)) { + System.out.println("Write failed in local DC, retrying in remote DC"); + // try the statement using the remote profile, which targets the remote + // datacenter dc2. + return session.executeReactive(statement.setExecutionProfileName("remote")); + } else { + return Flux.error(error); + } + }) + .doOnComplete(() -> System.out.println("Write succeeded")) + .doOnError( + error -> { + System.out.println("Write failed"); + error.printStackTrace(); + }); + + // for the sake of this example, wait for the operation to finish + result.blockLast(); + } + + /** + * Analyzes the error and decides whether to failover to a remote DC. + * + *

    The logic below categorizes driver exceptions in four main groups: + * + *

      + *
    1. Total DC outage: all nodes in DC were known to be down when the request was executed; + *
    2. Partial DC outage: one or many nodes responded, but reported a replica availability + * problem; + *
    3. DC unreachable: one or many nodes were queried, but none responded (timeout); + *
    4. Other errors. + *
    + * + * A DC failover is authorized for the first three groups above: total DC outage, partial DC + * outage, and DC unreachable. + * + *

    This logic is provided as a good starting point for users to create their own DC failover + * strategy; please adjust it to your exact needs. + */ + private boolean shouldFailover(DriverException mainException) { + + if (mainException instanceof NoNodeAvailableException) { + + // No node could be tried, because all nodes in the query plan were down. This could be a + // total DC outage, so trying another DC makes sense. + System.out.println("All nodes were down in this datacenter, failing over"); + return true; + + } else if (mainException instanceof AllNodesFailedException) { + + // Many nodes were tried (as decided by the retry policy), but all failed. This could be a + // partial DC outage: some nodes were up, but the replicas were down. + + boolean failover = false; + + // Inspect the error to find out how many coordinators were tried, and which errors they + // returned. + for (Entry> entry : + ((AllNodesFailedException) mainException).getAllErrors().entrySet()) { + + Node coordinator = entry.getKey(); + List errors = entry.getValue(); + + System.out.printf( + "Node %s in DC %s was tried %d times but failed with:%n", + coordinator.getEndPoint(), coordinator.getDatacenter(), errors.size()); + + for (Throwable nodeException : errors) { + + System.out.printf("\t- %s%n", nodeException); + + // If the error was a replica availability error, then we know that some replicas were + // down in this DC. Retrying in another DC could solve the problem. Other errors don't + // necessarily mean that the DC is unavailable, so we ignore them. + if (isReplicaAvailabilityError(nodeException)) { + failover = true; + } + } + } + + // Authorize the failover if at least one of the coordinators reported a replica availability + // error that could be solved by trying another DC. + if (failover) { + System.out.println( + "Some nodes tried in this DC reported a replica availability error, failing over"); + } else { + System.out.println("All nodes tried in this DC failed unexpectedly, not failing over"); + } + return failover; + + } else if (mainException instanceof DriverTimeoutException) { + + // One or many nodes were tried, but none replied in a timely manner, and the timeout defined + // by the option `datastax-java-driver.basic.request.timeout` was triggered. + // This could be a DC outage as well, or a network partition issue, so trying another DC may + // make sense. + // Note about SLAs: if your application needs to comply with SLAs, and the maximum acceptable + // latency for a request is equal or very close to the request timeout, beware that failing + // over to a different datacenter here could potentially break your SLA. + + System.out.println( + "No node in this DC replied before the timeout was triggered, failing over"); + return true; + + } else if (mainException instanceof CoordinatorException) { + + // Only one node was tried, and it failed (and the retry policy did not tell the driver to + // retry this request, but rather to surface the error immediately). This is rather unusual + // as the driver's default retry policy retries most of these errors, but some custom retry + // policies could decide otherwise. So we apply the same logic as above: if the error is a + // replica availability error, we authorize the failover. + + Node coordinator = ((CoordinatorException) mainException).getCoordinator(); + System.out.printf( + "Node %s in DC %s was tried once but failed with: %s%n", + coordinator.getEndPoint(), coordinator.getDatacenter(), mainException); + + boolean failover = isReplicaAvailabilityError(mainException); + if (failover) { + System.out.println( + "The only node tried in this DC reported a replica availability error, failing over"); + } else { + System.out.println("The only node tried in this DC failed unexpectedly, not failing over"); + } + return failover; + + } else { + + // The request failed with a rather unusual error. This generally indicates a more serious + // issue, since the retry policy decided to surface the error immediately. Trying another DC + // is probably a bad idea. + System.out.println("The request failed unexpectedly, not failing over: " + mainException); + return false; + } + } + + /** + * Whether the given error is a replica availability error. + * + *

    A replica availability error means that the initial consistency level could not be met + * because not enough replicas were alive. + * + *

    When this error happens, it can be worth failing over to a remote DC, as long as at + * least one of the following conditions apply: + * + *

      + *
    1. if the initial consistency level was DC-local, trying another DC may succeed; + *
    2. if the initial consistency level can be downgraded, then retrying again may succeed (in + * the same DC, or in another one). + *
    + * + * In this example both conditions above apply, so we authorize the failover whenever we detect a + * replica availability error. + */ + private boolean isReplicaAvailabilityError(Throwable t) { + return t instanceof UnavailableException || t instanceof QueryConsistencyException; + } + + private void close() { + if (session != null) { + session.close(); + } + } +} diff --git a/faq/README.md b/faq/README.md index 842804431a2..315bf934cd2 100644 --- a/faq/README.md +++ b/faq/README.md @@ -71,6 +71,20 @@ code. An example of downgrading retries implemented at application level can be [JAVA-2900]: https://datastax-oss.atlassian.net/browse/JAVA-2900 [examples repository]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/retry/DowngradingRetry.java +### Where is the cross-datacenter failover feature that existed in driver 3? + +In driver 3, it was possible to configure the load balancing policy to automatically failover to +a remote datacenter, when the local datacenter is down. + +This ability is considered a misfeature and has been removed from driver 4.0 onwards. + +However, due to popular demand, cross-datacenter failover has been brought back to driver 4 in +version 4.10.0. + +If you are using a driver version >= 4.10.0, read the [manual](../manual/core/loadbalancing/) to +understand how to enable this feature; for driver versions < 4.10.0, this feature is simply not +available. + ### I want to set a date on a bound statement, where did `setTimestamp()` go? The driver now uses Java 8's improved date and time API. CQL type `timestamp` is mapped to diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/AllLoadBalancingPoliciesSimulacronIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/AllLoadBalancingPoliciesSimulacronIT.java new file mode 100644 index 00000000000..bee2aa21fb6 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/AllLoadBalancingPoliciesSimulacronIT.java @@ -0,0 +1,503 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.awaitility.Awaitility.await; + +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; +import com.datastax.oss.driver.api.core.NoNodeAvailableException; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeState; +import com.datastax.oss.driver.api.core.metadata.TokenMap; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.datastax.oss.protocol.internal.request.Query; +import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import com.datastax.oss.simulacron.common.cluster.QueryLog; +import com.datastax.oss.simulacron.common.stubbing.PrimeDsl; +import com.datastax.oss.simulacron.common.stubbing.PrimeDsl.RowBuilder; +import com.datastax.oss.simulacron.server.BoundCluster; +import com.datastax.oss.simulacron.server.BoundNode; +import com.datastax.oss.simulacron.server.BoundTopic; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +@Category(ParallelizableTests.class) +@RunWith(DataProviderRunner.class) +public class AllLoadBalancingPoliciesSimulacronIT { + + @ClassRule + public static final SimulacronRule SIMULACRON_RULE = + new SimulacronRule(ClusterSpec.builder().withNodes(5, 5, 5)); + + @Before + public void reset() { + SIMULACRON_RULE.cluster().start(); + SIMULACRON_RULE.cluster().clearLogs(); + SIMULACRON_RULE.cluster().clearPrimes(true); + SIMULACRON_RULE + .cluster() + .prime( + PrimeDsl.when("SELECT * FROM system_schema.keyspaces") + .then(new RowBuilder().columnTypes(KEYSPACE_COLUMNS).row(KEYSPACE_ROW).build())); + } + + @Test + @DataProvider({ + "BasicLoadBalancingPolicy,dc1", + "DefaultLoadBalancingPolicy,dc1", + "DcInferringLoadBalancingPolicy,dc1", + "DcInferringLoadBalancingPolicy,null", + }) + public void should_round_robin_within_local_dc_when_dc_aware_but_not_token_aware( + String lbp, String dc) { + + // given: DC is provided or inferred, token awareness is disabled and remote DCs are allowed + try (CqlSession session = newSession(lbp, dc, 2, true, false)) { + + // when: a query is executed 50 times. + for (int i = 0; i < 50; i++) { + session.execute(QUERY); + } + + // then: each node in local DC should get an equal number of requests. + for (int i = 0; i < 5; i++) { + assertThat(queries(0, i).count()).isEqualTo(10); + } + + // then: no node in the remote DC should get a request. + assertThat(queries(1).count()).isEqualTo(0); + assertThat(queries(2).count()).isEqualTo(0); + } + } + + @Test + @DataProvider({ + "BasicLoadBalancingPolicy,dc1,ONE", + "BasicLoadBalancingPolicy,dc1,LOCAL_ONE", + "BasicLoadBalancingPolicy,dc1,TWO", + "BasicLoadBalancingPolicy,dc1,QUORUM", + "BasicLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DefaultLoadBalancingPolicy,dc1,ONE", + "DefaultLoadBalancingPolicy,dc1,LOCAL_ONE", + "DefaultLoadBalancingPolicy,dc1,TWO", + "DefaultLoadBalancingPolicy,dc1,QUORUM", + "DefaultLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DcInferringLoadBalancingPolicy,dc1,ONE", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_ONE", + "DcInferringLoadBalancingPolicy,dc1,TWO", + "DcInferringLoadBalancingPolicy,dc1,QUORUM", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DcInferringLoadBalancingPolicy,null,ONE", + "DcInferringLoadBalancingPolicy,null,LOCAL_ONE", + "DcInferringLoadBalancingPolicy,null,TWO", + "DcInferringLoadBalancingPolicy,null,QUORUM", + "DcInferringLoadBalancingPolicy,null,LOCAL_QUORUM", + }) + public void should_use_local_replicas_when_dc_aware_and_token_aware_and_enough_local_replicas_up( + String lbp, String dc, DefaultConsistencyLevel cl) { + + // given: DC is provided or inferred, token awareness enabled, remotes allowed, CL <= 2 + try (CqlSession session = newSession(lbp, dc, 2, true)) { + + // given: one replica and 2 non-replicas down in local DC, but CL <= 2 still achievable + List aliveReplicas = degradeLocalDc(session); + + // when: a query is executed 50 times and some nodes are down in the local DC. + for (int i = 0; i < 50; i++) { + session.execute( + SimpleStatement.newInstance(QUERY) + .setConsistencyLevel(cl) + .setRoutingKeyspace("test") + .setRoutingKey(ROUTING_KEY)); + } + + // then: all requests should be distributed to the remaining up replicas in local DC + BoundNode alive1 = findNode(aliveReplicas.get(0)); + BoundNode alive2 = findNode(aliveReplicas.get(1)); + assertThat(queries(alive1).count() + queries(alive2).count()).isEqualTo(50); + + // then: no node in the remote DCs should get a request. + assertThat(queries(1).count()).isEqualTo(0); + assertThat(queries(2).count()).isEqualTo(0); + } + } + + @Test + public void should_round_robin_within_all_dcs_when_dc_agnostic() { + + // given: DC-agnostic LBP, no local DC, remotes not allowed, token awareness enabled + try (CqlSession session = newSession("BasicLoadBalancingPolicy", null, 0, false)) { + + // when: a query is executed 150 times. + for (int i = 0; i < 150; i++) { + session.execute( + SimpleStatement.newInstance(QUERY) + // local CL should be ignored since there is no local DC + .setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM)); + } + + // then: each node should get 10 requests, even remote ones since the LBP is DC-agnostic. + for (int dc = 0; dc < 3; dc++) { + for (int n = 0; n < 5; n++) { + assertThat(queries(dc, n).count()).isEqualTo(10); + } + } + } + } + + @Test + @DataProvider({ + "BasicLoadBalancingPolicy,dc1,ONE", + "BasicLoadBalancingPolicy,dc1,TWO", + "BasicLoadBalancingPolicy,dc1,THREE", + "BasicLoadBalancingPolicy,dc1,QUORUM", + "BasicLoadBalancingPolicy,dc1,ANY", + "DefaultLoadBalancingPolicy,dc1,ONE", + "DefaultLoadBalancingPolicy,dc1,TWO", + "DefaultLoadBalancingPolicy,dc1,THREE", + "DefaultLoadBalancingPolicy,dc1,QUORUM", + "DefaultLoadBalancingPolicy,dc1,ANY", + "DcInferringLoadBalancingPolicy,dc1,ONE", + "DcInferringLoadBalancingPolicy,dc1,TWO", + "DcInferringLoadBalancingPolicy,dc1,THREE", + "DcInferringLoadBalancingPolicy,dc1,QUORUM", + "DcInferringLoadBalancingPolicy,dc1,ANY", + "DcInferringLoadBalancingPolicy,null,ONE", + "DcInferringLoadBalancingPolicy,null,TWO", + "DcInferringLoadBalancingPolicy,null,THREE", + "DcInferringLoadBalancingPolicy,null,QUORUM", + "DcInferringLoadBalancingPolicy,null,ANY", + }) + public void should_use_remote_nodes_when_no_up_nodes_in_local_dc_for_non_local_cl( + String lbp, String dc, DefaultConsistencyLevel cl) { + + // given: 1 remote allowed per DC and a non-local CL, token awareness enabled + try (CqlSession session = newSession(lbp, dc, 1, false)) { + + // given: local DC is down + stopLocalDc(session); + + // when: a query is executed 50 times and all nodes are down in local DC. + for (int i = 0; i < 50; i++) { + session.execute( + SimpleStatement.newInstance(QUERY) + .setConsistencyLevel(cl) + .setRoutingKeyspace("test") + .setRoutingKey(ROUTING_KEY)); + } + + // then: only 1 node in each remote DC should get requests (we can't know which ones exactly). + assertThat(queries(1).count() + queries(2).count()).isEqualTo(50); + } + } + + @Test + @DataProvider({ + "BasicLoadBalancingPolicy,dc1,LOCAL_ONE", + "BasicLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "BasicLoadBalancingPolicy,dc1,LOCAL_SERIAL", + "DefaultLoadBalancingPolicy,dc1,LOCAL_ONE", + "DefaultLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DefaultLoadBalancingPolicy,dc1,LOCAL_SERIAL", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_ONE", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_SERIAL", + "DcInferringLoadBalancingPolicy,null,LOCAL_ONE", + "DcInferringLoadBalancingPolicy,null,LOCAL_QUORUM", + "DcInferringLoadBalancingPolicy,null,LOCAL_SERIAL", + }) + public void should_not_use_remote_nodes_when_using_local_cl( + String lbp, String dc, DefaultConsistencyLevel cl) { + + // given: remotes allowed but not for local CL, token awareness enabled, local CL + try (CqlSession session = newSession(lbp, dc, 5, false)) { + + // given: local DC is down + stopLocalDc(session); + + // when: a query is executed 50 times and all nodes are down in local DC. + for (int i = 0; i < 50; i++) { + Throwable t = + catchThrowable( + () -> + session.execute( + SimpleStatement.newInstance(QUERY) + .setConsistencyLevel(cl) + .setRoutingKeyspace("test") + .setRoutingKey(ROUTING_KEY))); + + // then: expect a NNAE for a local CL since no local replicas available. + assertThat(t).isInstanceOf(NoNodeAvailableException.class); + } + + // then: no node in the remote DCs should get a request. + assertThat(queries(1).count()).isEqualTo(0); + assertThat(queries(2).count()).isEqualTo(0); + } + } + + @Test + @DataProvider({ + "BasicLoadBalancingPolicy,dc1,LOCAL_ONE", + "BasicLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DefaultLoadBalancingPolicy,dc1,LOCAL_ONE", + "DefaultLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_ONE", + "DcInferringLoadBalancingPolicy,dc1,LOCAL_QUORUM", + "DcInferringLoadBalancingPolicy,null,LOCAL_ONE", + "DcInferringLoadBalancingPolicy,null,LOCAL_QUORUM", + }) + public void should_use_remote_nodes_when_using_local_cl_if_allowed( + String lbp, String dc, DefaultConsistencyLevel cl) { + + // given: only one node allowed per remote DC and remotes allowed even for local CLs. + try (CqlSession session = newSession(lbp, dc, 1, true)) { + + // given: local DC is down + stopLocalDc(session); + + // when: a query is executed 50 times and all nodes are down in local DC. + for (int i = 0; i < 50; i++) { + session.execute( + SimpleStatement.newInstance(QUERY) + .setConsistencyLevel(cl) + .setRoutingKeyspace("test") + .setRoutingKey(ROUTING_KEY)); + } + + // then: only 1 node in each remote DC should get requests (we can't know which ones exactly). + assertThat(queries(1).count() + queries(2).count()).isEqualTo(50); + } + } + + @Test + @DataProvider({ + "BasicLoadBalancingPolicy,dc1", + "DefaultLoadBalancingPolicy,dc1", + "DcInferringLoadBalancingPolicy,dc1", + "DcInferringLoadBalancingPolicy,null" + }) + public void should_not_use_excluded_dc_using_node_filter(String lbp, String dc) { + + // given: remotes allowed even for local CLs, but node filter excluding dc2 + try (CqlSession session = newSession(lbp, dc, 5, true, true, excludeDc("dc2"))) { + + // when: A query is made and nodes for the local dc are available. + for (int i = 0; i < 50; i++) { + session.execute( + SimpleStatement.newInstance(QUERY) + .setRoutingKeyspace("test") + .setRoutingKey(ROUTING_KEY)); + } + + // then: only nodes in the local DC should have been queried. + assertThat(queries(0).count()).isEqualTo(50); + assertThat(queries(1).count()).isEqualTo(0); + assertThat(queries(2).count()).isEqualTo(0); + + // given: local DC is down + stopLocalDc(session); + + SIMULACRON_RULE.cluster().clearLogs(); + + // when: A query is made and all nodes in the local dc are down. + for (int i = 0; i < 50; i++) { + session.execute( + SimpleStatement.newInstance(QUERY) + .setRoutingKeyspace("test") + .setRoutingKey(ROUTING_KEY)); + } + + // then: Only nodes in DC3 should have been queried, since DC2 is excluded and DC1 is down. + assertThat(queries(0).count()).isEqualTo(0); + assertThat(queries(1).count()).isEqualTo(0); + assertThat(queries(2).count()).isEqualTo(50); + } + } + + private static final ByteBuffer ROUTING_KEY = ByteBuffer.wrap(new byte[] {1, 2, 3, 4}); + + private static final String[] KEYSPACE_COLUMNS = + new String[] { + "keyspace_name", "varchar", + "durable_writes", "boolean", + "replication", "map" + }; + + private static final Object[] KEYSPACE_ROW = + new Object[] { + "keyspace_name", + "test", + "durable_writes", + true, + "replication", + ImmutableMap.of( + "class", + "org.apache.cassandra.locator.NetworkTopologyStrategy", + "dc1", + "3", + "dc2", + "3", + "dc3", + "3") + }; + + private static final String QUERY = "SELECT * FROM test.foo"; + + private CqlSession newSession(String lbp, String dc, int maxRemoteNodes, boolean allowLocalCl) { + return newSession(lbp, dc, maxRemoteNodes, allowLocalCl, true); + } + + private CqlSession newSession( + String lbp, String dc, int maxRemoteNodes, boolean allowLocalCl, boolean tokenAware) { + return newSession(lbp, dc, maxRemoteNodes, allowLocalCl, tokenAware, null); + } + + private CqlSession newSession( + String lbp, + String dc, + int maxRemoteNodes, + boolean allowLocalCl, + boolean tokenAware, + Predicate nodeFilter) { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withBoolean(DefaultDriverOption.METADATA_SCHEMA_ENABLED, tokenAware) + .withString(DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS, lbp) + .withString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, dc) + .withInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC, + maxRemoteNodes) + .withBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, + allowLocalCl) + .build(); + return SessionUtils.newSession(SIMULACRON_RULE, null, null, null, nodeFilter, loader); + } + + private BoundNode findNode(Node node) { + BoundCluster simulacron = SIMULACRON_RULE.cluster(); + SocketAddress toFind = node.getEndPoint().resolve(); + for (BoundNode boundNode : simulacron.getNodes()) { + if (boundNode.getAddress().equals(toFind)) { + return boundNode; + } + } + throw new AssertionError("Could not find node: " + toFind); + } + + private void stopLocalDc(CqlSession session) { + SIMULACRON_RULE.cluster().dc(0).stop(); + awaitDown(nodesInDc(session, "dc1")); + } + + private List degradeLocalDc(CqlSession session) { + // stop 1 replica and 2 non-replicas in dc1 + List localReplicas = replicasInDc(session, "dc1"); + assertThat(localReplicas).hasSize(3); + BoundNode replica1 = findNode(localReplicas.get(0)); + + List localOthers = nonReplicasInDc(session, "dc1"); + assertThat(localOthers).hasSize(2); + BoundNode other1 = findNode(localOthers.get(0)); + BoundNode other2 = findNode(localOthers.get(1)); + + replica1.stop(); + other1.stop(); + other2.stop(); + + awaitDown(localReplicas.get(0), localOthers.get(0), localOthers.get(1)); + return localReplicas.subList(1, 3); + } + + private Stream queries(int dc, int node) { + return queries(SIMULACRON_RULE.cluster().dc(dc).node(node)); + } + + private Stream queries(int dc) { + return queries(SIMULACRON_RULE.cluster().dc(dc)); + } + + private Stream queries(BoundTopic topic) { + return topic.getLogs().getQueryLogs().stream() + .filter(q -> q.getFrame().message instanceof Query) + .filter(q -> ((Query) q.getFrame().message).query.equals(QUERY)); + } + + private List nodesInDc(CqlSession session, String dcName) { + return session.getMetadata().getNodes().values().stream() + .filter(n -> Objects.equals(n.getDatacenter(), dcName)) + .collect(Collectors.toList()); + } + + private List replicasInDc(CqlSession session, String dcName) { + assertThat(session.getMetadata().getTokenMap()).isPresent(); + TokenMap tokenMap = session.getMetadata().getTokenMap().get(); + return tokenMap.getReplicas("test", ROUTING_KEY).stream() + .filter(n -> Objects.equals(n.getDatacenter(), dcName)) + .collect(Collectors.toList()); + } + + private List nonReplicasInDc( + CqlSession session, @SuppressWarnings("SameParameterValue") String dcName) { + List nodes = nodesInDc(session, dcName); + nodes.removeAll(replicasInDc(session, dcName)); + return nodes; + } + + private Predicate excludeDc(@SuppressWarnings("SameParameterValue") String dcName) { + return node -> !Objects.equals(node.getDatacenter(), dcName); + } + + private void awaitDown(Node... nodes) { + awaitDown(Arrays.asList(nodes)); + } + + private void awaitDown(Iterable nodes) { + await() + .atMost(Duration.ofSeconds(10)) + .untilAsserted( + () -> { + for (Node node : nodes) { + assertThat(node.getState()).isEqualTo(NodeState.DOWN); + } + }); + } +} diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index dbb22712e32..3210c916a61 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -37,6 +37,9 @@ For each node, the policy computes a *distance* that determines how connections Typically, the distance will reflect network topology (e.g. local vs. remote datacenter), although that is entirely up to each policy implementation. It can also change over time. +The driver built-in policies only ever assign the `LOCAL` or `IGNORED` distance, to avoid cross- +datacenter traffic (see below to understand how to change this behavior). + #### Query plan Each time the driver executes a query, it asks the policy to compute a *query plan*, in other words @@ -50,23 +53,40 @@ return plans that: * only contain nodes that are known to be able to process queries, i.e. neither ignored nor down; * favor local nodes over remote ones. -### Default policy +### Built-in policies In previous versions, the driver provided a wide variety of built-in load balancing policies; in addition, they could be nested into each other, yielding an even higher number of choices. In our experience, this has proven to be too complicated: it's not obvious which policy(ies) to choose for -a given use case, and nested policies can sometimes affect each other's effects in subtle and hard -to predict ways. - -In driver 4+, we are taking a more opinionated approach: we provide a default load balancing policy, -that we consider the best choice for most cases. You can still write a -[custom implementation](#custom-implementation) if you have special requirements. - -#### Local only - -The default policy **only connects to a single datacenter**. The rationale is that a typical -multi-region deployment will collocate one or more application instances with each Cassandra -datacenter: +a given use case, and nested policies can sometimes affect each other's effects in subtle and hard- +to-predict ways. + +In driver 4+, we are taking a different approach: we provide only a handful of load balancing +policies, that we consider the best choices for most cases: + +- `DefaultLoadBalancingPolicy` should almost always be used; it requires a local datacenter to be + specified either programmatically when creating the session, or via the configuration (see below). + It can also use a highly efficient slow replica avoidance mechanism, which is by default enabled. +- `DcInferringLoadBalancingPolicy` is similar to `DefaultLoadBalancingPolicy`, but does not require + a local datacenter to be defined, in which case it will attempt to infer the local datacenter from + the provided contact points. If that's not possible, it will throw an error during session + initialization. This policy is intended mostly for ETL tools and is not recommended for normal + applications. +- `BasicLoadBalancingPolicy` is similar to `DefaultLoadBalancingPolicy`, but does not have the slow + replica avoidance mechanism. More importantly, it is the only policy capable of operating without + local datacenter defined, in which case it will consider nodes in the cluster in a datacenter- + agnostic way. Beware that this could cause spikes in cross-datacenter traffic! This policy is + provided mostly as a starting point for users wishing to implement their own load balancing + policy; it should not be used as is in normal applications. + +You can still write a [custom implementation](#custom-implementation) if you have special +requirements. + +#### Datacenter locality + +By default, both `DefaultLoadBalancingPolicy` and `DcInferringLoadBalancingPolicy` **only connect to +a single datacenter**. The rationale is that a typical multi-region deployment will collocate one or +more application instances with each Cassandra datacenter: ```ditaa /----+----\ @@ -96,14 +116,7 @@ datacenter: +-------------------+ +-------------------+ ``` -In previous driver versions, you could configure application-level failover, such as: "if all the -Cassandra nodes in DC1 are down, allow app1 to connect to the nodes in DC2". We now believe that -this is not the right place to handle this: if a whole datacenter went down at once, it probably -means a catastrophic failure happened in Region1, and the application node is down as well. -Failover should be cross-region instead (handled by the load balancer in this example). - -Therefore the default policy does not allow remote nodes; it only ever assigns the `LOCAL` or -`IGNORED` distance. You **must** provide a local datacenter name, either in the configuration: +When using these policies you **must** provide a local datacenter name, either in the configuration: ``` datastax-java-driver.basic.load-balancing-policy { @@ -126,7 +139,7 @@ that case, the driver will connect to 127.0.0.1:9042, and use that node's datace for a better out-of-the-box experience for users who have just downloaded the driver; beyond that initial development phase, you should provide explicit contact points and a local datacenter. -#### Finding the local datacenter +##### Finding the local datacenter To check which datacenters are defined in a given cluster, you can run [`nodetool status`]. It will print information about each node in the cluster, grouped by datacenters. Here is an example: @@ -165,6 +178,82 @@ data_center DC1 ``` +#### Cross-datacenter failover + +Since the driver by default only contacts nodes in the local datacenter, what happens if the whole +datacenter is down? Resuming the example shown in the diagram above, shouldn't the driver +temporarily allow app1 to connect to the nodes in DC2? + +We believe that, while appealing by its simplicity, such ability is not the right way to handle a +datacenter failure: resuming our example above, if the whole DC1 datacenter went down at once, it +probably means a catastrophic failure happened in Region1, and the application node is down as well. +Failover should be cross-region instead (handled by the load balancer in the above example). + +However, due to popular demand, starting with driver 4.10, we re-introduced cross-datacenter +failover in the driver built-in load balancing policies. + +Cross-datacenter failover is enabled with the following configuration option: + +``` +datastax-java-driver.advanced.load-balancing-policy.dc-failover { + max-nodes-per-remote-dc = 2 +} +``` + +The default for `max-nodes-per-remote-dc` is zero, which means that failover is disabled. Setting +this option to any value greater than zero will have the following effects: + +- The load balancing policies will assign the `REMOTE` distance to that many nodes *in each remote + datacenter*. +- The driver will then attempt to open connections to those nodes. The actual number of connections + to open to each one of those nodes is configurable, see [Connection pools](../pooling/) for + more details. By default, the driver opens only one connection to each node. +- Those remote nodes (and only those) will then become eligible for inclusion in query plans, + effectively enabling cross-datacenter failover. + +Beware that enabling such failover can result in cross-datacenter network traffic spikes, if the +local datacenter is down or experiencing high latencies! + +Cross-datacenter failover can also have unexpected consequences when using local consistency levels +(LOCAL_ONE, LOCAL_QUORUM and LOCAL_SERIAL). Indeed, a local consistency level may have different +semantics depending on the replication factor (RF) in use in each datacenter: if the local DC has +RF=3 for a given keyspace, but the remote DC has RF=1 for it, achieving LOCAL_QUORUM in the local DC +means 2 replicas required, but in the remote DC, only one will be required. + +For this reason, cross-datacenter failover for local consistency levels is disabled by default. If +you want to enable this and understand the consequences, then set the following option to true: + +``` +datastax-java-driver.advanced.load-balancing-policy.dc-failover { + allow-for-local-consistency-levels = true +} +``` + +##### Alternatives to driver-level cross-datacenter failover + +Before you jump into the failover technique explained above, please also consider the following +alternatives: + +1. **Application-level failover**: instead of letting the driver do the failover, implement the +failover logic in your application. Granted, this solution wouldn't be much better if the +application servers are co-located with the Cassandra datacenter itself. It's also a bit more work, +but at least, you would have full control over the failover procedure: you could for example decide, +based on the exact error that prevented the local datacenter from fulfilling a given request, +whether a failover would make sense, and which remote datacenter to use for that specific request. +Such a fine-grained logic is not possible with a driver-level failover. Besides, if you opt for this +approach, execution profiles can come in handy. See "Using multiple policies" below and also check +our [application-level failover example] for a good starting point. + +2. **Infrastructure-level failover**: in this scenario, the failover is handled by the +infrastructure. To resume our example above, if Region1 goes down, the load balancers in your +infrastructure would transparently switch all the traffic intended for that region to Region2, +possibly scaling up its bandwidth to cope with the network traffic spike. This is by far the best +solution for the cross-datacenter failover issue in general, but we acknowledge that it also +requires a purpose-built infrastructure. To help you explore this option, read our [white paper]. + +[application-level failover example]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/retry/CrossDatacenterFailover.java +[white paper]: https://www.datastax.com/sites/default/files/content/whitepaper/files/2019-09/Designing-Fault-Tolerant-Applications-DataStax.pdf + #### Token-aware The default policy is **token-aware** by default: requests will be routed in priority to the @@ -242,11 +331,20 @@ routing information, you need to provide it manually. ##### Policy behavior When the policy computes a query plan, it first inspects the statement's routing information. If -there isn't any, the query plan is a simple round-robin shuffle of all connected nodes. +there isn't any, the query plan is a simple round-robin shuffle of all connected nodes that are +located in the local datacenter. + +If the statement has routing information, the policy uses it to determine the *local* replicas that +hold the corresponding data. Then it returns a query plan containing these replicas shuffled in +random order, followed by a round-robin shuffle of the rest of the nodes. -If the statement has routing information, the policy uses it to determine the replicas that hold the -corresponding data. Then it returns a query plan containing the replicas shuffled in random order, -followed by a round-robin shuffle of the rest of the nodes. +If cross-datacenter failover has been activated as explained above, some remote nodes may appear in +query plans as well. With the driver built-in policies, remote nodes always come after local nodes +in query plans: this way, if the local datacenter is up, local nodes will be tried first, and remote +nodes are unlikely to ever be queried. If the local datacenter goes down however, all the local +nodes in query plans will likely fail, causing the query plans to eventually try remote nodes +instead. If the local datacenter unavailability persists, local nodes will be eventually marked down +and will be removed from query plans completely from query plans, until they are back up again. #### Optional node filtering @@ -284,7 +382,9 @@ If a programmatic filter is provided, the configuration option is ignored. You can use your own implementation by specifying its fully-qualified name in the configuration. -Study the [LoadBalancingPolicy] interface and the default implementation for the low-level details. +Study the [LoadBalancingPolicy] interface and the built-in [BasicLoadingBalancingPolicy] for the +low-level details. Feel free to extend `BasicLoadingBalancingPolicy` and override only the methods +that you wish to modify – but keep in mind that it may be simpler to just start from scratch. ### Using multiple policies @@ -325,6 +425,7 @@ Then it uses the "closest" distance for any given node. For example: [DriverContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/context/DriverContext.html [LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java [getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- [getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- [getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- diff --git a/pom.xml b/pom.xml index f4097e4d1a4..6d5d7f4c3d6 100644 --- a/pom.xml +++ b/pom.xml @@ -423,7 +423,7 @@ io.projectreactor reactor-bom - 2020.0.1 + 2020.0.2 pom import diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 88ba4cd8332..bba68707f8d 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -2,6 +2,15 @@ ### 4.10.0 +#### Cross-datacenter failover + +[JAVA-2899](https://datastax-oss.atlassian.net/browse/JAVA-2676) re-introduced the ability to +perform cross-datacenter failover using the driver's built-in load balancing policies. See [Load +balancing](../manual/core/loadbalancing/) in the manual for details. + +Cross-datacenter failover is disabled by default, therefore existing applications should not +experience any disruption. + #### New `RetryVerdict` API [JAVA-2900](https://datastax-oss.atlassian.net/browse/JAVA-2900) introduced [`RetryVerdict`], a new From e5f174dbae7af4cf3438355335e8e14f3d1f715f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 12:05:54 +0100 Subject: [PATCH 038/395] JAVA-2902: Consider computed values when validating constructors for immutable entities (#1520) --- changelog/README.md | 1 + .../oss/driver/mapper/ImmutableEntityIT.java | 13 +++- .../entity/DefaultEntityFactory.java | 11 +-- .../entity/EntityPropertyAnnotationsTest.java | 75 +++++++++++++++++++ 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 4c7cf9fbf4d..f3d5edda543 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2902: Consider computed values when validating constructors for immutable entities - [new feature] JAVA-2899: Re-introduce cross-DC failover in driver 4 - [new feature] JAVA-2900: Re-introduce consistency downgrading retries - [new feature] JAVA-2903: BlockHound integration diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java index ed1afdbfaf8..9ed1666f848 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java @@ -22,6 +22,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.mapper.MapperBuilder; +import com.datastax.oss.driver.api.mapper.annotations.Computed; import com.datastax.oss.driver.api.mapper.annotations.CqlName; import com.datastax.oss.driver.api.mapper.annotations.Dao; import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; @@ -73,7 +74,7 @@ public static void setup() { @Test public void should_insert_and_retrieve_immutable_entities() { ImmutableProduct originalProduct = - new ImmutableProduct(UUID.randomUUID(), "mock description", new Dimensions(1, 2, 3)); + new ImmutableProduct(UUID.randomUUID(), "mock description", new Dimensions(1, 2, 3), -1); dao.save(originalProduct); ImmutableProduct retrievedProduct = dao.findById(originalProduct.id()); @@ -88,10 +89,14 @@ public static class ImmutableProduct { private final String description; private final Dimensions dimensions; - public ImmutableProduct(UUID id, String description, Dimensions dimensions) { + @Computed("writetime(description)") + private final long writetime; + + public ImmutableProduct(UUID id, String description, Dimensions dimensions, long writetime) { this.id = id; this.description = description; this.dimensions = dimensions; + this.writetime = writetime; } public UUID id() { @@ -106,6 +111,10 @@ public Dimensions dimensions() { return dimensions; } + public long writetime() { + return writetime; + } + @Override public boolean equals(Object other) { if (other == this) { diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/DefaultEntityFactory.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/DefaultEntityFactory.java index e82832bf16f..6e5a9ac6488 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/DefaultEntityFactory.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/DefaultEntityFactory.java @@ -603,7 +603,7 @@ private void validateConstructor(EntityDefinition entity, TypeElement processedC if (entity.isMutable()) { validateNoArgConstructor(processedClass); } else { - validateAllColumnsConstructor(processedClass, entity.getAllColumns()); + validateAllValuesConstructor(processedClass, entity.getAllValues()); } } @@ -625,7 +625,7 @@ private void validateNoArgConstructor(TypeElement processedClass) { Entity.class.getSimpleName()); } - private void validateAllColumnsConstructor( + private void validateAllValuesConstructor( TypeElement processedClass, List columns) { for (Element child : processedClass.getEnclosedElements()) { if (child.getKind() == ElementKind.CONSTRUCTOR) { @@ -641,15 +641,16 @@ && areAssignable(columns, constructor.getParameters())) { columns.stream() .map( column -> - String.format("%s %s", column.getType().asTypeMirror(), column.getGetterName())) + String.format("%s %s", column.getType().asTypeMirror(), column.getJavaName())) .collect(Collectors.joining(", ")); context .getMessager() .error( processedClass, - "Immutable @%s-annotated class must have an \"all columns\" constructor. " - + "Expected signature: (%s).", + "Immutable @%s-annotated class must have an \"all values\" constructor. " + + "Expected signature: %s(%s).", Entity.class.getSimpleName(), + processedClass.getSimpleName(), signature); } diff --git a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityPropertyAnnotationsTest.java b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityPropertyAnnotationsTest.java index 59f0fb9e98d..ba047240057 100644 --- a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityPropertyAnnotationsTest.java +++ b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityPropertyAnnotationsTest.java @@ -19,12 +19,14 @@ import com.datastax.oss.driver.api.mapper.annotations.Computed; import com.datastax.oss.driver.api.mapper.annotations.Entity; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; +import com.datastax.oss.driver.api.mapper.annotations.PropertyStrategy; import com.datastax.oss.driver.api.mapper.annotations.Transient; import com.datastax.oss.driver.internal.mapper.processor.MapperProcessorTest; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; @@ -320,6 +322,79 @@ public static Object[][] entitiesWithErrors() { .build()) .build(), }, + { + "Mutable @Entity-annotated class must have a no-arg constructor.", + TypeSpec.classBuilder(ClassName.get("test", "Product")) + .addAnnotation(Entity.class) + .addField( + FieldSpec.builder(UUID.class, "id", Modifier.PRIVATE) + .addModifiers(Modifier.FINAL) + .addAnnotation(PartitionKey.class) + .build()) + .addMethod( + MethodSpec.constructorBuilder() + .addParameter(ParameterSpec.builder(UUID.class, "id").build()) + .addModifiers(Modifier.PUBLIC) + .addStatement("this.id = id") + .build()) + .addMethod( + MethodSpec.methodBuilder("getId") + .returns(UUID.class) + .addModifiers(Modifier.PUBLIC) + .addStatement("return id") + .build()) + .addMethod( + MethodSpec.methodBuilder("setId") + .addParameter(UUID.class, "id") + .addModifiers(Modifier.PUBLIC) + .addStatement("this.id = id") + .build()) + .build(), + }, + { + "Immutable @Entity-annotated class must have an \"all values\" constructor. " + + "Expected signature: Product(java.util.UUID id, java.lang.String name, long writetime).", + TypeSpec.classBuilder(ClassName.get("test", "Product")) + .addAnnotation(Entity.class) + .addAnnotation( + AnnotationSpec.builder(PropertyStrategy.class) + .addMember("mutable", "false") + .build()) + .addField( + FieldSpec.builder(UUID.class, "id", Modifier.PRIVATE) + .addModifiers(Modifier.FINAL) + .addAnnotation(PartitionKey.class) + .build()) + .addField( + FieldSpec.builder(String.class, "name", Modifier.PRIVATE) + .addModifiers(Modifier.FINAL) + .build()) + .addField( + FieldSpec.builder(String.class, "writetime", Modifier.PRIVATE) + .addModifiers(Modifier.FINAL) + .addAnnotation( + AnnotationSpec.builder(Computed.class).addMember("value", "$S", "").build()) + .build()) + .addMethod( + MethodSpec.methodBuilder("getId") + .returns(UUID.class) + .addModifiers(Modifier.PUBLIC) + .addStatement("return id") + .build()) + .addMethod( + MethodSpec.methodBuilder("getName") + .returns(String.class) + .addModifiers(Modifier.PUBLIC) + .addStatement("return name") + .build()) + .addMethod( + MethodSpec.methodBuilder("getWritetime") + .returns(Long.TYPE) + .addModifiers(Modifier.PUBLIC) + .addStatement("return writetime") + .build()) + .build(), + }, }; } } From 22d8bc5f5d81adad760377b85f6617cf6fb723fd Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 12:07:30 +0100 Subject: [PATCH 039/395] JAVA-2911: Prevent control connection from scheduling too many reconnections (#1521) --- changelog/README.md | 1 + .../core/control/ControlConnection.java | 24 +++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index f3d5edda543..c6b981226dd 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.10.0 (in progress) +- [bug] JAVA-2911: Prevent control connection from scheduling too many reconnections - [bug] JAVA-2902: Consider computed values when validating constructors for immutable entities - [new feature] JAVA-2899: Re-introduce cross-DC failover in driver 4 - [new feature] JAVA-2900: Re-introduce consistency downgrading retries diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java b/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java index bcba1e76583..3fcfd120086 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java @@ -425,13 +425,15 @@ private void connect( connect(nodes, errors, onSuccess, onFailure); } else { LOG.debug("[{}] New channel opened {}", logPrefix, channel); - // Make sure previous channel gets closed (it may still be open if - // reconnection was forced) DriverChannel previousChannel = ControlConnection.this.channel; + ControlConnection.this.channel = channel; if (previousChannel != null) { + // We were reconnecting: make sure previous channel gets closed (it may + // still be open if reconnection was forced) + LOG.debug( + "[{}] Forcefully closing previous channel {}", logPrefix, channel); previousChannel.forceClose(); } - ControlConnection.this.channel = channel; context.getEventBus().fire(ChannelEvent.channelOpened(node)); channel .closeFuture() @@ -503,9 +505,21 @@ private void onSuccessfulReconnect() { private void onChannelClosed(DriverChannel channel, Node node) { assert adminExecutor.inEventLoop(); if (!closeWasCalled) { - LOG.debug("[{}] Lost channel {}", logPrefix, channel); context.getEventBus().fire(ChannelEvent.channelClosed(node)); - reconnection.start(); + // If this channel is the current control channel, we must start a + // reconnection attempt to get a new control channel. + if (channel == ControlConnection.this.channel) { + LOG.debug( + "[{}] The current control channel {} was closed, scheduling reconnection", + logPrefix, + channel); + reconnection.start(); + } else { + LOG.trace( + "[{}] A previous control channel {} was closed, reconnection not required", + logPrefix, + channel); + } } } From 11448aa6532791f331f3f46dec03bf3d0870a63e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 14:06:25 +0100 Subject: [PATCH 040/395] JAVA-2904 follow-up: fix Revapi errors caused by the upgrade of Jackson --- core/revapi.json | 410 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) diff --git a/core/revapi.json b/core/revapi.json index 8bf661b8544..592d810e571 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -5030,6 +5030,416 @@ "code": "java.class.nonPublicPartOfAPI", "new": "class com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder.Node", "justification": "Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.annotation.JsonTypeInfo.Id.CUSTOM", + "new": "field com.fasterxml.jackson.annotation.JsonTypeInfo.Id.CUSTOM", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.core.Base64Variant.serialVersionUID", + "new": "field com.fasterxml.jackson.core.Base64Variant.serialVersionUID", + "serialVersionUID": "1", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonFinalClassInheritsFromNewClass", + "old": "class com.fasterxml.jackson.core.JsonGenerationException", + "new": "class com.fasterxml.jackson.core.JsonGenerationException", + "superClass": "com.fasterxml.jackson.core.JacksonException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonFinalClassInheritsFromNewClass", + "old": "class com.fasterxml.jackson.core.JsonParseException", + "new": "class com.fasterxml.jackson.core.JsonParseException", + "superClass": "com.fasterxml.jackson.core.JacksonException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonFinalClassInheritsFromNewClass", + "old": "class com.fasterxml.jackson.core.JsonProcessingException", + "new": "class com.fasterxml.jackson.core.JsonProcessingException", + "superClass": "com.fasterxml.jackson.core.JacksonException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonPublicPartOfAPI", + "old": "class com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer.TableInfo", + "new": "class com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer.TableInfo", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonPublicPartOfAPI", + "old": "class com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer.Bucket", + "new": "class com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer.Bucket", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonPublicPartOfAPI", + "old": "class com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer.TableInfo", + "new": "class com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer.TableInfo", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method java.lang.String[] com.fasterxml.jackson.databind.AnnotationIntrospector::findPropertiesToIgnore(com.fasterxml.jackson.databind.introspect.Annotated)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.defaultSerializationChanged", + "old": "class com.fasterxml.jackson.databind.AnnotationIntrospector", + "new": "class com.fasterxml.jackson.databind.AnnotationIntrospector", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.databind.DeserializationConfig.serialVersionUID", + "new": "field com.fasterxml.jackson.databind.DeserializationConfig.serialVersionUID", + "serialVersionUID": "2", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.returnTypeChanged", + "old": "method void com.fasterxml.jackson.databind.DeserializationConfig::initialize(com.fasterxml.jackson.core.JsonParser)", + "new": "method com.fasterxml.jackson.core.JsonParser com.fasterxml.jackson.databind.DeserializationConfig::initialize(com.fasterxml.jackson.core.JsonParser)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method T com.fasterxml.jackson.databind.DeserializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.DeserializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.generics.formalTypeParameterRemoved", + "old": "method T com.fasterxml.jackson.databind.DeserializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.DeserializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "typeParameter": "T extends com.fasterxml.jackson.databind.BeanDescription", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method T com.fasterxml.jackson.databind.DeserializationConfig::introspectForBuilder(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.DeserializationConfig::introspectForBuilder(com.fasterxml.jackson.databind.JavaType)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.generics.formalTypeParameterRemoved", + "old": "method T com.fasterxml.jackson.databind.DeserializationConfig::introspectForBuilder(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.DeserializationConfig::introspectForBuilder(com.fasterxml.jackson.databind.JavaType)", + "typeParameter": "T extends com.fasterxml.jackson.databind.BeanDescription", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method T com.fasterxml.jackson.databind.DeserializationConfig::introspectForCreation(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.DeserializationConfig::introspectForCreation(com.fasterxml.jackson.databind.JavaType)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.generics.formalTypeParameterRemoved", + "old": "method T com.fasterxml.jackson.databind.DeserializationConfig::introspectForCreation(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.DeserializationConfig::introspectForCreation(com.fasterxml.jackson.databind.JavaType)", + "typeParameter": "T extends com.fasterxml.jackson.databind.BeanDescription", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.databind.DeserializationContext.serialVersionUID", + "new": "field com.fasterxml.jackson.databind.DeserializationContext.serialVersionUID", + "serialVersionUID": "1", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.finalMethodAddedToNonFinalClass", + "new": "method boolean com.fasterxml.jackson.databind.DeserializationContext::isEnabled(com.fasterxml.jackson.core.StreamReadCapability)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.finalMethodAddedToNonFinalClass", + "new": "method boolean com.fasterxml.jackson.databind.JavaType::isRecordType()", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonFinalClassInheritsFromNewClass", + "old": "class com.fasterxml.jackson.databind.JsonMappingException", + "new": "class com.fasterxml.jackson.databind.JsonMappingException", + "superClass": "com.fasterxml.jackson.core.JacksonException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS", + "new": "field com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES", + "new": "field com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES", + "new": "field com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.ALLOW_COERCION_OF_SCALARS", + "new": "field com.fasterxml.jackson.databind.MapperFeature.ALLOW_COERCION_OF_SCALARS", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING", + "new": "field com.fasterxml.jackson.databind.MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES", + "new": "field com.fasterxml.jackson.databind.MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS", + "new": "field com.fasterxml.jackson.databind.MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION", + "new": "field com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS", + "new": "field com.fasterxml.jackson.databind.MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE", + "new": "field com.fasterxml.jackson.databind.MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS", + "new": "field com.fasterxml.jackson.databind.MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY", + "new": "field com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL", + "new": "field com.fasterxml.jackson.databind.MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.USE_STATIC_TYPING", + "new": "field com.fasterxml.jackson.databind.MapperFeature.USE_STATIC_TYPING", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.USE_STD_BEAN_NAMING", + "new": "field com.fasterxml.jackson.databind.MapperFeature.USE_STD_BEAN_NAMING", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.enumConstantOrderChanged", + "old": "field com.fasterxml.jackson.databind.MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME", + "new": "field com.fasterxml.jackson.databind.MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.databind.ObjectMapper.serialVersionUID", + "new": "field com.fasterxml.jackson.databind.ObjectMapper.serialVersionUID", + "serialVersionUID": "2", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method java.lang.Object com.fasterxml.jackson.databind.ObjectMapper::_unwrapAndDeserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext, com.fasterxml.jackson.databind.DeserializationConfig, com.fasterxml.jackson.databind.JavaType, com.fasterxml.jackson.databind.JsonDeserializer) throws java.io.IOException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.finalMethodAddedToNonFinalClass", + "new": "method void com.fasterxml.jackson.databind.ObjectMapper::_writeValueAndClose(com.fasterxml.jackson.core.JsonGenerator, java.lang.Object) throws java.io.IOException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.exception.runtimeAdded", + "old": "method T com.fasterxml.jackson.databind.ObjectMapper::treeToValue(com.fasterxml.jackson.core.TreeNode, java.lang.Class) throws com.fasterxml.jackson.core.JsonProcessingException", + "new": "method T com.fasterxml.jackson.databind.ObjectMapper::treeToValue(com.fasterxml.jackson.core.TreeNode, java.lang.Class) throws java.lang.IllegalArgumentException, com.fasterxml.jackson.core.JsonProcessingException", + "exception": "java.lang.IllegalArgumentException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method java.lang.Object com.fasterxml.jackson.databind.ObjectReader::_unwrapAndDeserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext, com.fasterxml.jackson.databind.JavaType, com.fasterxml.jackson.databind.JsonDeserializer) throws java.io.IOException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method void com.fasterxml.jackson.databind.ObjectWriter::_configAndWriteValue(com.fasterxml.jackson.core.JsonGenerator, java.lang.Object) throws java.io.IOException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.returnTypeChanged", + "old": "method void com.fasterxml.jackson.databind.ObjectWriter::_configureGenerator(com.fasterxml.jackson.core.JsonGenerator)", + "new": "method com.fasterxml.jackson.core.JsonGenerator com.fasterxml.jackson.databind.ObjectWriter::_configureGenerator(com.fasterxml.jackson.core.JsonGenerator)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.finalMethodAddedToNonFinalClass", + "new": "method void com.fasterxml.jackson.databind.ObjectWriter::_writeValueAndClose(com.fasterxml.jackson.core.JsonGenerator, java.lang.Object) throws java.io.IOException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDChanged", + "new": "field com.fasterxml.jackson.databind.PropertyNamingStrategy.serialVersionUID", + "oldSerialVersionUID": "-5237220944964015475", + "newSerialVersionUID": "2", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method T com.fasterxml.jackson.databind.SerializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.SerializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.generics.formalTypeParameterRemoved", + "old": "method T com.fasterxml.jackson.databind.SerializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.SerializationConfig::introspect(com.fasterxml.jackson.databind.JavaType)", + "typeParameter": "T extends com.fasterxml.jackson.databind.BeanDescription", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.databind.cfg.BaseSettings.serialVersionUID", + "new": "field com.fasterxml.jackson.databind.cfg.BaseSettings.serialVersionUID", + "serialVersionUID": "1", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.numberOfParametersChanged", + "old": "method void com.fasterxml.jackson.databind.cfg.BaseSettings::(com.fasterxml.jackson.databind.introspect.ClassIntrospector, com.fasterxml.jackson.databind.AnnotationIntrospector, com.fasterxml.jackson.databind.PropertyNamingStrategy, com.fasterxml.jackson.databind.type.TypeFactory, com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder, java.text.DateFormat, com.fasterxml.jackson.databind.cfg.HandlerInstantiator, java.util.Locale, java.util.TimeZone, com.fasterxml.jackson.core.Base64Variant)", + "new": "method void com.fasterxml.jackson.databind.cfg.BaseSettings::(com.fasterxml.jackson.databind.introspect.ClassIntrospector, com.fasterxml.jackson.databind.AnnotationIntrospector, com.fasterxml.jackson.databind.PropertyNamingStrategy, com.fasterxml.jackson.databind.type.TypeFactory, com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder, java.text.DateFormat, com.fasterxml.jackson.databind.cfg.HandlerInstantiator, java.util.Locale, java.util.TimeZone, com.fasterxml.jackson.core.Base64Variant, com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator, com.fasterxml.jackson.databind.introspect.AccessorNamingStrategy.Provider)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.finalMethodAddedToNonFinalClass", + "new": "method com.fasterxml.jackson.databind.introspect.AccessorNamingStrategy.Provider com.fasterxml.jackson.databind.cfg.MapperConfig>::getAccessorNaming()", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.abstractMethodAdded", + "new": "method com.fasterxml.jackson.annotation.JsonIncludeProperties.Value com.fasterxml.jackson.databind.cfg.MapperConfig>::getDefaultPropertyInclusions(java.lang.Class, com.fasterxml.jackson.databind.introspect.AnnotatedClass)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.serialVersionUID", + "new": "field com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.serialVersionUID", + "serialVersionUID": "1", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.abstractMethodAdded", + "new": "method com.fasterxml.jackson.databind.deser.DefaultDeserializationContext com.fasterxml.jackson.databind.deser.DefaultDeserializationContext::createDummyInstance(com.fasterxml.jackson.databind.DeserializationConfig)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.class.nonFinalClassInheritsFromNewClass", + "old": "class com.fasterxml.jackson.databind.deser.UnresolvedForwardReference", + "new": "class com.fasterxml.jackson.databind.deser.UnresolvedForwardReference", + "superClass": "com.fasterxml.jackson.core.JacksonException", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method com.fasterxml.jackson.databind.introspect.AnnotatedParameter com.fasterxml.jackson.databind.deser.ValueInstantiator::getIncompleteParameter()", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method void com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap::(boolean, java.util.Collection)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.numberOfParametersChanged", + "old": "method com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap::construct(java.util.Collection, boolean)", + "new": "method com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap::construct(com.fasterxml.jackson.databind.cfg.MapperConfig, java.util.Collection, java.util.Map>, boolean)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method void com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap::replace(com.fasterxml.jackson.databind.deser.SettableBeanProperty)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.abstractMethodAdded", + "new": "method com.fasterxml.jackson.databind.BeanDescription com.fasterxml.jackson.databind.introspect.ClassIntrospector::forDeserializationWithBuilder(com.fasterxml.jackson.databind.DeserializationConfig, com.fasterxml.jackson.databind.JavaType, com.fasterxml.jackson.databind.introspect.ClassIntrospector.MixInResolver, com.fasterxml.jackson.databind.BeanDescription)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.numberOfParametersChanged", + "old": "method void com.fasterxml.jackson.databind.ser.BeanSerializer::(com.fasterxml.jackson.databind.ser.std.BeanSerializerBase, java.util.Set)", + "new": "method void com.fasterxml.jackson.databind.ser.BeanSerializer::(com.fasterxml.jackson.databind.ser.std.BeanSerializerBase, java.util.Set, java.util.Set)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.removed", + "old": "method com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap::emptyMap()", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.visibilityReduced", + "old": "method void com.fasterxml.jackson.databind.ser.std.BeanSerializerBase::(com.fasterxml.jackson.databind.ser.std.BeanSerializerBase, com.fasterxml.jackson.databind.ser.BeanPropertyWriter[], com.fasterxml.jackson.databind.ser.BeanPropertyWriter[])", + "new": "method void com.fasterxml.jackson.databind.ser.std.BeanSerializerBase::(com.fasterxml.jackson.databind.ser.std.BeanSerializerBase, com.fasterxml.jackson.databind.ser.BeanPropertyWriter[], com.fasterxml.jackson.databind.ser.BeanPropertyWriter[])", + "oldVisibility": "public", + "newVisibility": "protected", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.abstractMethodAdded", + "new": "method com.fasterxml.jackson.databind.ser.std.BeanSerializerBase com.fasterxml.jackson.databind.ser.std.BeanSerializerBase::withByNameInclusion(java.util.Set, java.util.Set)", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.method.abstractMethodAdded", + "new": "method com.fasterxml.jackson.databind.ser.std.BeanSerializerBase com.fasterxml.jackson.databind.ser.std.BeanSerializerBase::withProperties(com.fasterxml.jackson.databind.ser.BeanPropertyWriter[], com.fasterxml.jackson.databind.ser.BeanPropertyWriter[])", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.typeChanged", + "old": "field com.fasterxml.jackson.databind.type.TypeFactory._typeCache", + "new": "field com.fasterxml.jackson.databind.type.TypeFactory._typeCache", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.field.serialVersionUIDUnchanged", + "old": "field com.fasterxml.jackson.databind.type.TypeFactory.serialVersionUID", + "new": "field com.fasterxml.jackson.databind.type.TypeFactory.serialVersionUID", + "serialVersionUID": "1", + "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" } ] } From d765a6a59162ee596418001ec56b9360679d8d6b Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 16:06:49 +0100 Subject: [PATCH 041/395] Remove redundant call to Collections.unmodifiableList in GraalGetpid --- .../com/datastax/oss/driver/internal/core/os/GraalGetpid.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/os/GraalGetpid.java b/core/src/main/java/com/datastax/oss/driver/internal/core/os/GraalGetpid.java index e910f3ce80a..913f13557da 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/os/GraalGetpid.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/os/GraalGetpid.java @@ -28,7 +28,7 @@ static class Directives implements CContext.Directives { @Override public List getHeaderFiles() { - return Collections.unmodifiableList(Collections.singletonList("")); + return Collections.singletonList(""); } } From 84c6dfe920b6aa8a8af299f35f5e042803323a51 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 16:08:10 +0100 Subject: [PATCH 042/395] Fix various compiler warnings --- ...tinuousCqlRequestHandlerReprepareTest.java | 14 +++--- .../CompositeDriverConfigReloadTest.java | 7 +-- .../LoadBalancingPolicyWrapperTest.java | 48 ++++++++----------- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerReprepareTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerReprepareTest.java index 634c6eda5d2..2d287210c2a 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerReprepareTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerReprepareTest.java @@ -18,6 +18,7 @@ import static com.datastax.oss.driver.Assertions.assertThat; import static com.datastax.oss.driver.Assertions.assertThatStage; import static com.datastax.oss.protocol.internal.Frame.NO_PAYLOAD; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyMap; @@ -91,7 +92,7 @@ public void should_prepare_and_retry_on_same_node(DseProtocolVersion version) { when(harness.getChannel(node1).write(any(Prepare.class), anyBoolean(), anyMap(), any())) .then( invocation -> { - AdminRequestHandler admin = invocation.getArgument(3); + AdminRequestHandler admin = invocation.getArgument(3); admin.onResponse(defaultFrameOf(prepared)); return future; }); @@ -121,7 +122,7 @@ public void should_abort_when_prepare_fails_with_unrecoverable_error(DseProtocol when(harness.getChannel(node1).write(any(Prepare.class), anyBoolean(), anyMap(), any())) .then( invocation -> { - AdminRequestHandler admin = invocation.getArgument(3); + AdminRequestHandler admin = invocation.getArgument(3); admin.onResponse(defaultFrameOf(unrecoverable)); return future; }); @@ -135,10 +136,9 @@ public void should_abort_when_prepare_fails_with_unrecoverable_error(DseProtocol verify(harness.getChannel(node1)).write(any(Prepare.class), anyBoolean(), anyMap(), any()); assertThat(handler.getState()).isEqualTo(-2); - assertThat(page1Future) - .hasFailedWithThrowableThat() - .isInstanceOf(SyntaxError.class) - .hasMessageContaining("bad query"); + assertThat(page1Future).isCompletedExceptionally(); + Throwable t = catchThrowable(() -> page1Future.toCompletableFuture().get()); + assertThat(t).hasRootCauseInstanceOf(SyntaxError.class).hasMessageContaining("bad query"); } } @@ -158,7 +158,7 @@ public void should_try_next_node_when_prepare_fails_with_recoverable_error( when(harness.getChannel(node1).write(any(Prepare.class), anyBoolean(), anyMap(), any())) .then( invocation -> { - AdminRequestHandler admin = invocation.getArgument(3); + AdminRequestHandler admin = invocation.getArgument(3); admin.onResponse(defaultFrameOf(recoverable)); return future; }); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigReloadTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigReloadTest.java index 761ecf9cc60..b97ae4f5b45 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigReloadTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/composite/CompositeDriverConfigReloadTest.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.config.composite; import static com.datastax.oss.driver.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -83,9 +84,9 @@ public void should_delegate_reloading_to_reloadable_children( if (compositeShouldBeReloadable) { assertThat(reloadFuture).isCompletedWithValue(true); } else { - assertThat(reloadFuture) - .hasFailedWithThrowableThat() - .isInstanceOf(UnsupportedOperationException.class); + assertThat(reloadFuture).isCompletedExceptionally(); + Throwable t = catchThrowable(() -> reloadFuture.toCompletableFuture().get()); + assertThat(t).hasRootCauseInstanceOf(UnsupportedOperationException.class); } verify(primaryLoader, primaryIsReloadable ? times(1) : never()).reload(); verify(fallbackLoader, fallbackIsReloadable ? times(1) : never()).reload(); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapperTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapperTest.java index d7be8e96b0b..a9bd9951b9d 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapperTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapperTest.java @@ -18,7 +18,6 @@ import static com.datastax.oss.driver.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -41,6 +40,7 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; import java.util.Map; +import java.util.Objects; import java.util.Queue; import java.util.Set; import java.util.UUID; @@ -54,7 +54,6 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; @RunWith(MockitoJUnitRunner.class) public class LoadBalancingPolicyWrapperTest { @@ -63,9 +62,8 @@ public class LoadBalancingPolicyWrapperTest { private DefaultNode node2; private DefaultNode node3; - private Map allNodes; private Set contactPoints; - private Queue defaultPolicysQueryPlan; + private Queue defaultPolicyQueryPlan; @Mock private InternalDriverContext context; @Mock private LoadBalancingPolicy policy1; @@ -88,16 +86,18 @@ public void setup() { node3 = TestNodeFactory.newNode(3, context); contactPoints = ImmutableSet.of(node1, node2); - allNodes = + Map allNodes = ImmutableMap.of( - node1.getHostId(), node1, node2.getHostId(), node2, node3.getHostId(), node3); + Objects.requireNonNull(node1.getHostId()), node1, + Objects.requireNonNull(node2.getHostId()), node2, + Objects.requireNonNull(node3.getHostId()), node3); when(metadataManager.getMetadata()).thenReturn(metadata); when(metadata.getNodes()).thenReturn(allNodes); when(metadataManager.getContactPoints()).thenReturn(contactPoints); when(context.getMetadataManager()).thenReturn(metadataManager); - defaultPolicysQueryPlan = Lists.newLinkedList(ImmutableList.of(node3, node2, node1)); - when(policy1.newQueryPlan(null, null)).thenReturn(defaultPolicysQueryPlan); + defaultPolicyQueryPlan = Lists.newLinkedList(ImmutableList.of(node3, node2, node1)); + when(policy1.newQueryPlan(null, null)).thenReturn(defaultPolicyQueryPlan); eventBus = spy(new EventBus("test")); when(context.getEventBus()).thenReturn(eventBus); @@ -125,7 +125,7 @@ public void should_build_query_plan_from_contact_points_before_init() { for (LoadBalancingPolicy policy : ImmutableList.of(policy1, policy2, policy3)) { verify(policy, never()).newQueryPlan(null, null); } - assertThat(queryPlan).containsOnlyElementsOf(contactPoints); + assertThat(queryPlan).hasSameElementsAs(contactPoints); } @Test @@ -142,7 +142,7 @@ public void should_fetch_query_plan_from_policy_after_init() { // Then // no-arg newQueryPlan() uses the default profile verify(policy1).newQueryPlan(null, null); - assertThat(queryPlan).isEqualTo(defaultPolicysQueryPlan); + assertThat(queryPlan).isEqualTo(defaultPolicyQueryPlan); } @Test @@ -236,25 +236,16 @@ public void should_propagate_node_states_to_policies_after_init() { @Test public void should_accumulate_events_during_init_and_replay() throws InterruptedException { // Given - // Hack to obtain concurrency: the main thread blocks in init, while another thread fires an - // event on the bus - CountDownLatch eventLatch = new CountDownLatch(3); + // Hack to obtain concurrency: the main thread releases another thread and blocks; then the + // other thread fires an event on the bus and unblocks the main thread. + CountDownLatch eventLatch = new CountDownLatch(1); CountDownLatch initLatch = new CountDownLatch(1); - Answer mockInit = - i -> { - eventLatch.countDown(); - initLatch.await(500, TimeUnit.MILLISECONDS); - return null; - }; - for (LoadBalancingPolicy policy : ImmutableList.of(policy1, policy2, policy3)) { - doAnswer(mockInit).when(policy).init(anyMap(), any(DistanceReporter.class)); - } // When Runnable runnable = () -> { try { - eventLatch.await(500, TimeUnit.MILLISECONDS); + eventLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } @@ -266,15 +257,14 @@ public void should_accumulate_events_during_init_and_replay() throws Interrupted wrapper.init(); // Then - // wait for init launch to signal that runnable is complete. - initLatch.await(500, TimeUnit.MILLISECONDS); + // unblock the thread that will fire the event, and waits until it finishes + eventLatch.countDown(); + boolean ok = initLatch.await(500, TimeUnit.MILLISECONDS); + assertThat(ok).isTrue(); for (LoadBalancingPolicy policy : ImmutableList.of(policy1, policy2, policy3)) { verify(policy).onDown(node1); } - if (thread.isAlive()) { - // thread still completing - sleep to allow thread to complete. - Thread.sleep(500); - } + thread.join(500); assertThat(thread.isAlive()).isFalse(); } } From 97c665730bdfcb4657985cab64935274d0f750ee Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 16:09:00 +0100 Subject: [PATCH 043/395] JAVA-2871 follow-up: Fix failing tests due to wrong keyspace exclusions --- .../oss/driver/core/metadata/SchemaIT.java | 158 ++++++++++-------- 1 file changed, 90 insertions(+), 68 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index aa5a862cb42..dc915e25c77 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -38,8 +38,10 @@ import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.protocol.internal.util.Bytes; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; import org.junit.AssumptionViolatedException; import org.junit.Rule; @@ -51,11 +53,12 @@ @Category(ParallelizableTests.class) public class SchemaIT { - private static final Version DSE_MIN_VIRTUAL_TABLES = Version.parse("6.7.0"); + private static final Version DSE_MIN_VIRTUAL_TABLES = + Objects.requireNonNull(Version.parse("6.7.0")); - private CcmRule ccmRule = CcmRule.getInstance(); + private final CcmRule ccmRule = CcmRule.getInstance(); - private SessionRule sessionRule = SessionRule.builder(ccmRule).build(); + private final SessionRule sessionRule = SessionRule.builder(ccmRule).build(); @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); @@ -187,59 +190,69 @@ public void should_refresh_schema_manually() { public void should_get_virtual_metadata() { skipIfDse60(); - Metadata md = sessionRule.session().getMetadata(); - KeyspaceMetadata kmd = md.getKeyspace("system_views").get(); - - // Keyspace name should be set, marked as virtual, and have at least sstable_tasks table. - // All other values should be defaulted since they are not defined in the virtual schema tables. - assertThat(kmd.getTables().size()).isGreaterThanOrEqualTo(1); - assertThat(kmd.isVirtual()).isTrue(); - assertThat(kmd.isDurableWrites()).isFalse(); - assertThat(kmd.getName().asCql(true)).isEqualTo("system_views"); - - // Virtual tables lack User Types, Functions, Views and Aggregates - assertThat(kmd.getUserDefinedTypes().size()).isEqualTo(0); - assertThat(kmd.getFunctions().size()).isEqualTo(0); - assertThat(kmd.getViews().size()).isEqualTo(0); - assertThat(kmd.getAggregates().size()).isEqualTo(0); - - assertThat(kmd.describe(true)) - .isEqualTo( - "/* VIRTUAL KEYSPACE system_views WITH replication = { 'class' : 'null' } " - + "AND durable_writes = false; */"); - // Table name should be set, marked as virtual, and it should have columns set. - // indexes, views, clustering column, clustering order and id are not defined in the virtual - // schema tables. - TableMetadata tm = kmd.getTable("sstable_tasks").get(); - assertThat(tm).isNotNull(); - assertThat(tm.getName().toString()).isEqualTo("sstable_tasks"); - assertThat(tm.isVirtual()).isTrue(); - assertThat(tm.getColumns().size()).isEqualTo(7); - assertThat(tm.getIndexes().size()).isEqualTo(0); - assertThat(tm.getPartitionKey().size()).isEqualTo(1); - assertThat(tm.getPartitionKey().get(0).getName().toString()).isEqualTo("keyspace_name"); - assertThat(tm.getClusteringColumns().size()).isEqualTo(2); - assertThat(tm.getId().isPresent()).isFalse(); - assertThat(tm.getOptions().size()).isEqualTo(0); - assertThat(tm.getKeyspace()).isEqualTo(kmd.getName()); - assertThat(tm.describe(true)) - .isEqualTo( - "/* VIRTUAL TABLE system_views.sstable_tasks (\n" - + " keyspace_name text,\n" - + " table_name text,\n" - + " task_id uuid,\n" - + " kind text,\n" - + " progress bigint,\n" - + " total bigint,\n" - + " unit text,\n" - + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" - + "); */"); - // ColumnMetadata is as expected - ColumnMetadata cm = tm.getColumn("progress").get(); - assertThat(cm).isNotNull(); - assertThat(cm.getParent()).isEqualTo(tm.getName()); - assertThat(cm.getType()).isEqualTo(DataTypes.BIGINT); - assertThat(cm.getName().toString()).isEqualTo("progress"); + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withStringList( + DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, + Collections.singletonList("system_views")) + .build(); + try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { + + Metadata md = session.getMetadata(); + KeyspaceMetadata kmd = md.getKeyspace("system_views").get(); + + // Keyspace name should be set, marked as virtual, and have at least sstable_tasks table. + // All other values should be defaulted since they are not defined in the virtual schema + // tables. + assertThat(kmd.getTables().size()).isGreaterThanOrEqualTo(1); + assertThat(kmd.isVirtual()).isTrue(); + assertThat(kmd.isDurableWrites()).isFalse(); + assertThat(kmd.getName().asCql(true)).isEqualTo("system_views"); + + // Virtual tables lack User Types, Functions, Views and Aggregates + assertThat(kmd.getUserDefinedTypes().size()).isEqualTo(0); + assertThat(kmd.getFunctions().size()).isEqualTo(0); + assertThat(kmd.getViews().size()).isEqualTo(0); + assertThat(kmd.getAggregates().size()).isEqualTo(0); + + assertThat(kmd.describe(true)) + .isEqualTo( + "/* VIRTUAL KEYSPACE system_views WITH replication = { 'class' : 'null' } " + + "AND durable_writes = false; */"); + // Table name should be set, marked as virtual, and it should have columns set. + // indexes, views, clustering column, clustering order and id are not defined in the virtual + // schema tables. + TableMetadata tm = kmd.getTable("sstable_tasks").get(); + assertThat(tm).isNotNull(); + assertThat(tm.getName().toString()).isEqualTo("sstable_tasks"); + assertThat(tm.isVirtual()).isTrue(); + assertThat(tm.getColumns().size()).isEqualTo(7); + assertThat(tm.getIndexes().size()).isEqualTo(0); + assertThat(tm.getPartitionKey().size()).isEqualTo(1); + assertThat(tm.getPartitionKey().get(0).getName().toString()).isEqualTo("keyspace_name"); + assertThat(tm.getClusteringColumns().size()).isEqualTo(2); + assertThat(tm.getId().isPresent()).isFalse(); + assertThat(tm.getOptions().size()).isEqualTo(0); + assertThat(tm.getKeyspace()).isEqualTo(kmd.getName()); + assertThat(tm.describe(true)) + .isEqualTo( + "/* VIRTUAL TABLE system_views.sstable_tasks (\n" + + " keyspace_name text,\n" + + " table_name text,\n" + + " task_id uuid,\n" + + " kind text,\n" + + " progress bigint,\n" + + " total bigint,\n" + + " unit text,\n" + + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" + + "); */"); + // ColumnMetadata is as expected + ColumnMetadata cm = tm.getColumn("progress").get(); + assertThat(cm).isNotNull(); + assertThat(cm.getParent()).isEqualTo(tm.getName()); + assertThat(cm.getType()).isEqualTo(DataTypes.BIGINT); + assertThat(cm.getName().toString()).isEqualTo("progress"); + } } @CassandraRequirement(min = "4.0", description = "virtual tables introduced in 4.0") @@ -247,18 +260,27 @@ public void should_get_virtual_metadata() { public void should_exclude_virtual_keyspaces_from_token_map() { skipIfDse60(); - Metadata metadata = sessionRule.session().getMetadata(); - Map keyspaces = metadata.getKeyspaces(); - assertThat(keyspaces) - .containsKey(CqlIdentifier.fromCql("system_views")) - .containsKey(CqlIdentifier.fromCql("system_virtual_schema")); - - TokenMap tokenMap = metadata.getTokenMap().orElseThrow(AssertionError::new); - ByteBuffer partitionKey = Bytes.fromHexString("0x00"); // value does not matter - assertThat(tokenMap.getReplicas("system_views", partitionKey)).isEmpty(); - assertThat(tokenMap.getReplicas("system_virtual_schema", partitionKey)).isEmpty(); - // Check that a non-virtual keyspace is present - assertThat(tokenMap.getReplicas(sessionRule.keyspace(), partitionKey)).isNotEmpty(); + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withStringList( + DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, + Arrays.asList( + "system_views", "system_virtual_schema", sessionRule.keyspace().asInternal())) + .build(); + try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { + Metadata metadata = session.getMetadata(); + Map keyspaces = metadata.getKeyspaces(); + assertThat(keyspaces) + .containsKey(CqlIdentifier.fromCql("system_views")) + .containsKey(CqlIdentifier.fromCql("system_virtual_schema")); + + TokenMap tokenMap = metadata.getTokenMap().orElseThrow(AssertionError::new); + ByteBuffer partitionKey = Bytes.fromHexString("0x00"); // value does not matter + assertThat(tokenMap.getReplicas("system_views", partitionKey)).isEmpty(); + assertThat(tokenMap.getReplicas("system_virtual_schema", partitionKey)).isEmpty(); + // Check that a non-virtual keyspace is present + assertThat(tokenMap.getReplicas(sessionRule.keyspace(), partitionKey)).isNotEmpty(); + } } private void skipIfDse60() { From 915fbea5e2ce889caacb475bcb95a363cf4b720b Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 16:15:18 +0100 Subject: [PATCH 044/395] Fix various compiler warnings in integration tests --- .../graph/ClassicGraphDataTypeITBase.java | 38 +++++++++-------- .../core/graph/CoreGraphDataTypeITBase.java | 41 +++++++++++++------ .../TableGraphMetadataCaseSensitiveIT.java | 2 +- .../metadata/schema/TableGraphMetadataIT.java | 2 +- 4 files changed, 50 insertions(+), 33 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphDataTypeITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphDataTypeITBase.java index 4f30a51fec8..7251a88fe4f 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphDataTypeITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphDataTypeITBase.java @@ -35,6 +35,7 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; @@ -46,11 +47,12 @@ @RunWith(DataProviderRunner.class) public abstract class ClassicGraphDataTypeITBase { - private static final boolean IS_DSE50 = CcmBridge.VERSION.compareTo(Version.parse("5.1")) < 0; + private static final boolean IS_DSE50 = + CcmBridge.VERSION.compareTo(Objects.requireNonNull(Version.parse("5.1"))) < 0; private static final Set TYPES_REQUIRING_DSE51 = ImmutableSet.of("Date()", "Time()", "Point()", "Linestring()", "Polygon()"); - private static AtomicInteger schemaCounter = new AtomicInteger(); + private static final AtomicInteger SCHEMA_COUNTER = new AtomicInteger(); @DataProvider public static Object[][] typeSamples() { @@ -97,29 +99,29 @@ public static Object[][] typeSamples() { {"Decimal()", new BigDecimal("8675309.9998")}, {"Varint()", new BigInteger("8675309")}, // Geospatial types - {"Point().withBounds(-2, -2, 2, 2)", Point.fromCoordinates((double) 0, (double) 1)}, - {"Point().withBounds(-40, -40, 40, 40)", Point.fromCoordinates((double) -5, (double) 20)}, + {"Point().withBounds(-2, -2, 2, 2)", Point.fromCoordinates(0, 1)}, + {"Point().withBounds(-40, -40, 40, 40)", Point.fromCoordinates(-5, 20)}, { "Linestring().withGeoBounds()", LineString.fromPoints( - Point.fromCoordinates((double) 30, (double) 10), - Point.fromCoordinates((double) 10, (double) 30), - Point.fromCoordinates((double) 40, (double) 40)) + Point.fromCoordinates(30, 10), + Point.fromCoordinates(10, 30), + Point.fromCoordinates(40, 40)) }, { "Polygon().withGeoBounds()", Polygon.builder() .addRing( - Point.fromCoordinates((double) 35, (double) 10), - Point.fromCoordinates((double) 45, (double) 45), - Point.fromCoordinates((double) 15, (double) 40), - Point.fromCoordinates((double) 10, (double) 20), - Point.fromCoordinates((double) 35, (double) 10)) + Point.fromCoordinates(35, 10), + Point.fromCoordinates(45, 45), + Point.fromCoordinates(15, 40), + Point.fromCoordinates(10, 20), + Point.fromCoordinates(35, 10)) .addRing( - Point.fromCoordinates((double) 20, (double) 30), - Point.fromCoordinates((double) 35, (double) 35), - Point.fromCoordinates((double) 30, (double) 20), - Point.fromCoordinates((double) 20, (double) 30)) + Point.fromCoordinates(20, 30), + Point.fromCoordinates(35, 35), + Point.fromCoordinates(30, 20), + Point.fromCoordinates(20, 30)) .build() } }; @@ -133,11 +135,11 @@ public void should_create_and_retrieve_vertex_property_with_correct_type( throw new AssumptionViolatedException(type + " not supported in DSE " + CcmBridge.VERSION); } - int id = schemaCounter.getAndIncrement(); + int id = SCHEMA_COUNTER.getAndIncrement(); String vertexLabel = "vertex" + id; String propertyName = "prop" + id; - GraphStatement addVertexLabelAndProperty = + GraphStatement addVertexLabelAndProperty = ScriptGraphStatement.builder( "schema.propertyKey(property)." + type diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java index ef9568ce80f..333110096a7 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java @@ -15,7 +15,11 @@ */ package com.datastax.dse.driver.api.core.graph; -import static com.datastax.oss.driver.api.core.type.DataTypes.*; +import static com.datastax.oss.driver.api.core.type.DataTypes.BIGINT; +import static com.datastax.oss.driver.api.core.type.DataTypes.INT; +import static com.datastax.oss.driver.api.core.type.DataTypes.TEXT; +import static com.datastax.oss.driver.api.core.type.DataTypes.listOf; +import static com.datastax.oss.driver.api.core.type.DataTypes.tupleOf; import static org.assertj.core.api.Assertions.assertThat; import com.datastax.dse.driver.api.core.data.geometry.LineString; @@ -97,9 +101,8 @@ public void should_create_and_retrieve_correct_data_with_types() { session .getMetadata() .getKeyspace(graphName()) - .get() - .getUserDefinedType("udt_graphbinary") - .get() + .flatMap(keyspace -> keyspace.getUserDefinedType("udt_graphbinary")) + .orElseThrow(IllegalStateException::new) .newValue( "some text", tupleOf(INT, TEXT).newValue(5, "Bar"), "some missing text")) .put( @@ -107,9 +110,10 @@ public void should_create_and_retrieve_correct_data_with_types() { session .getMetadata() .getKeyspace(graphName()) - .get() - .getUserDefinedType("udt_graphbinarygeo") - .get() + .flatMap( + keyspaceMetadata -> + keyspaceMetadata.getUserDefinedType("udt_graphbinarygeo")) + .orElseThrow(IllegalStateException::new) .newValue( Point.fromCoordinates(3.3, 4.4), LineString.fromPoints( @@ -148,8 +152,7 @@ public void should_insert_and_retrieve_nested_UDTS_and_tuples() { CqlSession session = session(); // use CQL to create type for now because DSP-17567 is not in yet, so this is more stable - session.execute( - String.format("CREATE TYPE %s.udt1(" + "a int" + ", b text" + ")", graphName())); + session.execute(String.format("CREATE TYPE %s.udt1(a int, b text)", graphName())); session.execute( String.format( @@ -175,11 +178,19 @@ public void should_insert_and_retrieve_nested_UDTS_and_tuples() { graphName())); UserDefinedType udt1 = - session.getMetadata().getKeyspace(graphName()).get().getUserDefinedType("udt1").get(); + session + .getMetadata() + .getKeyspace(graphName()) + .flatMap(keyspace -> keyspace.getUserDefinedType("udt1")) + .orElseThrow(IllegalStateException::new); UdtValue udtValue1 = udt1.newValue(1, "2"); UserDefinedType udt2 = - session.getMetadata().getKeyspace(graphName()).get().getUserDefinedType("udt2").get(); + session + .getMetadata() + .getKeyspace(graphName()) + .flatMap(keyspace -> keyspace.getUserDefinedType("udt2")) + .orElseThrow(IllegalStateException::new); TupleType secondNested = tupleOf(BIGINT, listOf(BIGINT)); TupleType firstNested = tupleOf(TEXT, secondNested); UdtValue udtValue2 = @@ -191,7 +202,11 @@ public void should_insert_and_retrieve_nested_UDTS_and_tuples() { firstNested.newValue("6", secondNested.newValue(7L, ImmutableList.of(8L)))); UserDefinedType udt3 = - session.getMetadata().getKeyspace(graphName()).get().getUserDefinedType("udt3").get(); + session + .getMetadata() + .getKeyspace(graphName()) + .flatMap(keyspace -> keyspace.getUserDefinedType("udt3")) + .orElseThrow(IllegalStateException::new); UdtValue udtValue3 = udt3.newValue( ImmutableList.of(1), @@ -225,7 +240,7 @@ private void runTest(Map properties, String vertexLabel, int ver properties.forEach((k, v) -> assertThat(results.get(formatPropertyName(k))).isEqualTo(v)); } - private static GraphStatement createVertexLabelStatement( + private static GraphStatement createVertexLabelStatement( Map properties, String vertexLabel) { StringBuilder ddl = new StringBuilder("schema.vertexLabel(vertexLabel).ifNotExists().partitionBy('id', Int)"); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java index 420d231c554..77bfeb13896 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java @@ -35,7 +35,7 @@ /** * A regression test for a specific case of schema parsing for graphs built from tables containing - * case-sensitive column names in it's tables. See JAVA-2492 for more information. + * case-sensitive column names in its tables. See JAVA-2492 for more information. */ @Category(ParallelizableTests.class) @DseRequirement(min = "6.8") diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java index f9516fa22a3..933951dd7f8 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java @@ -48,7 +48,7 @@ public class TableGraphMetadataIT { public static void createTables() { CqlSession session = SESSION_RULE.session(); - session.execute("CREATE TABLE person (name text PRIMARY KEY) " + "WITH VERTEX LABEL"); + session.execute("CREATE TABLE person (name text PRIMARY KEY) WITH VERTEX LABEL"); session.execute( "CREATE TABLE software (company text, name text, version int, " + "PRIMARY KEY ((company, name), version)) " From 6dcd345cdf0e4a61cbd9dc771abdd6611e9a58b9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 5 Jan 2021 18:50:34 +0100 Subject: [PATCH 045/395] Improve error messages when assertions fail in TokenITBase --- .../oss/driver/core/metadata/TokenITBase.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java index 08ac446b22f..4ebe1bc4e7b 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java @@ -250,17 +250,27 @@ private void checkRanges(Session session, CqlIdentifier keyspace, int replicatio Set hostRanges = tokenMap.getTokenRanges(keyspace, node); // Special case: When using vnodes the tokens are not evenly assigned to each replica. if (!useVnodes) { - assertThat(hostRanges).hasSize(replicationFactor * tokensPerNode); + assertThat(hostRanges) + .as( + "Node %s: expected %d ranges, got %d", + node, replicationFactor * tokensPerNode, hostRanges.size()) + .hasSize(replicationFactor * tokensPerNode); } allRangesWithDuplicates.addAll(hostRanges); } // Special case check for vnodes to ensure that total number of replicated ranges is correct. - assertThat(allRangesWithDuplicates).hasSize(3 * tokensPerNode * replicationFactor); + assertThat(allRangesWithDuplicates) + .as( + "Expected %d total replicated ranges with duplicates, got %d", + 3 * replicationFactor * tokensPerNode, allRangesWithDuplicates.size()) + .hasSize(3 * replicationFactor * tokensPerNode); // Once we ignore duplicates, the number of ranges should match the number of nodes. Set allRanges = new TreeSet<>(allRangesWithDuplicates); - assertThat(allRanges).hasSize(3 * tokensPerNode); + assertThat(allRanges) + .as("Expected %d total replicated ranges, got %d", 3 * tokensPerNode, allRanges.size()) + .hasSize(3 * tokensPerNode); // And the ranges should cover the whole ring and no ranges intersect. checkRanges(allRanges); @@ -269,7 +279,7 @@ private void checkRanges(Session session, CqlIdentifier keyspace, int replicatio // Ensures that no ranges intersect and that they cover the entire ring. private void checkRanges(Collection ranges) { // Ensure no ranges intersect. - TokenRange[] rangesArray = ranges.toArray(new TokenRange[ranges.size()]); + TokenRange[] rangesArray = ranges.toArray(new TokenRange[0]); for (int i = 0; i < rangesArray.length; i++) { TokenRange rangeI = rangesArray[i]; for (int j = i + 1; j < rangesArray.length; j++) { From 22065cab793ed2d91577749f032e401e8be02cab Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 11 Jan 2021 15:22:37 +0100 Subject: [PATCH 046/395] Remove unnecessary `@VisibleForTesting` annotation --- .../internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java | 3 +-- .../internal/core/loadbalancing/nodeset/MultiDcNodeSet.java | 3 +-- .../internal/core/loadbalancing/nodeset/SingleDcNodeSet.java | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java index d9cf67fb7c0..7d947805d81 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/DcAgnosticNodeSet.java @@ -16,7 +16,6 @@ package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Collections; @@ -27,7 +26,7 @@ @ThreadSafe public class DcAgnosticNodeSet implements NodeSet { - @VisibleForTesting final Set nodes = new CopyOnWriteArraySet<>(); + private final Set nodes = new CopyOnWriteArraySet<>(); @Override public boolean add(@NonNull Node node) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java index 5c3d425ba69..741c8e9d3d7 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/MultiDcNodeSet.java @@ -16,7 +16,6 @@ package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Collections; @@ -32,7 +31,7 @@ public class MultiDcNodeSet implements NodeSet { private static final String UNKNOWN_DC = ""; - @VisibleForTesting final Map> nodes = new ConcurrentHashMap<>(); + private final Map> nodes = new ConcurrentHashMap<>(); @Override public boolean add(@NonNull Node node) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java index e638913edfd..ea7f42a0492 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/nodeset/SingleDcNodeSet.java @@ -16,7 +16,6 @@ package com.datastax.oss.driver.internal.core.loadbalancing.nodeset; import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -29,7 +28,7 @@ @ThreadSafe public class SingleDcNodeSet implements NodeSet { - @VisibleForTesting final Set nodes = new CopyOnWriteArraySet<>(); + private final Set nodes = new CopyOnWriteArraySet<>(); private final String dc; private final Set dcs; From 5f0d5365bb2ba9d6dd057c2fabef2d2d3d493e98 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 11 Jan 2021 15:22:49 +0100 Subject: [PATCH 047/395] Make fields final --- .../oss/driver/api/core/session/ProgrammaticArguments.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java index 6d693f69b72..75a49fb3a59 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java @@ -173,12 +173,12 @@ public Object getMetricRegistry() { public static class Builder { - private ImmutableList.Builder> typeCodecsBuilder = ImmutableList.builder(); + private final ImmutableList.Builder> typeCodecsBuilder = ImmutableList.builder(); private NodeStateListener nodeStateListener; private SchemaChangeListener schemaChangeListener; private RequestTracker requestTracker; private ImmutableMap.Builder localDatacentersBuilder = ImmutableMap.builder(); - private ImmutableMap.Builder> nodeFiltersBuilder = + private final ImmutableMap.Builder> nodeFiltersBuilder = ImmutableMap.builder(); private ClassLoader classLoader; private AuthProvider authProvider; From 57fdce590f0dbc79858a888be37918976a56c220 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 11 Jan 2021 15:32:17 +0100 Subject: [PATCH 048/395] Log error when BlockHound fails to be installed --- .../DriverBlockHoundIntegrationCcmIT.java | 13 ++++++++++--- .../DriverBlockHoundIntegrationIT.java | 18 +++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java index c275eaae12b..e771b28116a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java @@ -39,6 +39,8 @@ import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.blockhound.BlockHound; import reactor.core.publisher.Flux; import reactor.core.scheduler.Schedulers; @@ -55,9 +57,8 @@ @Category(IsolatedTests.class) public class DriverBlockHoundIntegrationCcmIT extends ContinuousPagingITBase { - static { - BlockHound.install(); - } + private static final Logger LOGGER = + LoggerFactory.getLogger(DriverBlockHoundIntegrationCcmIT.class); private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().build(); @@ -70,6 +71,12 @@ public class DriverBlockHoundIntegrationCcmIT extends ContinuousPagingITBase { @BeforeClass public static void setUp() { + try { + BlockHound.install(); + } catch (Throwable t) { + LOGGER.error("BlockHound could not be installed", t); + fail("BlockHound could not be installed", t); + } initialize(SESSION_RULE.session(), SESSION_RULE.slowProfile()); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java index afe08817fae..8c6b197bbd5 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationIT.java @@ -17,6 +17,7 @@ import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.rows; import static com.datastax.oss.simulacron.common.stubbing.PrimeDsl.when; +import static org.assertj.core.api.Fail.fail; import com.datastax.dse.driver.api.core.cql.reactive.ReactiveRow; import com.datastax.oss.driver.api.core.CqlSession; @@ -27,9 +28,12 @@ import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import java.util.UUID; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.blockhound.BlockHound; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -43,14 +47,22 @@ @Category(IsolatedTests.class) public class DriverBlockHoundIntegrationIT { - static { - BlockHound.install(); - } + private static final Logger LOGGER = LoggerFactory.getLogger(DriverBlockHoundIntegrationIT.class); @ClassRule public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(1)); + @BeforeClass + public static void setUp() { + try { + BlockHound.install(); + } catch (Throwable t) { + LOGGER.error("BlockHound could not be installed", t); + fail("BlockHound could not be installed", t); + } + } + @Before public void setup() { SIMULACRON_RULE.cluster().prime(when("SELECT c1, c2 FROM ks.t1").then(rows().row("foo", 42))); From b6f72736e061de14ec6f2f26fdce97a665b37092 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 12 Jan 2021 15:14:29 +0100 Subject: [PATCH 049/395] Upgrade native-protocol to 1.4.12 --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 7ee0bf21874..7e2aa86d4a5 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -71,7 +71,7 @@ com.datastax.oss native-protocol - 1.4.11 + 1.4.12 com.datastax.oss From f624ebf5df4d93eff34b4033ac57d9fb4a6b12f5 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 12 Jan 2021 15:52:25 +0100 Subject: [PATCH 050/395] JAVA-2907: Switch Tinkerpop to an optional dependency (#1522) --- changelog/README.md | 2 ++ core-shaded/pom.xml | 2 ++ core/pom.xml | 2 ++ core/revapi.json | 45 +++++++++++++++++++++++++++++++++++++++ integration-tests/pom.xml | 10 +++++++++ osgi-tests/pom.xml | 8 +++++++ upgrade_guide/README.md | 28 ++++++++++++++++++++++++ 7 files changed, 97 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index c6b981226dd..d54e6d8713a 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,8 @@ ### 4.10.0 (in progress) +- [improvement] JAVA-2907: Switch Tinkerpop to an optional dependency +- [improvement] JAVA-2904: Upgrade Jackson to 2.12.0 and Tinkerpop to 3.4.9 - [bug] JAVA-2911: Prevent control connection from scheduling too many reconnections - [bug] JAVA-2902: Consider computed values when validating constructors for immutable entities - [new feature] JAVA-2899: Re-introduce cross-DC failover in driver 4 diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index addaf4070d1..ba8101ea31f 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -91,10 +91,12 @@ org.apache.tinkerpop gremlin-core + true org.apache.tinkerpop tinkergraph-gremlin + true org.reactivestreams diff --git a/core/pom.xml b/core/pom.xml index 6049cb2ef63..40090ea75a9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -94,10 +94,12 @@ org.apache.tinkerpop gremlin-core + true org.apache.tinkerpop tinkergraph-gremlin + true com.fasterxml.jackson.core diff --git a/core/revapi.json b/core/revapi.json index 592d810e571..b20a307277c 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -5440,6 +5440,51 @@ "new": "field com.fasterxml.jackson.databind.type.TypeFactory.serialVersionUID", "serialVersionUID": "1", "justification": "JAVA-2904: Jackson upgraded to 2.12.0. Caused by the exposure of ObjectMapper as a parameter in ExtraTypeCodecs.json()" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.process.remote.RemoteConnection", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.P", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.Path", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.Edge", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.Property", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.Vertex", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.newClass", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.VertexProperty", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" } ] } diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 3cf5c8076cd..553199ea830 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -131,6 +131,16 @@ rxjava test + + org.apache.tinkerpop + gremlin-core + test + + + org.apache.tinkerpop + tinkergraph-gremlin + test + org.apache.directory.server apacheds-core diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 9a3c62ae770..cfbc99e7368 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -78,6 +78,14 @@ org.reactivestreams reactive-streams + + org.apache.tinkerpop + gremlin-core + + + org.apache.tinkerpop + tinkergraph-gremlin + org.osgi org.osgi.core diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index bba68707f8d..3b3125de12f 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -87,6 +87,34 @@ token map for these keyspaces, you now must modify the following configuration o [Metadata.getKeyspaces()]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- [TokenMap]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/TokenMap.html +#### DSE Graph dependencies are now optional + +Until driver 4.9.0, the driver declared a mandatory dependency to Apache Tinkerpop, a library +required only when connecting to DSE Graph. The vast majority of Apache Cassandra users did not need +that library, but were paying the price of having that heavy-weight library in their application's +classpath. + +_Starting with driver 4.10.0, Tinkerpop is now considered an optional dependency_. + +Regular users of Apache Cassandra that do not use DSE Graph will not notice any disruption. + +DSE Graph users, however, will now have to explicitly declare a dependency to Apache Tinkerpop. This +can be achieved with Maven by adding the following dependencies to the `` section of +your POM file: + +```xml + + org.apache.tinkerpop + gremlin-core + ${tinkerpop.version} + + + org.apache.tinkerpop + tinkergraph-gremlin + ${tinkerpop.version} + +``` + ### 4.5.x - 4.6.0 These versions are subject to [JAVA-2676](https://datastax-oss.atlassian.net/browse/JAVA-2676), a From 1ad477a2ed725336b67e842f932eb590cbbb5d6a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 12 Jan 2021 15:56:21 +0100 Subject: [PATCH 051/395] Update Fallout duration test scripts and associated README (#1523) --- performance/README.md | 103 ++++++++++++++++++------- performance/ctool-cluster-info.png | Bin 20505 -> 14654 bytes performance/duration-test.yaml | 82 ++++++++++++++++++++ performance/graphite-setup.yaml | 94 +++++----------------- performance/metrics-dashboards.png | Bin 80419 -> 0 bytes performance/oss-performance-setup.yaml | 79 ------------------- 6 files changed, 176 insertions(+), 182 deletions(-) create mode 100644 performance/duration-test.yaml delete mode 100644 performance/metrics-dashboards.png delete mode 100644 performance/oss-performance-setup.yaml diff --git a/performance/README.md b/performance/README.md index c4b6ec2e929..e42c83a57f7 100644 --- a/performance/README.md +++ b/performance/README.md @@ -1,27 +1,76 @@ -# How to run the Fallout performance tests - -## Setup Graphite - -1. Create a new test based on the [graphite-setup.yaml](graphite-setup.yaml) template. -2. Modify the parameters to match the scenario. - * Change the dse_version to match one of the versions you plan on testing against - * Change driver_oss_branch to be whatever branch of the driver you are using - * Driver_examples_branch should stay java-driver-4.x -3. Run the graphite-setup test (wait for its successful setup) and get the graphite server address: - * Navigate to running test, and obtain the ip from the observer node this will be used as a graphite server in the other tests. - The ip can be found in the `ctool-cluster-info.txt` file: - ![ctool-cluster-info](ctool-cluster-info.png) - * Login to the graphite server; the address should match the observer’s, the web interface is on port 3000. - The username/password is Graphite's default: `admin/admin` - * Dashboards will be loaded automatically. - - -## Start performance tests - -1. Create a new test based on the [oss-performance-setup.yaml](oss-performance-setup.yaml) template. -2. Change the parameters in the same manner as the first test, with the addition of the graphite_host parameter. -Use the IP from the first cluster’s observer node (the previous setup step). -3. Monitor the performance on the graphite observer host IP (taken from the Setup Graphite step) - The performance tests will report metrics in the two dashboards: - ![metrics-dashboards](metrics-dashboards.png) - +# How to run the Driver duration tests + +Note: the procedure described in this page is currently only accessible to DataStax employees. + +## Overview + +A duration test applies a constant, pre-defined load to the cluster for an extended period of time, +typically 2 or 3 days, while also generating some chaos by randomly restarting nodes. The load is +a mix of reads, writes, and deletes. + +Duration tests are useful to detect performance regressions between 2 different driver versions. + +The Java driver duration tests are stored in a [private +repository](https://github.com/riptano/driver-examples/tree/java-driver-4.x/java/durationTest/) +accessible only to DataStax employees. + +A duration test executes in an infinite loop the following actions: + +1. Confirm row does not exist +2. Write row +3. Confirm read of row +4. Delete row +5. Confirm row does not exist + +The actions are performed randomly via SimpleStatements, BatchStatements (except on reads), and +PreparedStatements. + +## Running the duration tests on DataStax Fallout + +DataStax internal Fallout server has modules that allow to automate running and monitoring duration +tests. + +### Step 0: Set up a Graphite server + +1. If you haven't done this yet, create a new Fallout test based on the [graphite-setup.yaml] + template. +2. Run the test and wait for its successful completion. + * Choose a `keep_alive` parameter that is large enough to run all the planned duration tests. + E.g. if you intend to run duration tests for 10 days, set this parameter to a value greater + than or equal to `10d`. The default is 15 days. +3. Obtain the IP of the Graphite server: + * Navigate to the test artifacts. The IP can be found in the `ctool-cluster-info.txt` file of + the server group: + ![ctool-cluster-info](ctool-cluster-info.png) + * Log in to the Graphite server to check that the server was correctly set up: + `http://:3000` (VPN required). + The username/password is Graphite's default: `admin/admin`. + +Two Grafana dashboards should be loaded automatically: + +* `Java Driver 4 Duration Test Metrics (aggregate)`: provides high-level information such as + the number of completed tests per minute. Useful to compare different test runs. +* `Java Driver 4 Duration Test Metrics (focus)`: provides detailed information for one specific + test run. Can be useful to drill down on issues encountered during the test, or to inspect + latencies, throughput, etc. + +If the above Grafana dashboards are not loaded for some reason, they can be found in this [private +repository](https://github.com/riptano/testeng-devtools/tree/master/duration-tests/java/grafana). + +### Steps 1 to N: Run duration tests and compare results + +1. If you haven't done this yet, create a new Fallout test based on the [duration-test.yaml] + template. +2. For each combination of server and driver that you wish to test, launch a distinct test run and + modify its parameters to match the desired scenario: + * Change `server_type` and`server_version` to match the exact server you plan on testing + against; + * Change `driver_rev` and `driver_label` to be whatever driver revision you are using ( + `driver_label` is merely for reporting purposes); + * Don't forget to change the `graphite_host` parameter to match the Graphite server IP obtained + in the previous step; + * Finally, choose the desired duration (default is 2 days). +3. Run the test and monitor the performance on the Graphite server. + +Once a test run is finished, the cluster and the client VMs are destroyed, but their logs are +conserved as test artifacts in Fallout. diff --git a/performance/ctool-cluster-info.png b/performance/ctool-cluster-info.png index 041203cbf42c5ed92bcda0fb4bc34b97a0baa51f..550b077b7ebe785c5bf0aad8a4ff6ac9aac5b478 100644 GIT binary patch literal 14654 zcmZ{L1yo$kvhED-?(Xgc32wn5xLa^{cL?t88X&m41b2700E1g_=aF;%EAPJhW>(Lx z?y9e4ckQ*iWWp8XB@p58-~a#sqLieV5&!@s{h*a$pgw-5{cBAC00b)wQBegcQBe{F zM>|ss>yIYM@MLvp4doH69PNZSArV*-63QE@up2VUAgod)NPJRQiX;^DzzD>#AAwfb zs5SZJWD!+W{tR@6>R1Dt*zj%D%*0;2w_<)OX3y-^3;e$Ht< z1lA~M_n$s}>3_K18c=)CemO1Quh61-R)q-j(^jo5Zo4MfrI!Xg`!N-G>lCpE-d?fSuq0>yQ%?KpTyt`;+mv!?bQP#Nen1b1RV24 z!?%rsLd`-yi=1#0dyNXEt{~|_A%{djR+0GhQz|=#;5cM^FE%TBh{waM6l!1V<%4if z#Ck1LCk?6m$hB}5Hcok3q;mfXtF+g8R4yUiQl{`J-9)VNbAzXdy- z40e0n>%S$&zI(ma+?9vGa-d2_TQ8G~`Yb2l$Rd!1po)eywE)jUpSMvj@c^0Z=iy$6 z2Y(iFE~BR9-DO*Z4@uV3nRF-~nMNh2fsdj|jgrqzSS^@)&VAqx`ol=+4!Y|A?(M2+ zWc2&coQ=Gcq9|=W%t5zxzp?Gi;`|13-gw0;8b`p&{&V^#-i$Sv$d1LWMF~`^RmoqP zlmD(NFvxj#&mIMYipUhc|m{pho)vF)(kJw9`0R>q2 zmxOo~3UE|XHe;qb99rQ;GSIMVA>JeI=ZGvZCX%yZ!ada4=ni3le4Mfn%L4HdOdhOT zv2=58yjb}!?9;gBz%~fo@RWSjLxBb){%}1JyF9`}nFeI=G`gRW>4r#Y)Puc0YB3lH z6Ai9w4J$Cpdo63lAF`^y5o#dcp;GTSX9e(fV-kc=Z|itN2@vZCr0#lM^1OWVMf3~0 z-_eIr2_)^w*_Javr$S|eVTb(^q}0pQi`t9ZlF9>n5hnJ7X(rDZ`VqBN9OKC5o;h1AUuH){N8-92@XaMUXGMi436|w>BbGq2}`&6O{G#5dP@LD zaE64gROQc{9|DEGc{3Iw1vv^7G|nu^-2>L7#Gry=jP$(WfqXj_0=wBNUSt0 zYCdt}U31WVim_auJ)A4FikXXA9G}t2Z&kkzG)={l8k45ih%9atvkG0Lt)zC2vXwWR zX}uY^$-ZH~k+=EL)X1sLtK2T;)#aM$S{;)TQ!f8wk|7%|+lYs-Ev+ho9W+zrlpv-lCLGj{N`~>pw&uzpl(&5JRbK%r9^5WF2et~}VdpCfqhCR)k zWzHb72lso<%xZy;xRV5StiY$IDpE^xGaM`KA^Xs8<==ASYZXi4m(3GrXbXspbaw%} zvb(o~L(%PWhg7~)B8j(D)UtXk&N#B-oCQ%188cRv=6I%b>>IYLrmJ?QHYo;8!>9f$ z;7$>(#U5>sp4V8{dhqCxl98=g99V9QBPls4U}MoK2Mk-nc#KsboAO++plz+TQ*$_+P}0hx>z|ppPv6_a;SE>xU0F8ye+wD z0hONN?zZ+`cVPF>Pg@13CoW0Yxn1yGh;I5laX%P8p57ke+41KH`W`$`cbaw*Y@Kxy z`XY3xblLb4zWsb7c&B?G0`3Dl{B?m-=}qIZ`vUvrLd8N-+wtA^40elrYECFv7#_StvS0FD(5G6y$|egNK{BpS10pC?0*pjJ{ilc0xD5I8_s*v~2#Yk%4EH#>4mb#|WmFAShqT(uyQ$kaA zExM6I%IWy#c!1GN`$gGSzA=Z#>NwZ}YOb!BFtbV^oBh?Ej+BGe#qJnDouNE%Bx6*p z`t#ONb3J-JwF9u}smHaI+LiLox54FOhrR%!KAPewkDIO}v^yr%on9vRE4bs^Rxn zpYn0>yYHupo%+6C-a^yE*^#GavnVqbc-Cz1u2!btMc{lhzEAz0v`Dw&ar?b4ah-PE zG$pZLJYlD4&}lFdIN3Yh%MVWrUyt?HG;A@m`o)h?UTeLj-(2c<0<~b!n}V_!eFDaY z)^WY_37dDiz2=%@Dkw9>k9HqZpTU8SmJwH@N7v!ckb_{#D|ZW6F$)BcxSsMWl{;b53oi`>Q_wPrDX{W34t9a+3mUBMD70%|5C~xpFSVB=}J~ z6$mwgl1~*ndXK*BcGnAxKyAxrJR8Q9CyPw`wX?JQwUe@nGHEvyx4jGZCU%E|)?7Zn zvQ3kka^t0gjUO9?UWWHsRd*#-n^rAus)$*jU_H@LiSfR<~!$ zX41tR5oo()IeL%$=|P92e##h_;HPGn7qCd*bi9}^R9^b}m2bn9>Sg?~p49AXwowkR z!{)vB9OMPO1hc1JMc1BhY1KmI?XaC~7omldU3vSdL+kH|rR2f8KW9VLPx|~GjEAc$ zC#NT=wqhIRUFr7Mca^lwJhs=iZW|+=*H5-@8*g60_ptYo#O8c7KIRWK$8Kv|$j&Wp z1YQ_7CASXiyIx;gzUm1i3lJXaTtz)q+_a8dA2S_P{XCC5r)Q?>I`pRXUD;B;3Ed}7 zuC~^Dy)x_0t^Aef$*V7;huo?8NA3OWyi4cZ@+k7i>w)P&_x*VX`HA?>`{u>{TzR(m z;FTR(65J%$Mv%)F_TABs#mrt|Jl;OU7m{Up`o3~ImCg$Kv zD6%d1ZNS4pavfL_oc+R;vw+Yoyj%fC%GD8z1RxOr4T>pOJKFSCBpDTDm2mtz{hW1f{^1%K>8c3Q4{vR|z`GW@#Ru+|# z`nW0^IhvT*I+@!!uM?fQe>A|_OKLg+09cfN3s6dl;t~J=bFxs;aMqBM|YW*AN1d5W-^k0i8x#FlWE8)kciqj znvifZu`sca3BZw%knlMgoAM}$iT?xtsPU7TJ3HI+Ff+TkxiPu1Gub(sF|&UD{F#}B zjhT&&@k4^q$-~z9n>(Ye6ZyY8`Hz0YOq`4yE$p2w>}*N?_WRAy&c&IZjO_0~|M~g% zJWbp!{%a&#r+=39u|Vd(9A;J~7UusA=4@g5|AGDG{2TVKb^UudzQ3LEs5+TAirU%O znAkcC{MQ}l``1YS7xTa7`EQ_tg}aHhrkKSC(&=MO0<4^z|DgUS=YK_N{1=jgi~GML z{~PDOA^$Fc=c}W|$2`CNy@vvDGt;$!~1 zE&pws{;dQ5YW+|G0XRP9|5PXexLBP=P5^*bLrP3o#T|H-4ehTwurP!SZ=KI1qm9*5 zbkC#&Ax3JcAdHdhPYFdk=*=2mvize&G0@=s2U@#uw0A^O34{s;%F(a;&iSIgx^CYC zx6R4(-CEEu#+n+p8;7y+tn|yF%{n zEg1A_vhq26>8?|}v>gP)m@t@(S}Kc`+SFqyjEP1=F}T<+33Gck{B#{;$t%OPDLx*G zii)!(isYr5^*`kd(ibkzv5}DWaDo7NEA?h$85~xHy6vt?rAm~U8*tET9g6!&;2MJM zu4f79>}I1m{9b!kW6bydG{xf`lE=XaA`e$B1{y+u=?Sha21@CqONb*f)UX#Ks49(0 zt;Ry>WV$O*s=jnE9OkK(+qsv+z>BFbu!xuq1~rHZDhNIV5(0pV3H6 zM7jsrD(o9q@bKV{>|ckT6Ui-TyaxzEAu|+eF#se$3-w5a4N(*4Zi731e<6_=Mt1}i z^^OF@2@mJWRoJ`Jx+85ny3=NZ=e!hN|6s`l;RJb?8)()~wi1tfzoebDs4t`KLiu;T zJz4RFu$>%)=+94-`I{o%!WpPt~GCi0ajx{rC|NuS{jdG6Shet5s1#An3~{ zhpNyyJS@pRfV!`c^v7`9Q%Ol_xUXBQ+vU&KFA*$m4-d%5ge(uKzlrG6_MjKtKzVYV z@4ke`tltz;ujh)tnzbB{_#E!P;hHi^R8?>O*#QYL3DG$HOar33L>3+TOhGXn^~qiT zU7=15k;%63u&|o!+VP(>YMGoil&q|Z=dA}h4e8l+{xjc^1!%H)T-ZP(!(<{3%ei~G zc_UMlNyC&izxSka2fBTZp=Vue!vt;4AN6@XnMzKdwhtW&#ehu+FXwlcD_d2a%&ZAim?Lr5C((M_|(k5ZW21KM(Nd<>wSf= zn_@*Pv>CT#1ISWRdv02(yJGU zN5>iIrr!>=>pyVEF_Y{qhs_#*@^Hp?2v#V0?Kb&%i*;7&OwNdy0D*}1pM$T8MSU=g zMiMB0!l)XSOI~A56d8{s{4{Q8H0S}N2S4PnT9lyad) za7bhM@6w_}p8*IRSpq(7d^gjgvp>GTpM*X`8~ED+a9-a&RC?lvL-kyX~l26k<7FHVG)^`*cKIFw^1TRNn4(p%-a04P`qf-YCFRUe4-r ztkQa1R&KoA9RTG{?0p$9&|EX``|ukYeC%V0G3s1zLjd$yhf;6Nk8f;G-)A_*F~(9ku$VN=jrOtxIBZtu-60i-1-vzU-=DY2*LX#mY&Ynx52l)*Vsh13Zi$5= zTaeNF*r)i6g!*;HC2VT3?7%vtR(jG6&Hy41AUB{mg zTK9nnOt}_zWjIq?f0$shR!17;jW!q1g1TOE37Vqg5TP4RoPlt@H2_6|>-+obgUlF#6J*vDS4RD|7~t;vXp1TGAeweCdF8*g>`TpgEJj~3c>C4YxT#sdH~T0|&z znC~~esx`G}4hy9cjc*QTt|oaeGz4o!2;8-T30`(9aMp=e!AOA6LXb72-ztBb&Zxx_ z@gt;ZH(Hv=ym!6bR#%RfC>CI(RW-QPWlv`_wxKm5CZ|;kff$c-Mi)0opqY%`2!pxap35^ zNSEVjtbKrdulsYV^(q3UnGXd9_4FW*B66)8FafZnOO=X@dxK!b{XnD1b>=f&c|@ zG9cu9FTo5P{0-AfA3G#hH7f(fj5Ixk_F9e! zML|NH{wTdMb!5xq;~K={=l$L_rV2Wv+(780w1Dt?=Zl#QQ-@-f>3lwRfr!Bf1hs`` z%SOJ-Zt$yq^si}=-E3?IVwxCWk%zzTH`#pwBK|l>Vpp)4Gq7bpoIf^|)1cqc5P5E< zK%$bs=YYVZ|JJZ5*2H2x-t}xXlWZRnFq5`B;I<_fUu!fZ{h<&h&v$3NqZmS=YfD8k z*vjsP?3eIMQEyE)Yib{b3V$J)K)}0Yz^3#0oR`q7P7a{qqw)3Qupn1&Z0-Mq{CeO4 znD3ArHFlVjv#FCGUm|c4at-wxlOTE`n&BokVqo!!NULvXz1Z4 zweOfaE(3um5kb!wX$qg#^HLbKGupoZlKdUxYi=mLD!?&<-G_YcH_X&vrDsl3^f*Q9 zmmu>DQmAZJ8>AMibgi~SA|>!Ck|2u?E>`k1`rRKADQ=R*^0IEWzklaoLbp255D|QT zsn;ZwwQg zM2`#wwm%)0Pl3U8M*#$kpsY1rz~_NxfEukv%LGRreohHqB$nUQd8Z%ez}A27XLQ`% z(VT?9(;+!H^j#AG0gxmE^Xa@d1QGxAi?~|z&hGBSo*PI9*AOM`eY}%~J_SI_N2aq( z|24J$y_>Q7;6e{TL8H*+`^wP7X3!0&Pcny(gq7K|^YfB_dpQu) ze$SKHUK}v9m%3sDirj?z^9!QwLPy!l)NT_?QLq&z#dmNQ zbs(kMT;7zE1BvWscd+VppPYf$`z<@Hz3F^W(8tR)p+-evNZMqbiDjamY(HcG=F;mt zZMVY>AsPG;Oaz9Dor9g_Sp`5Y^gVq+Fdu~m02kaoNQc~e3K&j?Bv@t$H4zfRf;WE) zeB3|guw7rS08~JlI$*?hA7#63S}Y>M1;Xz#keZ9cibaKqMTNJ(ON%3fJfKz~O3V3a zgiwdc;XZ|YNg;;Si>ndn?e#G@Q|lb=J0qpq0~#V5=19wrQM<6ksqj-TpSP>N)k8%VM-2U2gAfYCp`60bOH%wy1 z`;BrEK++QJkE;qDr9f1CgPZ)DhzZ)6EmN*E_R>l0PmQEKX^m-%1n>9`%}fq|3(J=Y zM z3`l#ClzSTfy%2OEW7mRY{pmmyP+mZdQ$HgRqoj|2b9b*3Jfo$BP8<)?DFPQ&_=RGZ zYqWOxC17^O(Z->Wa7hplkc2)^kgcGkp`qAF8us|JV-^W}PxuvV?Y4>^DX2G~zKH&C)ePRpKoufcpM{p3@~Zma3W$|@ zs%Oc??G_;{uv8^4?Vr&4M8FOPr9Rc@LRGmvxVsg?>lSfVRWEo|wVr-9gUx^eZa}%c z)hy(>@@F&WD-|*2<$;W;GeIuc8sZs`*Jrrs9Q7xWU7;9Zn(yKFSyBAFJyT4AN%H%c zj7d1<-xsJW`o@!Z4m(RXuZoqJLYzDI4h^?A2G~MwipmJ0hBe_nmuS(HbKjRJAPIaI z_PR<0D#QJ*j1vyi%<`uwmt;Ui&%5E;fG0)%PE_|{GnD^hGxR_me>ZJVzYN?F8a~G% z36kkC6>NH`f0+>fj9t)@C+-)+o2h=j@%h{}hYR|!rZ@DZ<{O64Rp7eEqmIl&x;5Q&p$mMwckASa+LGFC(iAIcY7!#P->F~saSsvj- zjeaQZtZptZmOEoMK2nX=krgcV_%p&y>+h%FY3VAVFyKzc?+74SK9$-<-_0w_@l~<- zN-F|NEyEcEr%Hz2W8f4phZQ{yJB{gK>R9K7WiL&^pg4;;)&N9NtDGLBAoBg!Cp`cc zbykP{@wO{(YpcEI+3lw;?l>zH$DYNkekUD5p-`uo^Mk|vrEdPVgH-U%YyPemX35IX z4zb+SY`4I)6;|f8D|3$z16G0Mv%Q{hi9uceN%9ad7W^OqoCqdc#@5T`FV`OHuT2|C zxrz8M3zzb5Ep`2F_3FdI-Tu&DPnT1M2<&b|wH=s{cK-*+X_M+mB4{`Y=xNI0ubr^fTUFB4XF3&jszlTCIO^}uBh>)K<2KOD}q;!Xc3^uL&aZX)LSaqF5kn?cW*}- z&Q9zg1-!+u(Q=_q@SxAE^kMBnC-g~LJ|92|Hr?-U-}CUy0YG7%XuDsWJS(`?qCX`V zwjpUI`Gd?ak~>X*LoXm8um_ndQY(fG)5Fl2s`_CVgHs^;!zIvQS9R*h)(vT-ZO_o( z!1KeqEVL?Uh`f=>QwWwrfU_I_cw0dgh<0L~Fx33hGd3oOv|VLP9s0QB`KB;A;SLu} zxwl-EpKp!c!`X@Dwa7ejzhYr115gx}Zaw>IdvZX{EOLe)OEu5)xZ>xxDr*avUefm? zbY2gtg<#JaAAMMII|z_?7uetDE4GYp)Qrm{!W?c({|*fX2Kb}vrZ&BPkk}fVu2~?C z=yA7VW^#YNq10@68;$0G;0oIuik< zJAm&a>EOeNQfhTHX*bo(#ca&9Z5zS)bJ>SHru>zkl2NN+7!?JRzDyb~rF}y8Jbe0K zms)=G{B?+e^Jh?=zwmKcywFm@*PIl_XC#?{Lz-}esSU1~2PJwDA0;3OH-{_v$OB9z zV>^RNw2pCQCwx)Q7k$)1{v|9KyEA)z+R`zRITYm1{DS$36cGWkH(}Y z5YiPnV1$PB>4l6=|~9!vRKzj1n(XE818Qj(L4?z4^&;-qe;E>Gv>uNyDFssP2b z&Awizv%bD4v}Rz92ff?yy%Seq)9;gJeCS&mXht-j$K#>oI$v!=x-IsfHo@R;e~NMA zOpL(&0Z|e}9%8N?-lxQSs%?skrg&GpkLxNO&H{@U`0_?*iepIQaK^+JTl z#-UpKa?b;sCBM!5W+dCt# zO)&6LbfP%yMstmR99>KvE`O)Dnf|7eJfi)QkdROmrUmDPOpurJzPO;tB`Z&n zi-Ezk-g$q13jOv%Td%|u-2H-X32apf@^5V)-X7*wP-0+7#VNqo*Rbr)?g)cvaEd~}&=@!c$jaR&5D$`p&6gFNxaBvg~PiPb&4j)I^E(X(At0e?7 zkDgW_t^Z`HERW7m-5*5Y118iHx9F4&h+AdPp_Tg7kE#t1WzF#*os?fW?nh+L7Arz} z?C0FUp%o{EQd5$>jK3L5Wo0X21VxM_xU`#`|9o}4HQ}ff(&`V8}fs7ONrnKTo z_>Bto*3wT3<2S3ZvulpFv%({c>wdv=Fqy-F2`i%B zrg_bHE4X|{B2veLO(?07mUWi0(4tlwO;()Sh@hXQSq7l6r&=d^rlzFA9p_l|C6wH% z*{;%09IGTKQIZ+&-o4hTJZBV=;ArPJe5zLe0@L?WXCA2%1Ct2Kyq9@Qv*BrqINroe zwP{BlF$6)Th-M#S7Roo`sG_-`C&};pMjuT5JjN;A7*SMc8!Zh*ppms|gD>t5aX}S~ zJ7vbaMVhKcOYh}^P|kTC?^r}$q}o@e)F$ST{>!?&V#PsnR19nG+Ge)Fm68?}lLH(DE#Y?&{{Gsh4sHP>-jDwnxU_K8jCj3>?KiO01jMImjj z&M?hxD^I#gjgFd9%RUNi13_cGjqQcTDh{Q@`U0=0dzVoQOP4=>*LmJr;_`boROq%Z za=r`Oe(dmUt&v21jG>|7tWbX!Z3XeHS*{P2&(lr(NFp_UcMB}ECZm35NB_XU$Gqk6 zx$W~Rv>HdHhE*uqvO&d-^r5uI$%0`TgoB5CZ*>%Ws`xjl(xU z^-qsqie!B}yYXF{51Yepq|(=3m2@_<0!?QBehGcEtk{%U+p-xj)3htcsdFnRK!eQ` zY3qHo#ntJtGl*ny_-M?rU4eCpju+skjALiNd}$Cr~4+6KJ~D7+27&{FK*G#8<0Xe{gEk@Qg{f zSq6{){g*d~Tf3}&t2!Rvdx30L?cyLp+{W{7Z;w0u`l1snCzGK~a!>t@jrq<31b_Q$ zRCeQm!C#BH#hn^-ex3)|9zHvcghRqdPdy?YCga}Gk=ZF1SQl}a?J>g%grO$mQ~1d# z!#Ba1Mf+R6aSqo_V_CQ1vo9drtMi}%)6YO5K6+ld17DpcQQsABgh0tPs!NG7EE}qd$hu_pXgVbnZb?W(S+mkGZFg@1@5I_p>4?>P?BjI!) zMpKhF4S(`(gaTx6+GGGx${mKmJYHI$k~CgHSc3&tJ!-*LkbNPx)-Rk5kC6cyi-L&2wV?Sb{ceWU#mD|Gc?Xul&e@`Y^Nt0S<-DN({A<8VoO!R@gH zwv+rjM~_`g>4OI6C);41>o>3!ZDzHmlc=?eYgM+Bc=qe+SNr_aQsQ#kEZ<*AgB&xl z_BxrLTrLAOoWu+$)-+_p~2;7g{^n2w3VHb64@ILygI#vR^|6K zhgg+TaS@gS2q#;@KN_;Nt1B4$x^8H1Bf(c?a0>%`R1~@25<8TXLaGfy_Ln8l>vz^qbKXmJ*VT?K7#%!K#!4;eB3a z#z@kF7f3%bWrPw_X6zZR#wz!et`;OS7Wuk58ts=!7VB(BLztmomKZ-PZKi#UBf@+6 zQls|aX($qp#&bnFM7eI=&#>CNUD9t>T~pqFdZZ%JBH`>mLHqDACoJiCP2fe-VjD>a zLE;g3RPH3J>&4r3J`VcB8uV%PE?8}}-Fnmq!6Co|EIw3H1o}PkT~Xxgx8P0xj6Ov( zSq_PzzuSpq&O!BtqDbdQNqV|Hkuf$djAySaebsI9ZC+n%==fAsS#G5j(*%8I{&O+# znF-%Vp<9lzOJ(d`ZLHZ6#SEl)XSFsTCyl-|%;PfEbiqU8lhF^cx0GZ)v6c4-T4-D? zV2!kIbZ^PwcKVg1mb%xX#j!w_8b8TcKDJERZfqVK0wqKvWBr&=_fo1ar6R`q+5ILc z=?eTK=V}bP?kFw94dtfo_~*oGy9m+qfpcrqm#lvE==fA4E>#=vBp*RjXBwquD08MQ^Nue& z)nK5YzA2k?b=h8)3XhCwc>Y;fHqMZ|6g>+l0$cjMOI>6soqLgp8jJH{^}y*kvzX$>6z(a}*LdYZv=i%?W}2Zf#2E9SY4G@jsJ;AY!@ zada+}W58xO|JE0>vICuo-|l>5coj;}?%NKve#?8&K~BiyjIzVWkkN6wsLf_Pj8YF) z8hZLSlI2^)B$0BYY5fgf+SKr zEcxAd6Ujq1InIZ%WWH%5oXzI~wzSYxke+YLH<#w?Bgk(4<@57b$rZLv0Tq=%8i$Qz z5NM=*7Q7IkoB)O@E#{wwkq-z>Kzw$NX{gjz%vh|fIL|WC)H$r7tB4*`3lT#)M0+DD z3czf!UvQ9)y=d`t+F|hted^96c1OSQx~~2uQ=MYMJ(zm z!mI$QffY|~QOv;kXEvQBD#4-TQCEo^q@*5~sdNOu1p`xdrKm9gK6!ooTbew3%lz#( z8@rDzrf4L**FtsHTV5L9e_v7z+^M{_nC9MGXlyXlCayBM%;u6$QI25ZTLhe(i z`ozgvXpv z=@hd>%jCWL&O$L6N29CRdxgSMs}MYF?x3a&_)~dbrL;=$Y1GevH%pTud(6mY}_^ z`o%H$dbiQ0gKE}D^YLDY$D!rmt7ToA=ppJPGnpi6htWvs3aWiJ;NW5R%i}d8Q8>N0 zhCjdPFiVR2$H{g=DNy36ixQeaHjYB5Lb+HT>;3oKF}+$v+(*0;+7ZYOXZWh+A$7siH_`7@3kZBQeH8GQ17b(8=N-e0KOx#V1s zBP0_K!)`iTdVq1O%y++awmO?Ss%z6p-}NX!WRat+kl9km&9#-_u$HvWbi@`oaFPNG z<)sLZ*7+|F$6wK^ZMP9CF(_Q#5uH6n_ zBh|}!vuv%{@=?)itNy-TTwB96#Fzjq@QsIoEJ=VvaSC;v&2xtJnIucK(~BR*!z|o;X#)vzd+PXGDDR)RABZ-h6|F^5cQvJ1s0M zY%h~};IL}BT5|K2?-~Hz!AAlq%U!{d6Kk^E=B_yDc)PmPK& zwwE}wzy-H;htL2e7ShP982Wn8FBtsSfp+OLQ+ER6V68(Rk$-;Ao0{})TA!xm?+hri z_~UR4+IOcbb9!qA)U@mvbdl58h3*SZzZZ$0pbz1TUpUfC`C37j~@yC%C7 z_hJ0BYp1x1-WVYpV{O_X#uScAeB(~D9Sw?&(4_h{6ExmQW`wbcpRfOye!#no-||Me^&XC#q`PK zR}{t#RE))Y(h$jP52&V<4EX?{{{FWKgCg@v0C1%VF+IjWJRnr7*c6pus-4-OEgcYw zNt^_eaTDr&KZ%2(U>vwy1f*pQ-3Al8NycOv1(ydzTSRrYSjgw!VO%Fy%)FFA^jPB3&?*h5}9L93=+W8#z(<$q8JO36m|VWleL}>9;AGzc>HNus&FM! z9p}d?Cc3XYd~}C}Xm+9Dl|5hpqv&7xz9BQ?h-XqJ0%88J-pH|zr9|u($tfgZA`&rWf44G54^AEh6(DwT!gyjFe&HH)2oo|1+mdXwWgDo zvoSIAeuMqVFA-_v3aTHwFHW9m4VOf5Owesrct*8+jC#t+^g3wwS#sNhEDusO*kfQ9 zvIj9Y7|B2Cln8}|Mr@72iJ8*!8jMurxNYqU)eu~|#RgU?PmkrRf0pYs3C>#V6gmbn z0FcWOAd(yk*x2-$<9@qubaa2VXB{Cj68`Jd|8UkX^wMLbpvd;TP)_qX?aO+x#!ZAk z>~-upZ0k6Y*zGVMv@PK_e*}N3k$&w&;semi9rB}U75q^UdUT8nu!${p@ugUzOx(Li zWd3IV1x*5-;oxBaJHd80kzV-#lu9f*#Qv*qn%T|akK$;4gUNf^VZ#Qr{f@u<{+0Zf z2!2#Ov>nKr4=(iimH`g)<86X7kjozy8`~_GV8*u8{x_0Bf`POh^E(hk#iDyC1OvsJ ziwWg9@;6y9%gNupe6Bc4i8hI3&wEj!;Ni1Lo%+;n_rN&tBfdgtl&|q)iq@&a^Y7gD z1V5rPqkcqQjDHgo;~@Xm0zd1e{Eg~7P63gFu5yR;;QvY*_k7gq3}RA24&A##Z%*Cd l`7Z~xOM!nSHSM?Gfp-uSYBL1{)_)UurM}3ERf!k`{vQFf&NKi3 literal 20505 zcmd?Rbx<7L0w>xyK_|g2!6CT23==#^aEIXT?hxE9xVyW1NFW4v2@>4h9o~H3y?6KC z-L2ZUZ(qIIs@MPZRCiC!bf0s6+F_sMB+yX^Q2+oymy#4!1OQkp0DzH2hJ}8@S?OU8 z0P?F+q9V#}8Ar>$PFOpc%+K<*f^{Rb_%S3LYauFM5CZiL>0_l|NiOvcQsD|lb?h~I z${(7DET>oJm~L5DH7rNSEm9ntY!z89*XJB#1}&##)L+}o8OXn0Qd&9iIxBPYJukd3AWfO15my*g9aGa{QS#IiI+Kq!Ha4cF zJ6>x3AWb6{UTSeruU9gQmSlX!$r}(P0+SjEf}A`3*?}|=B#lnp|FsViRdoKQuO{9> z$&i){@4?v8nNH~<;}C@`@J-KVO5Hcs5N=|UyZ40Ge9;Ko^;rtH;LOqv<-$*iyJ%dP zA@2h~X$pH6I^Wi*L<4J4^NuZo9(rPo{0BeRCrODpYT*KNW~?&_!D)z`B!-!|5fd8Y zHF{igDx`r)OoxucY4#puubUMbPeO~ISGxusbj;0LOIdlAm{+|eBDV_Z5~Wo%Z3Nag zf|GtiY%GmSr3>jQ1?KTPR>u6*e;KlWO-?FNrs4}25#-RsJ#U$Z?QD(AeJ@?cwXf3A zuAl1^41#=wrS7-#D9~byBn1|h-a<}zW>+n0SSpq$uwnc@bq*|vs`4)BR`=)9EN=%~ z5d(qRxLP?mZ9N;#zZ>;k*@dU289rAxAvCANw07zytGuqNY(g>sSsMPprpOO=rHUUw z&FdlM#tVr6dC07q&0M}lphEnRC{C8INRUFl$ycci4;Y9u1+;;XzIiTNBW#5{*0ATgaN8-4CazFt@W!wwfM)$jnm_kp%Y?wAv zzi=YR2G4-Y$hRDjUDn_MR#{Q~!XH&z8Jr#;{XQ=J0CI*ht1L_o*;qN>aKOWmLZ9w; zn>l`6zQM)D94$YH?bd8^3MeA_5I9~508WnDUo9u;wetxR9pgf7GApP9L1|@F>BJH- zZ!-frH5BMp?&$xL^&uynp^~s z1)2;_%0#DnERjW~gAIOut}Z%=3O+LkSTbnPm`>ogpJF2vSOfWC1Hg9?3^N3D>`c^W z5E3aOu-a}H35Fq`I_`N_T_=5^^ZfXGg zrV=%`Ca1Nk(uYN!4UvXfi|SZem-`Q8leob;a`Lo@Ak@}Oo2-d4^BkOg*s9XeAAO`h zIr)hKKEzDC85rU)=$@Jw?gPks#6KFhHuA!f&Zx4iwJnGzMVyMnEbkT5JDu;nV}c+@ zecMc7V|^{4cp$&9Op1z~$Q2^?UM^S4Tr8@Ra-YLYnJy~#EuBS$F$W+y#Q2lZy2+tY z+VmV-)od@9j6QBj-7+rZD3LHo+S2K@ic5qh8t`>iQwavW$RTQUbrWYcjjkgVj*KIr ztCq4m+YoVNRn410=HoN)8p4k8K#WWls2DKd4}#Egru=h=W2eC<}{=8c90R zm?9z(Btk#8&jJT(&D=V5qc^@v7fKgu5@PC#I-cxKpkA}W9UoAzW%oQWzCB=}ebfJs`F?;_*sNbO9u_M;Zz2%Ql z&E0L_qUeH9_2XTC*}~Xw%BZ?`St?IMBlv)JYsvjx;y1JzK5JJCOJOb@f{f`lZ*H{N zmA89oTj7dWW#!5Qgjg?%AWcyg-XtcnLpB<;n3fga%w)DIIHJ_wi=K0`H}4GU=N`Xc zqqbH)I8o6Bl{HK%kBJxkCf>2Uv}aeuhp?kblqYdO&n5bH%rVrLpY$i<60T81#&~!= zD*&&G52?wl`+ZuUHv>zpUuPRvNgbc15&5VgJ3*!LhbWW%ji8RPJ>=b?ua4d^@U?m1 zrmNKAIYnhv7rtI{!ACU`k!yoflNDmTFSsl+(S?$$tv1e4bJ@F%UH87{zxj_vLgbx& z8aG0SLX%V%_o|w*U`VCznyLe=5Ea z^Q`?C3ooXob7I(Priv5u3$4$bW7*7a!nJ#U&3fr>iJ}qtkJmoEZG1;GRqlNEL6?`X zdu{uIimmv-dc{fI6~`D%5B7i)TxBDimi)eI(Y0#KLRj|%*3>lqSH;(WihhNi+6?za zTAf551tE`tQyXjs7{?+iWZ0r)MeR7ApXhohSQm3fMV0g95o-d;*H;RtAFQrx!z|7B z=UaTOmJ@~d3sy|5u~k|Q2AI>fbZ+@=hy4py+_FZwycmz&oIXpntK&mbLQ>YBo2?Te zzU7Or=iN3Vp3)gN1x^=^B-uVrX`QKdX4rx*b`2I%ZANqN-+oF>d)M(*<&1_oZI*$4 zsq*sKj$+Dr#9_V3>84pg_<{KtCET`c_m)j6LFcIGzWNu*SSus5`yXw2-Ph4{4&-Sd2?jutA|ug|zQj~e*Ie1yC;m9H=XWNLnb{5- zCuID=*($M}0nwFj`Sj55yIx}{RoA<1%~ybHABCF`QBvaU-kEh%*2|Po7zY>XW>KlT zFur>BAlQ$F;A2^7$_Hm;E-%!+)40>u6EkWbAc!ZYH~c(X{^EQvP6La7$aAy!c8|Wg zQ#qD1N-(DoF2S&r6noa>1^;ci!FPV}`5gbsbCS7Z67poPWwzqZtF_VI1gzXyB5U`9 zYdmH=xX^Q|`@CVUCd;yb)1l2pGjl}1h((e0a%n5R=^biKCkMq$g-ifioWoq&8gckV z6oZ)y-e8|OKoFS+US8QcmaJiP_wA64nJpZM^e!|SP{iQWUy%Y2)Zn1n$c5Vn6co~IsKUE z==1#tu6V{^N#;gp$I$>v9OJ^X9ihilhwD+b?85l#qwx(m=v0EzW2->V@ZOed+(pQ3 z^ZSwA~=D?A6zU!;p^Q2Sc(3N>rw$Ol5~9n-y0cHz=B(Y_vVBlY}A7Bo7%A z66O2$O%TRUe#ys|2Sr(T`*gBm%Zd6F03GezKcr{KRw+Eh-Son|ky#eCxsn(dM#@ff zOq#OepN4A{gpEt!bqF3cIZtY(apXxzcGC{YLET&P2@5THk9?{CqIYsgAHiW^J3rnw zk<-m3!2bC$dFMM8FFU)V!G33dNrT02oca?p(7T%?ersDOB7pYU-D z$IC0rOJ?@2T!wsh;C|nC?_$_ZpMLLyt-=Qq0{c;pMZ!djz2Awpoi)O~4vXjlb(<5y zk9*H*q>g>#xKRL_@9|Fl>o4Rqhw!0Lu!E9GSaA%F#PIxnj?(u-E6nfHZvoEzkN}ac z7eO_#@s-0fE?)FezRdipv{X$u(eBT!c{_>nE4Q~1X1hvFAxwlb8~C^T-%Zy*Fn+^D zQ$cp7#KBr`Hz{st?bj{)dfiive0^ImQ*v!2#&j_1j3`3~oO0{4k#YdQhl-Jt78&icrMAiFIeaoL#Z-Q$C|CK|#VmA>-ncVk+Z}(EK6Tit z=R04nj4O3fM|M7ghv(Hr?=_pYqxbvDX><5&>~>&TJ|KxBV@I8?h+|A-3k0DVyN0B19qxcx=mw&(96p+ z?|_7kVhX7Tjd0oD#6;&yZv)-*F7~2V$0af&6OCosUM^?07XyH^RT`_UwV@GjfaRBu zL*e!MGOKL0w{(JId(|E;9@1{RlJ7nJe1m2jLJ*N^JPC=jZzx=^#tNscQ`!rj=s8N| zuMInnkXvNDlKOV?vUAb7P4TCzs2*f6!>+|?fHor@x^<;WSQ?3QhGIGX9w#VpoMfB4 zHbpt#kS94`2p=ZYzDx5%Yb_akEm*d-sx52F5Mb?M{3iC^gKrECzr+2w_e|cfPH=_Z z)3`k4<&gX3`PuWt+wSo)5&7z|eC5HGzjR#U<=Gyec|;7D-%;l)n%;?hZ`3w!{G)yD zl|zur7`v)@`I_iZSH{syOjTNURS~&~;8p4NEns9qk3FW@YzhO6SWP$Uax9D~8sXMk zH*)P@AO!&C=XomA)#{briAP73`vXfn@de(c1`)Lvc}J%&^(OIUI*Qh##x~IDWV1bj zu~_rSch2gq-%`h888=sHJ+P|VlIWNazh5~d!P)u!(^;flUgLT7L(t{$cUhvt_H1l8 z@EYO}SJQR?d)1}P9hb&T@S=pG*UejU1GGlm_L-_V2Z&AX;Aie~tVosD=MIdf)pYvq z{svB}7f({w;#v^S7J^DIN}eXO1_bJMxt(T?`JsyIlFHcSUg@i!1)+QB1`Hb7T6cOcqb`Nahyh-U zjrXA3`LBX{jlGa8!gf7P71r`v|8bd~zs@OjamPYq%6&C)P}z>KSh`Yrfb=VaX1YC_ zvm!H_ALmPB8=aa}#HeO|pRJ)-1ROPzhgIP~ldZe0r^Vv%Prt~Dg{}Tmi3pTvRYt-u zelcheRAraz4)n`hcmIJ}9!bhKk6ES-pN&mT|4C5(M&5t(6a8i=C?_Bw=Ryp|QDHB7fqJ35g8wJ3Kt>=;(kV`zRvrNe;OaVewO+=)S;>mZT(H z;wA`ch$#7cCZ?bBZcG2vG@@0>{+2fWL+AK^XQyDy6$Z=9*49+xy7oyNbqoWj5XmQxqscs5<$+@M{ORPfND4P8FIxG z$Oc`OsqZMI;wj(9Noq4Ci<0+bAwkUi)mtuz8HVT*2m86Wjwz5KrOHhW4a2Tv$YdN= zYt$0|l6i0gmzI|LU5b#%8UV(nO#nEwLvu&laRWh6e}9qti;kg!{-N|R{M-x;B9z^t z3fHIFD*E}!DovK_opRy=EW08J1ewt}f|VDxpZJfR(`K>R`~goejW<*WU`M_2iQWth zWpNRi)~U1;zKvt}L|`?`R%&K51SOySy#|MlGDb_fk_?-*1cM)y=~Sf53rm^4t@w%| zw^k+=LTO3ClJXcvl&}3rWAOQ#L`W{(d+up2#}Ag`^Wq0x=aX*|p-1r4eJ!t6COBA{ zbx0iCy#JhC_9%JkGu1<}Rpx!Q^eNz{v`(0`O5UPtO)~YOSmt{lsTN5eU-E zNiuK%f3X>;!9QTpfe(NL;99-jQYTH=u4W&UwPcYF>I5*E6 zf;2hNdnm*${kV9bLeWqWP6oB5BRl|x_o`2)cWue=_-)nA3B5l$5%vxHLU}p8pGzib zji!x|ilBOvT-QoYkr+U(A(mJ)x_d3bp$ULcoIIkG(MVO*_EE|Op2vNxDd|8QVxfSa zYC6$00CX&F71Qkx8W{jNU+?L}4=&+vhI#?mp06q_*g)t^8YEy*mK(hKXG?L2H9(ykW=7=(9c^%e0uwR8T`H<0cqn)_%po`Kw?p)Xf1V?Z zL7b$F=)kn`17oyDI^B8|CcsGV_ety42M}`;T3e=U&{UeAogU`$XW%E?=M z@bt$YlXznt1|49F1~M3}P@$it&myZ6M_Pv~z0D>W8d#a_J{s zj8E7>{)MSHCI;rT%dm>2@{^>Yf0~1iv*1uaVBn?Y7oo_3V34Rv<`&HZCjgE#Js95d z@FZ1m8Mm<3AJ;j+VAsUq?6`T8Ca8LV(FYii$wzf9E&Uq#rS$~_aWrF%Rt*cwshrJj zXcxhybwa%GDdd@mi0ms5c6Sz%L7QIV{%O5|7aMcZZ+t`J>A zEWZLA&GJUHZbvw>hFylG6LX=@7horLMHJS zmeCodm^d>IzB6g)pi#rMarkSUI6op=US77GtI9l~13}E@zsq6->w5{kbK!>unqmDYlfx2wJcPu|5V2RZ><<329Iyg z-N*kDwNULaW$s{$N3K-4Ou4N8v?s#M22F5v^5AM6j%nh1$N;PV z^|ed%h7%u&2o>EGYJg!BXDNOW>AZA1Cnm|9idXfrVB0iCs4G2D0nNCYn zbGscB_%i@{_UNcwm?+zdN>0Bd^e-4K$wk0OFf^E713SLjnH-0Hf&W{HzjR!v#*-zX4X%z?z{9h?{n|-ShB> z2BX=2k;>vZy71G$0nXh<#f0zn=AD+7?#r&N3!ZF|NbZz(+s1*tYRjMfHjY+WS*D+y zbA&@5l~MjyvG76#>JV4VKJ8fqVESBZ41FB5?m`COW4_WKDdwSw}W=QODGTr+8qW;HDY>)ifcaKP2Ku1vVxl847)-P4nWB3nveQ zX6|pzBjo5gSg3I_>Nrg6ztc9usq0%eXUMJPdp1O^M)Yn-SLJ*mD?2Hk#@FSxSPf}y z`GaXwx6kz$m$!HBUjK<6&)f{=Z{D$!g{S(LE`3e_{1TKv3a>J{1MGV6Uv&34qdZORi zi&?O7hG}gz>yNow3{Qg7zMZ+gVfQWQa=uklSk8qLj*l+eI1Va%vA@<>^nX`*?7rf3 zJ6tuF-R*R}8I`5wI*_?i?Y1N4_F@{c(#nUdhWQd_s-<&uJQEh<-CKyo|L5*d^|4-U zrNwS_EH%N`Q-4SP&wU&R3F-cQ`Hv7s-R3QhqbE#VKi}v4i^Y8m`6{dn+N==R%-@P+ zcyN9TpQv2t5EsA{^5=3$2a(j6);=e(9@D+JA_~}IFu*4#mBPBw;UGg&q8+^8af1Nw z=v3!{Dy2xmN*2x-_r{A;{{AtXLtdXtU++ud)Pon*mnqa#9AWnl$&7T~534l3O;S$F zzNAL>~cjjqpu@e2|Apb?f>EQOv7i}xD6rIoaZ1l|Wj>_5B_w*)&-s$@uT=Z-; z3^18nJTp^R!e1dwD*MOh=PIxK!T!lX%v{&ez0mJXD?W-%uNRu1**21kmrror)yq0x zH|O8Y*A=fll!twJxnD!FeJa&H8+DyLcsYA?_Nx}=y^0tQe&_4^qv@r}*Hmj^Uv1^_ z>8l|eKBMfD9IOAb=9-N_$0(=%ee|a`wx0xO)r_w7Pr`*_FrwTV zkHfTy;^5H!lE&M2nL@VwC;Rcwx9yWN@Zj9_%x1@`ok;hm1sc36fx_E#9d~))o5l9G zs;TNH(}OF;Z5hYiS6AsP$tJL1pNXmyyoHxDr+&Sz)YO)&u$qqSWM73kz`JF(Fe?$Mn*&t5L_eglx|(dm%b zcFw}_XJ?$wa=TgLm;Rd<)Y4;`9v0VC0r#6<( z0eadRYSiAexPc#|9TE+9vtbo-8hIMr3Q05#Sa^$MPqn5|hA34Z?>)xmc-_lG#_abF znpqC|tLy}q;L073v+33FHoxs@&E@WB;#H{bL@`jS?G(E@iy7Jp^YXov-JcvlDP@I^ zbN0tHGiFyBI-7`f39&2Ty9?Ks+)r&62u15bvIqTH5#3#X96N6!;1ZL?8MT}{kpO_r zL3IZJzRCLDWxuS9tplW!Pq)l}-V;wj{v=Rvw-^@)-@g_ZsQnPX36N4E`F!heIb9K6 zyzZxIrg=4C9tt0gkI6MLgHf-Yv1;sp;emSf^G)&(#d0Ur7>y8G2G{AY3Qz+u%bDLQ z@#n7Rb?;rk_s_iQbqZ>2|&4 zyU;k08Vj3yK6)I(=*%UWq49%)Oo5%p5Wz9wX$T(p=P$j91TkO3MHVNrI38c8jr#S2 zbiuetj@|tZDwc#y!))SF$8mKcRrQRSLCQ{qFS8n!Whp5T7JLj%Bf|jyoRYX5oXJZc z)OWPimS`3?Lnd{if!j0jveAFL)cjDLso;TFzGBopuXzX4HP?(6_|_=@xKo!J&WNe1 zt`iH_-RX?}xrEt)aS85@NcF?$w%0AK6Y6Jl01&NqMc>5Rj0`Wkq{$lgWI@WZW1d8! zk6;IfVoH2Gv~k+}p6g$I@*S(ZaA8K#x^(^N#rgK>La=R8p-(t9d1cYP5-DqpfN$SS zEo0c%Et1ypYG2{qi;`3{Wq;Pv@~rEh6R*1??zxvmBw-;9r^m()`&rpnC-sCD?L$YS z;b%0BuK>_MnZ>YG;f%W0YK6%gXE^|X2L%RZQ-Cxpplj#?a!})M;o$x<$=la0H6YvDQT2 zjDE8>H&T4?;R%476E^qgW~}y7I}c%@{yl{3;4GxwzI4V3APdsS2M624v>e~c7K^}Wo-9VZYWwuS~PgEe|$Os0CKIa{`dnUH zvhI|gzu40xbz1DW()+XtVttNsQTy|J^D;Js*X4N5j1#gF{e1i6`{#Mc=hx_>hUOWn zEC#UIeS06r-~X~-{pYD%*Nt3H^WGH4mrmB68FQPL?PFK_!{!U`*?BfsWL^Hk3Wxc^GcG)-}y0-FJWreKqsa24~>TuKDW-@a++Nc zDNTX>7LSbx*UcSSKihDSHjUhmh?x&L{Oyy1v(nv|Njo)1LE{?Dg$^v_BLOt3!8*fa z>r6+qx`#&Az_E(P>p{Gx4uVYi53sU!6ucQJG;?Z;c@Q&e(sz&nlgF(lL-JdvmzO(T zju!5!U~|ttJIMIy<7bbBEMstR{{vP3_)A%cLNfhDQ)9Etm$jqAl&n}fJTgKh<*;rI zlGgdJDu&hO8Wl3*C#by)^@)=tDH$0Vd8~p=5=F@sN|m7)bq(qbW2Y6Jy|6=&(R==% zyTkueN7-xezM!GGxt<{cngPLO3lmk;){fLe^4kWe`+GZdnfvXf3l$3$*IZ%qg3Nd6 z5ju6N|K)9uzxnTwH$*B9s=*Y9lH0dxzX^l)d~2rq@5oz$^uH=FW?|5u2>zD<14^q{ zTGGyl{ZNno59A$zEZ3LI>o?&4N%3FEJM_OGZ>*mT6#rowBaiSwS8sx`Gf3Xnnnyy< z_J(P&H7YE41wG)ZS)$FPyXs7~J`%wJ8(HuV3$KYk$R$+? z8MCVLhpVS5DlFi~FnGB=TbJ>BMFFD2z3dx00w%cd#Ln+)*3@34hgb7Q>Cqc%%Osr;>e7YU-xZVsFPr6iEl5}I9=KVLPlO1p|64m5 z0B2k^E{wVaJ@}KVnMrdIG&A8*Eh2$8F|Cs}=HL`^W-GX?TDUtJPJ-8#$CH|M=d&^6 zm=~>S7M_~#^TAg7Tq!pKR73a+L&gW@S#V$8$L}F(S|T-NO;;KT3s^=jKKoyLiT;X3AYeK8HYWFvWg1`UU4NykA^8o#JP`$^ zJiM-@zF|Jz-Kr$P9MOb;ewEF8u3IAK5@Yw6bfl&yjy=}uS_M@7P<<(keeRvdvEkpZ z4o+Q1e3GtvNrKL?wpZ0WO^)t|L*+?D?cw2gQHm{_-ByD902%qID4NqFf#IAlJZSGr@_Jl@Nghn>7~s4&HnNmuks@cqcUeC~KV|bjfAb*F>=U zToCGVSDHwSI##Kvfmfp9_z>Y}gvyUJ424g%*S=YMKAn`OC(R}IVp&xUOS`3n&C1AY ztK75sm89!zyD5>4gg$5sIZmmi4Hg&q2o)tlgFf*6OgK_A#*=Hl5?_uzYy(Tb()^KP zP&egpM;*q9VB71%7FgVUH5I=9<$ZG4I0H02#|6>9n&-@K2VTc0Se^;k>^B2AiFT(>t=b*2z;lNpIjl%Ia#c;iEtg}Alk@VS8 zm!bek1I-hYXuz+}1qM8x$#5x!^5HrwN<_cGUkit z*1#mAo}hN(%MedLrop!w40(=8XM(l!0V_HM*S5ZMcBoJt)v7uHS%K~0Sq8{V78CeN z%rZ~XX2QRWb4UOJK7R(dmf(Oc2~r0(2_e9g-F;~3rkOM>E>cUp0PdS$=yeDZ8z(OX zoDhKqhkJFUDZobS9X5Yk&R*zFpGb86v1wv3Q3^3A?`aJN!aiA*GCBnSMsh9}f&9{{ zH~^SW41<|w5(e>@s)NNw{8xF*jGDc57GKB!tqV_?5oYFn5Lb+z2@CB$G15Uwh#s}d zw&9Ee;HOTBT~beUnX#-9wdaqU1P$Ujx?;|4LSYt*9rMJb`QU7K?lcrAhqAG+t!220 z&LtP=IpcJw9xk+L!+-N}n;lOuYYcnlh+k6ArdGnuW(dF4bZ1_);U!k=er6on9?%Po zv%3hyS`VB3N?C3p7e=coJ)x*U7TDMn{80t>ZhkHd(z&cCB4O0=$E*pL2eVWHQ$5U4 zB1=_rN)c6iGVP!vm=IkYNmDY(%HeRi-Bo-cmB*iYc?Yy(9RKvRCiJ-u03d1$aH-{k zU3Z@mG~-`c*&>6Xk=wOVpPMu2+WEm@vlDJ`c{DP=nx?gISr;z{$K zw24!oqrU2*3NYN}B`0bAVbtaB7A=T-h)s$GfMtqMGoJ(i1Ymr~hDw)O6>Ssbc&d3p)ek~;_TD`CAz6naf_I^HeGA2vZoml%tj z$RI=So}y=`P?Tlhzcq)Kx}(sf+s#vNE*rr{AW~ejwrv_U^Fs4)jeAFo63?Ir7_eSo zCntE@=rsTjE+~#UA@Z_&JEC5?+%UZ8#A(O>w$*#c{?XwB4M>VB<}r8KWqUS-pXg0h zYDF0V9@KFkbDW?>X3g4g&x!%SFiNzyG4q6Q#AA*k@=;Urbjrg#Ba%ZExX#T#v^PBM zwyY@!&jiLU1n>+5T|)3S2@!NPgK$%*7I#wk6OJ8$3KnGniVWoal_NYhslF=Hk#u$- zYaH7+UGAy)c%L0T@xX%4U{)#HA{rBH(gZoHaQ4InK53<$4{MaVKm9JV z@A4u$7}%dv(~|QlJ7dnDtKd3T-+Sj7SF@XbP@Xzw@ly3WF6;eDZQp&`{N_gq;m27*h&=nT-y)OC<0m;&Pm*6muA{oZL= zFn_JzHC;tUg~(vthVXlw^2X{qk``gMgxn=1D*>Oq)wOLK(k7O4D=KnULayI~R~`|q;~H8baNudn33nL4kJQmTb<&L6;!J_dEcZ@aKxpcv9M>;jB4%{e zOeMZ3O_r|S_0fDbq2bUh%J_41YAv5-rVTwSMr?y?lizE3nSOMtJWqj_9X6z*%{ z$~3m{BI=ZADq0U#Z_Ukx!Iyj2CVFpH{LRIxnGoc@qQkJ}G_AN%WXwHmm&Dg;YPWiJ zgDDot%^qD5DN>gn2R1z}`>y-)9Qrc_#!Sl94Uu4&lsz}^TF(yz==ca z*MC|7ShfM<8UN-1LJbeQ{piMxJ3 zfftSV{ufWIX@vUSJv}|!+uKmT8y9M2d>%53`wk@@(5v*@^JPYphTc^n%AKOR5|5R+;nX? zmDmHFk6)u6=sU_W~K(G00WUWpfwr9C_U| z(I&5!r%0<@m{>$X(f#;$?jMtpiF=mIG3L?4V1!yFY=*lmmm-m>E#NH%a4R0L4x?h; z+OzOW+~naDl!hOzI)d>(&%+A*H0a?A_$_N47u`z1v0a}|oQvZ5!xIhX6_;kDNyPNl zxMD^A!XTX$dZRQ7Pt43`Rt4w&vVx5UU0bfUQj31Fky8>Z_{w_TOEy^W>JOpf#-B#T zI=EYxzU}53ms48YL$eim4!z{~yHV%dwq9pT>0n?Kf zBod*SyP4>BHl&)G*2V1$9*BOFIQ(2%U+H_pxS;5za>OGX^%4ziQq&=7GP^ke`0IJf zK8f-MzJ7Lf!itGUO#_Se(DDmB*{DRA210Iwa zIW;D}EYGRf3Kx^?vdr_N+@RqIfGA3zs%;4u<~COf6(mF~Tt5y>S-B;*nOIJWQ&WnT zvT0?i)+BpKT)l5?`rH66*QW(QLmZl^ok{2cNyyD-U$u)1L;k{s3W*&V00t zvyNP7m;dNtee^p~iYO{H*D_M^(Peq}3_JbChf*kY?@~o&G&II zwU@?#0(ZO2OHp2~rn!b=|DQ`0O81A{3q0%Gtr?_gUBlYz*{JQ^PxJx)N{mgTG{d$> zmzuf_HoKKir1+t5m&+BEFKpkj+g}Wdbzbwk++Y7fnllC+Iown@<2N6euR?j*9?TID zzaXyjkF3LQXJf?L=QnKL1mNm)ouaw!)%)zh50*BI(R%W29(DPrdJQ@{y58U;-kR3f z&i(z=;}Gb8FHaP7_>)A3?KD4yziJ4?#m-?Bd@X|jwH<+Bw>m;hh@g$Mbl9A6mN5By z)~>spTrNfZ>PokUyEPS_?8SHQr)4hoQP201bv?KCezn&3m@zob_6v8GUm}=ak6Q|= zjcSu+JzSTMDJqSrUaCVqQz%=qzK&U|rK9eEqx9{(II>OUG7Te@?YMsLoCP|T5#W7o z(K(USY~y?8!0Jb(0 zq*4#QNj}n5Vqxjywjr;3YO*LB$WfukP7Bx6wPdC11Hj1|j56OUl<2W7GJ{mqN74d| zz5m#9tEU;HJ#AqkMSSDjRrxT@SKpnpke48rKgzLxr{)sceS0cA8jM&s(DkRHxVdV? z=d>;bAI<0SfIZGsR{_sR){xt5;0H8_fc1#m_&xsI1kQRVK!RxrL*fL+Z``*UbWEik z^N*zN*sDA$4ZF4Dg7^)WhprzzAK`%5DsRJNF%)1AoA*&aUJ?nvg$6hcTRg#(@E;r^ z)=g{77=?ceK=HY+Z$kY5r-kr&mK!|0|8P-=JePSL=TKO5T=G=??wWqfvmNHR*p0k0 zIiD%P3RXl9&rXR9pXuh5t%)krsWvw0M2>E}t2qK5!u_*C1@@4nq}RkEM;~nCHibgw z4;`lBz??-BE{%fzLrp$)(>eqkF15^f#H!ymb@&Iw{ZQs)`}WH7dm>`yihd(qM#yyj zkDwf9uKw|1$w*9(OqWiwb+2j&UmwKWq<%L7b8MLyKJ;4DF& z+-($tX>_~@0C}ovb$PXg)pkQqV5avUZsKdn4ok#)feM+ClF%r ziobd{i-l;J@De++6O^-EGGUUN%Y{qCz4Cvnze!8pLpwamnD&K~G9?rAS!U@KD?q0I z7zTz1pbanM^5N|?NU>OIha4H#RYVoiontre!(_AGlib4IO2)%_zTS@u{_F(7)C8{i z9|*p#+uCli@tv207wbdsvXBk!a_mBa0tM-q(~EhdM{t%JYrXb<5&|L{pU{8hD%+gt8n4C9>56zWjU^ zM6Fh9>3VRcG8S} zlS_-?D)*sV$bZKzYsWnc6_L<-6et~+Ik3su#e4VeWdx6x`SHwmvEK0L8=k4p6Z1*; z&2x8_0G_n3xXyK_8o}C9wY=BQjYbtS?T<}ktgiou1cSi_e;glHOXWFahfugGxR2Fe zp9(J^!CKHOVRdRh^bmLo$MVv1Rtsy1!GVJt)b zpW)A1Wc7r(WiS$bqpD}Gs^xpvbJ*AhZOih~cv!zlBksi`&MiV+;EM@IlIDka%X0Bh zBOK0caA9LxQO+ni9EeA)(Z)A2cUhs)q`z3DUPt73ER<3GlT|)Low0veV1aCGY*6Y$ zV1nDNjmU@#HMZ27Z8Bx39b2`Jj*ceGoYv7nnhtgK^%v*o&_lUwmUzw?urJkr5S)iW zBW52d-j|F=Gw9zNoc~eh{NLS?*U0_~ z&5$J-Cr{ouO8%W~^Kue^n4v&>q1#s;ywOT@iFAqKlmmB6rih~X6UWCk)pPU-15p0C z(@q>XPX1Sn?B7FZLy=_AFtSvb=(}0qLl*dnJcU>ZmuLGlIG;jT?1yfD?KiJkc9eG|?1{-` z*kx}rd$!kDj6o1~l#`tlHZt-^9gwpc{Su}RC8{!FdZP?o+F~8hA|6qi#WBrMvWI`r zpdLB;CHSeXwF;K3!3pZH&PGn5hP6bMc}oafA>F7X9Y}v1l8x$F^MN_xH(+2^fu{8) z9X4LS<8I)!s6wY=zSZ+{^~ndL7xFeex1&L{kZyv&>Nt0zF1Ei9cXz}XO;$m% zQK5Q$86CBd9U4l012yNSD3;^(;bF$NuR$LDwTNl~LHbA0MaV$lzU(%2-Qe1_haiUF z9@o2y9e{MRZXOn42K{aIP!)Q6`dzN70gPuOV@sdc@X=LUMYx@HqaY|iortIipMbN2 zK2Am#gpSzS%A*Y}^ukJ%7sb%hvf`IojohO++v*Oz78pwx7muK@Fh=lRYM!ACqfaS!(T2@3iDN2;Pqr z8Ssh?_<}SRoA>`w*Zd#drVYy26xR9jJ&%0-j(O5%d~4jRO}V9pNJM!acv1ww&n^~D zQv^ygv{sIvW6i2nk(=@0(y+1a^MB zsB!Wj_RRNMKatqNOh$Be;Ej)l_gJu5EalZ4e+(Otifn(6eP4$YI z+YqqZ%G=*jgJoAfXjm?-e42MMwo^Q~US?7E^(?SVqKE9(LVNd4uk@37_1$`(o)0>{ z+LO%x8vgUA-KOmYl-{|GSAeYLTT=&p-N)at0r}mD4a|9I6>)i^&3^ToKc5sWtk9r| zbZD|=T}UO&W~HYMyuK-6*0p9f6HgteV*)pyY0~O8J?RviGPojwovCqxPtys!1`79JhDqof0`Nqx2l2ul%8_N^6Aa(KajVkO z*|?(dsH}d@_PUPt9A8t))H}LeL(D6jacL`udV7+JwTAU#t>nMM!vD|jru+E1De7}5 zmm5Qsggwsw%VhPpMp8v-w8bbkyeIus{xNrS9CWJpylvi34bQn}k`I znM!PL-0^Bjq8MSXN{8rT)@C?Ao5_P|^Pz$w7zyea7XZ+FkL;fA;{m<)E)wSyUAU2YdO&9|`-A0b( z#O~+3ouea<^R@tzl^OVyTR=axWlmFPb_7nGgeM)d~f{hrO}q+ z6#m{4j&e(3ik=?k9{j~DPYCk?nb`QjdHcN3liT3!*xWCE_#~aJ6N*ytB?UQvoJeN7 z_BhS56|r?f-RtQqldRNdfSIcOh1w?eKqeu)5N>5{Smsz%Yz|bkeTDSgqQx1K9pUxW z6ABw$cRf*L5yN(CiJWInC=JJ2LYth*59_MkO@$OVcu48-)w4D;9J)h2H@Tg78}?u@ z*tgWYzXm^N2t%D6y)~*KD~+*ImC&z5uWEi>Ss~kGMH1|!ke9PNmsBmX)OOs%8bF%t z@7*u1@3rY$9?n##Y2}gt&G{k2gf=}_TBXLUnF#eb`J)3*b)@tOSD>=6O@K}9Li#Zk zeW2K5>X6KWda0t_qH3~5j#vvU#k79og2aB;?Ng)SEB22w-1$z#@$=OG^OOz-z@ zW|f*DV-p4A7X8q-HeneyV+2Z?PQV9Ko{A`tZ^wL7M$hr+6$Z#(U)*(c_WpRHV`l5| zNb_^Tt7rFTFCTfh1JG2Fm!5tlV;xBJbg{JlIojg%6 z=6lw%nl57EY0FWatprQ6s5kSl12G#R&z&m^l%E}CrgPzEk-moh#eSgCC^{F zWg`jXIp0#uAGoG)!#=C`ENU2(0~z)G16LYO{?5Fkex) zn7C*i@W8jBcPuBrQ046-qOTGFWWB%}^VPwiu*kZ5Ms+|NRD`zSuebKoXSqSseXyp| zh4(|1%`b7+Uy(+nd-HeTO;63Gy8O0uF_zFwIecy}EB1`Q@k}t%Cd2su(ao-1+lJZX zxzEm@XZ|=NIjyEKxfkc3BOO|bT@YW}nsUn4`;->XpBROvxj9XA-D#v$GEnuq4Wfml zp`WILxVcTp++;JZ1Aqpz|1h20$qTwy=(6*<}xHJ(|w>C?sR6(ZWh-TlixE{B^_0NVi1%j_T=H35p>e!^*4X!ETslTCfbu63I z=g}vV6s9N%KBIOJ3D^bnX#=EslE@Vg%Ex$6B8De8oHjxtNx~No!QCNjvMEAE_EX92 zX#tDLoD>QJu6nIPw^c>?oic*{&bvot5lnK+8XBzC+L2_g(Gw1b!)CLY%;%3HN13gz zifU4#i6c&XC?P>X&3=X!ed}vY9WstGR4MRB9UM^w&bYY-gF{9bxsp$J|I$G>wo&1u zE6uJrIHj)t=GtbE3JhEnlcD8&c4Wcl7;z&zPl9`*s;;hYVva?q5C{YxYTXH?_>lz! zxB-QrJexWLLH|lLHc$LehSpI^VUJ${13Giyn3aP9u_!*ktHhn2g&*B}Q4@6g*X6V# z#^XT*_10%SU8w_y6ZM@3H50xuRDdG@-!A}SGzcsKf;~6s$u(Kns~m2ryfGV``~wcy LAF`uid@ue1$?cJO diff --git a/performance/duration-test.yaml b/performance/duration-test.yaml new file mode 100644 index 00000000000..8a50e0de3b5 --- /dev/null +++ b/performance/duration-test.yaml @@ -0,0 +1,82 @@ +# Possible values: cassandra or dse +server_type: cassandra +# Server version (e.g. 3.11.7 or 6.8.8) +server_version: 3.11.7 +# The driver Git revision to checkout and build (can be a branch name, a tag name or a commit SHA) +driver_rev: 4.x +# A distinctive driver label to use, for reporting purposes (will appear in Graphite metric names) +driver_label: 4.10.0 +# The IP of a running Graphite server, see graphite-setup.yaml +graphite_host: 1.2.3.4 +# How long to run the duration test, default: 2 days +duration: 2d +# Cloud-specific settings +cloud_provider: nebula +cloud_tenant: drivers-automation +instance_type: m4.4xlarge + +--- + +ensemble: + server: + node.count: 3 + provisioner: + name: ctool + properties: + mark_for_reuse: false + cloud.provider: {{cloud_provider}} + cloud.tenant: {{cloud_tenant}} + cloud.instance.type: {{instance_type}} + configuration_manager: + - name: ctool + properties: + java.version: openjdk8 + product.install.type: tarball + product.type: {{server_type}} + product.version: {{server_version}} + cassandra.yaml: + hinted_handoff_enabled: false + datacenters: + datacenter1: + size: 3 + workload: cassandra + client: + node.count: 1 + provisioner: + name: ctool + properties: + mark_for_reuse: false + cloud.provider: {{cloud_provider}} + cloud.tenant: {{cloud_tenant}} + cloud.instance.type: {{instance_type}} + configuration_manager: + - name: ctool + properties: + java.version: openjdk8 + install.maven: true + - name: java_driver + properties: + oss.git.repository: git@github.com:datastax/java-driver.git + oss.git.branch: {{driver_rev}} + type: FOUR_X_OSS + - name: java_driver_duration_test + properties: + git.branch: java-driver-4.x +workload: + phases: + - run-duration-test: + module: java_driver_duration_test + properties: + is.four: true + duration: {{duration}} + graphite.host: {{graphite_host}} + graphite.prefix: duration-test-java-driver-{{driver_label}}-{{server_type}}-{{server_version}} + kill-nodes: + module: killnode_rhino + properties: + target.strategy: whitelist + target.number_of_nodes: 1 + target.selector: "*:*" + repeat.delay: 120 + repeat.iterations: 0 + graceful: true diff --git a/performance/graphite-setup.yaml b/performance/graphite-setup.yaml index be6a55b7919..04c37aecfd9 100644 --- a/performance/graphite-setup.yaml +++ b/performance/graphite-setup.yaml @@ -1,102 +1,44 @@ -dse_version: 6.0.11 -# Driver branch to use -driver_oss_branch: 4.x -# Driver dse branch to use -driver_dse_branch: 4.x -# Driver version identifier (used as part of graphite prefix) -driver_version: 4.8.0 -# Driver examples branch to use -driver_examples_branch: java-driver-4.x -# How long to run test for -duration: 2d +# How long should the Graphite server be kept alive, default: 15 days +keep_alive: 15d +# Cloud-specific settings +cloud_provider: nebula +cloud_tenant: drivers-automation +instance_type: m4.2xlarge --- ensemble: - observer: + server: node.count: 1 provisioner: name: ctool properties: mark_for_reuse: true - cloud.provider: openstack - cloud.tenant: performance - cloud.instance.type: ms1.small + cluster_ttl: {{keep_alive}} + cloud.provider: {{cloud_provider}} + cloud.tenant: {{cloud_tenant}} + cloud.instance.type: {{instance_type}} configuration_manager: - name: ctool_monitoring properties: graphite.create_server: true - server: - node.count: 3 - provisioner: - name: ctool - properties: - mark_for_reuse: true - cloud.provider: openstack - cloud.tenant: performance - cloud.instance.type: ms1.small - configuration_manager: - - name: ctool - properties: - product.type: dse - product.install.type: tarball - product.version: {{dse_version}} - cassandra.yaml: - hinted_handoff_enabled: false - datacenters: - datacenter1: - size: 3 - workload: cassandra client: node.count: 1 provisioner: name: ctool properties: - mark_for_reuse: true - cloud.provider: openstack - cloud.tenant: performance - cloud.instance.type: ms1.small - configuration_manager: - - name: ctool - properties: - java.version: openjdk8 - install.maven: true - - name: java_driver - properties: - oss.git.repository: git@github.com:datastax/java-driver.git - oss.git.branch: {{driver_oss_branch}} - dse.git.branch: {{driver_dse_branch}} - type: FOUR_X_OSS - - name: java_driver_duration_test - properties: - git.branch: {{driver_examples_branch}} + mark_for_reuse: false + cloud.provider: {{cloud_provider}} + cloud.tenant: {{cloud_tenant}} + cloud.instance.type: {{instance_type}} workload: phases: - upload-dashboards-to-grafana: module: bash properties: script: | - echo "BASH SCRIPT FALLOUT HOST IS..." - echo "${FALLOUT_OBSERVER_NODE0_GRAPHITE_HOST}" - + echo "Graphite server IP: ${FALLOUT_SERVER_NODE0_MONITORING_GRAPHITE_HOST}" git clone git@github.com:riptano/testeng-devtools.git ${FALLOUT_SCRATCH_DIR}/dashboard - curl --user admin:admin -d "@${FALLOUT_SCRATCH_DIR}/dashboard/duration-tests/java/grafana/aggregate.json" -X POST -H "Content-Type: application/json" http://${FALLOUT_OBSERVER_NODE0_MONITORING_GRAPHITE_HOST}:3000/api/dashboards/db/ - curl --user admin:admin -d "@${FALLOUT_SCRATCH_DIR}/dashboard/duration-tests/java/grafana/aggregate4.json" -X POST -H "Content-Type: application/json" http://${FALLOUT_OBSERVER_NODE0_MONITORING_GRAPHITE_HOST}:3000/api/dashboards/db/ - curl --user admin:admin -d "@${FALLOUT_SCRATCH_DIR}/dashboard/duration-tests/java/grafana/focus.json" -X POST -H "Content-Type: application/json" http://${FALLOUT_OBSERVER_NODE0_MONITORING_GRAPHITE_HOST}:3000/api/dashboards/db/ - curl --user admin:admin -d "@${FALLOUT_SCRATCH_DIR}/dashboard/duration-tests/java/grafana/focus4.json" -X POST -H "Content-Type: application/json" http://${FALLOUT_OBSERVER_NODE0_MONITORING_GRAPHITE_HOST}:3000/api/dashboards/db/ + curl --user admin:admin -d "@${FALLOUT_SCRATCH_DIR}/dashboard/duration-tests/java/grafana/aggregate4.json" -X POST -H "Content-Type: application/json" http://${FALLOUT_SERVER_NODE0_MONITORING_GRAPHITE_HOST}:3000/api/dashboards/db/ + curl --user admin:admin -d "@${FALLOUT_SCRATCH_DIR}/dashboard/duration-tests/java/grafana/focus4.json" -X POST -H "Content-Type: application/json" http://${FALLOUT_SERVER_NODE0_MONITORING_GRAPHITE_HOST}:3000/api/dashboards/db/ target.group: client - - run-endurance: - module: java_driver_duration_test - properties: - duration: {{duration}} - is.four: true - graphite.prefix: endurance-test-java-{{driver_version}}-DSE-{{dse_version}} - - kill_nodes: - module: killnode_rhino - properties: - target.strategy: whitelist - target.number_of_nodes: 1 - target.selector: "*:*" - repeat.delay: 120 - repeat.iterations: 0 - graceful: true diff --git a/performance/metrics-dashboards.png b/performance/metrics-dashboards.png deleted file mode 100644 index 6ffb85b9f180c63ee80376283250828ff27c790e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80419 zcmd?RcUV*J)-4Kz-jUuBREqS_q<2)Li!|va^q^EBbfgz6(yIbW7Z4N(AWfPyDbh)# z*H8llI4k(u``h>2bH8)$bN{?NPsk!!b*}fFbBr;^B2Hgdi-MGe6bA=~;@(|#LmV6e zI$*him=O4_l@k6K2M1TpMNLiro|+n${!^%vi@PHZ4&O_A8=Gr)1^Is1+S=Is7`V+( z`qbYrHa5}FCiHvjPp{EhkPX3CUB!&y_g8@p_o!_?3@nxh!}|?#Z*qQPeTw%cv#^KGqqaAeMRS zqyNg>0Iwi>pG+V@d=z}2jxGH9n@DGQIF+zwl4nQ^CP{UdLA3z zHj)t@z6Mqmy#6NK){Ptls+3ZF;HC(Qw7CUpx4nqyC{S+zF|}0F6*H?L!d@1~hKC<^ zUtZ=qGBZv3i-}@{PA@NyXD%-LVYm7F4tf=hLj?SF z4R{6Q;r(lE0=hiVzm{<-fbVcrjMVPk1Ky47pE^2vdOJgXj07K?10Rrh-8J*Z!C|!)Xq^jz{3l>9~}7rSzyt_(Z`l6z{B0sTQ)#} z`)UnYU>W)I^^F?jlCV8szE(~EqxUKE9(Dj{GVU` z&l_GH)9gQvDJ}7zhy0Ik{@GGq1bgZK5sJTYzWNjhv?8gz$iHuzBB}Y@E$p3Sb5YlO z2)qNM?CQq^_{|5ru)h>6>p7!fIk5lE z+-$Jie$dX`$BOm!PwQZBh^t(`xzF%#J-VLiAyu+x>o2u9h2r0UwWCHpzqhi5(GNvD zBwp#y70lQ&3>xED9waw!o^Y<3=pS_EPrFIVaw0e%epDd2N0WjGmp#BYDOs$+lX)Zc z1Cu|>_DqKB3%Im6h5N`QaL6O8h*qoHGJ5*m(n@;|EKzTv414WA{XfiL=hru8j zhwK3TC-#AcdEoqRzm($j<1{nwwmoJJGdN+2F1^$Ts`R@GXwon=*=h^vj*;EvQM>s!?!|926S{AFdyeQ5M z@rySnuQh5cmvO*ObOX(}D+XP|A3tb>=0Yoa9%L$m|Lta#Yzydt93&gNCuB|RDRU#oZ@x^XQ22G-LPw$w+~;>M-zXY zO8yg;$I#nvYha{Z(=IrOc`^id)j2;RoM3V$y%sW+hw2QwmtW^G`9p!*@7OwH zY5(w=2%ltC;&GP9Qx+V*rsCpz__ZMVm!hnW5xn2+7gUNeau*f8S{FRx$z4j)^f0mR zcf{;%y>aP+-n3Q=kCtF_VeUP2MwC9joTbL4s3LsRS&HT}dbaFe$ef~seuO`Lo`vFH z&h)jTM0!k0#6%u~l?v}{dMT^*G%;(qQP*nyezvT~FyQyG*_CP^RQ@-_u-r_XlK5v3lP8ZL&r%M8yJ@pmq^@fh2jJJ9(WSTxw^V(GMeE_JUwogU7)+eMH6?5V)|dZGrY{dx z9NrAj(|b+)%eQ19X_pCVI))+NfhpYzcEmJJ+36-vQ2(q(!#|CQ^nu}-o`Zt9zD18Y z&d=o%9(3b%ahgCbyj;3ACee>vnxN%Pxy(Y!8QwcyYQ=dRM@ zu`?G?f8~3lhP#f@jP3j*D)ulHQqr`+fW$pJgR%vB36z=j5t;VsNLuW3!}l~jH&0*n zq=X$MBVG#Gg=kKb84OXQ^%@#K3^C8&YY0tjL5(Duj6>?7-pcahGyLphr<}ZHnJA<)pB`7 z;yzuAJ#TGZd+G~~{0SScok)QSUMUe*t zM!a|<)8mcq%=`x3wie~jH*@kQr^LVM7(mq(l2}x zRu1dC1SyHuL)*Etdg+5`&NRwY=EnrNfz6Wy0%`pVnTrNG=?Ba|vN zd`1~3ju|LcsCj+}PcF(lVTYP>{@YpAM%y}>b-z7KYIsw)519OF`>5CLjCan>`0*U& z-APN&f@^^eX{A-(D`yx1y9^B6J4|Rf)78AFhgDIu=S6IyPoN(>B(}4OlEty4W z2W@zZZlabEoKF`a{f3zTR$K%ekiC?|+FsS*P<}ss@Ym?e5N{$cBoHmiJie*`pQRd@ z_P0;%FyoJdn7cK~NuX*xvIjKg{i`jq8hJ&>Iz(6iut|7Bvb&?D)PCd?ZmdT#J)&NiVh>h%&&vC;-x zI34uy*F@>%r+EI863Fz!AUJq<_XZ)0d~F=xzX$rh z?S}If8^+EfQKcbwA#LDXKjcM0O`Ih5d1Jq9)0{I8B-fEqO=Lt!$o1b64~6;U>c2rV zx89tK=3S<`3&Ht9*q~DMH8K+|sC3_aIwEN^Z*n%&H$F`BVPVhP^xR=X(I;q1iVntp zoBTS)++C2peg-Ov5H_0LeT_RQZST%gpj_{)#l-?C;E1rk4Re2ro@Guwe7*0Qc)7KH zWOOYY+E^4K!DY%+NmM<_y883E!?UBtm$}BPWJPxPWsPo$eb#qD>aM8UI3qN{{EEZs zuKFDgy-|w6UC_2 z>+-oaaRhC022O<@)2#9gY2~FTbA~J81>>I*AN;RA5LM&RZ|nni7wYjnRS*33zgZi* zzt;W)<&7vrKbg+XlmB+t|30`cOAm;m3;8 zN%@LF%$ka~&+l~s#ooy?b91^$sqK-l9&o5~2F2$ibxt71u|q)Rs)(?O*)O<8X?(3~ zRqF{;7o|q{GN+Hf#;1HXgnq+o&*T$@^EnSdPBg!n+oVdMJ7~u+&Q-g895*S)cFl4? z6F&w84hUXThkt2y3t(VPVt_Hvwff(u*a48PE?pp5S@SrWq5beSOUcdiV~Hdj(Xs#s zMyB~YN_YFOQRw~HsUA+8xTV-v|9${hOs2cu)RVH!UW;!a*+sbvF@Z8Q(bEHT2HM*8 z2L9!DE?sW;>Ouc7P1CLG?g&^18gyaNMSG{R7QMbi7(QD=~VPdX)0x4Gar#Mz5Vwa%yJds`?~^5s)3 z(a91q1uz0#T$oRTFJERSMtmUP;2vG^_iKnmND*`HLSty665LX1Ka#UxZa%qr$xd+t zeEb|ZOe)7b+e?yyuWAj<%T(_wzWY~&?R4i$xLJ~tL+#*gF()7Zjkt+`@0Kxw4o<0S z5bv0o67EA5O1H1s7tyfbQ%;t+B+J!XcbfQg*NddO9_ZqeLkn8XAs6_=#^__6dqFvs zSj6R!(p_Z1OUD^p8yHnEmAB>XjjiKpt6|<@WzGFuC}sBhCxMhS%QeWZiTmcQ5&vsi zE7}wX)O{t>F31UGEo1r1!CiBJ1BI925EfI2hptL!aZtwA^slewYbf)Sd4=1(;UB4)(%(3e<)!FOFNzUO!t-p9q~u z*3UwbbW&HMd(N5fEcT;k+5~@G;WzIvW^nxST-ZJza`o3pL91u$HHFuZi!cdRhpjlp zWvvX>GBMFdHsLhGBM&YmM~Ef97k@mq_@01bS<4Hfz40I>Djuwv^CAN+IDZ#nP=8wn zfLx=zc!|(2@`_b47fvVW?;l}pr86Sn5DG=+$_HRYZ@8&2VZ@H!VNy7|TLhFg_wexG zO(G6b8vcB2!FX;&Lgn>heVjFbpE#cLAf@MaA|EfvZPbwIe(y)S7Zf|}^y3#cfPO;& ziWL*HV`JiOSwYoav#Y_?y@5t!0tQa+xB}29*EsDXL3MX2Pb+44gl68IefQ%GT9K6B z)VW?wY+@H5*ZUMR{=g;>Qzw%urh_*Ycc#zgF4CoKzZm$Y;jCb1&gT0Nn8 zDC**;)vm=}Caqyav3loA7a50FfJmPblAo`1KbAo%1eGx9l4943V_`h5XQBz6vy z%o8;4)JpFKx3CTbByka+mZI~07g^zvvt}EHtpTi31B*82Sd=L@V+2W)E_9}dKqO^D zE*ys4-%XWbF;=hR+O@4Ha=n5sbU`bcRvm2hRRQ2?jZjKad%Lw5PR~24PcS4Je(!ti zcj+k~`=1W2;|5JC0Jjw;~5Bbo~FsVpa@>;@%oi6t4o?glsTXr#N^P?WzqT6$h z^4f*tasUkVem?iw~$K9(1k+ZTt)cIMu1?3D*^*|1j}-svVLaSRI2kp+dDIu+n9&SH)WG!g^zpm8czH`cIXmlP#B))ZDCWwOvR>$UaiTuolN>z#ux-O@Su=VDeGcuT$Pc`N2|iO=S^5${QW>{~%Gc2f`%AJ|nf@ z^)FjLTRT+eabMt-UaGiUUs(6W)lFgPtC8w(ojCDA^Ao%46ZIE%R8u2toJnEh5cse_ zEB&p=M;110^-#jTd%z7S<}JrERx&JO#Y0x#9+>Ss+&FQ^@rNd9=}>q@s^yO{OqM9T zN`10(a1g+gH$3KCqqq#IrDJ*wAp8W87vV2QRa9VY}SM{{2)z)lD_qwA*_N5W#zc(RW(IAd*6>Wxu-UhdyT{*0MX z-q+JBB#tuqndZfx`ESZP-+`2ybo8Q!tsmMkme`0#LZhLm8p?J-Yf5dsBtg6>m8t8_ zOpf=#Ef2sUNS)iipnvM&p)q0T@!1$lsz=snI}T(`oRhy<4p3V%QgYegKh_5C)9@ib zcI>Isb2_pu^yKrv3zxFXXpfnov?^ysu2XL05Fe4OCk^RJ6GPWT$*ASJu*Icf(T6%{ zR5oAcf`4$cm8&)*Wx?w_j)cjLU9y~`w0=hMAKFR!&>E&pp4fF-R(W$^mLLc=R@TM> z(ovypF}Qx4iAHGP08j;6oBtB5A(G3ATY&Q|IbrHMxyU`kK|sE;SI~be^;GKtet)oRCVaMKX8E0*kKn)=f|f+9zzL z*h2hL^MwT0W(%SImDcPI2!aFSpXsnsB8TcP^d>q1z-nBf03g`aev6Cd8XNqBuXFVs zrZeRUtqZ$-i>b;vO6uM3Ty4-=pnSLn(r{DUaJvV=kpfL}75y#*KzYim@h>(!a(w?t ztz*tl9kFBd0UKNmgu+!cb>4DhWMcjG%1J&S*V=d;D_1^cF(@CzlD-Pq z-W;N$P`%hJJ>#MPzrzjSQRzoUom$NPtqVRwk1TUhS(w%!HRQe;z*UVg%yS(IZaM-? z02^v=!)|5wE;v2>k+_;(gVr7LD^%$^5$-PJW*efZjf?d7o^n5Mw}18Q{P_j z#v)Eciujk})a5X3(5*oXu8UNx+#8_M`~7~$?0j>HcDK3Qu8Kd3sn@j4VYKSD!eq`H zY44w3k7Y*<+jei|*Q^2pY{sI)mhVMpbokHMk}#p18|E2XKqmk=Hi=xG<{a|ZY8HnIlLH5c2fp~IR%9z?l9e7ltP)a=@-wk>v2%?Oe{GXZ6=0?XL^G)Gx(Q1B5&{_PJ`C`+63;6+Ot6wY;>Rj=BgTpvzC11hs}K4jCx zo@xTWj6cuvWCr)K(yoQxGtW%@GM{<+FN6{?5Io#1V-uFm#FAu_L|5AR8`Dy)q`VQ> zEW05cx%3{;>b-$1i*&9n(og{=dcQNEx_J9*o|nC7lwLd=jfyV0KzM<8idS@DIs}zN z$au&Xtsxtrp+b?xl#3z&o9Yizkru*yK{}XCJO`>mT()cZl6EXFS*qayhCF%Ah0UE^ z5`P)h9x02I?-TK0)t5Z8qqMZ))ii9@cMnO4Z$|6sQj2?#wCT@J=vERfPmHt$1!q-l z^!zz@yv2F4Pcxqb&WL24b=1{Mk-)P@j>^h!=x?{Wej}Z4YsRmv$YaL!%!_8gXT*PwXj8o6(43u9v z4hjcdYyrBvGd&xtQ;8_--_}j6C()K!3WzBWR8WtMAVLKi!eaJr@KBTfQn8(WcgOkW zdC!|fteDNj+Jg~ixBfw34KxWdP}bT+jZs^km5Gq$cWZ3(_WNdvcX@MJgekPXuj|Dy zUr~QwaEn|LO9r)$QI2yQDjP*n`5ziUq-hi*fd2}=4~5k+QrLm|Y9}47SvVgdo#Rrr9oBTJdLEq z=eShx+pJOxV4O@`ck0niTUN#OTF)?gU1}lMvr1i>lC|K`wkv{J^Gm`~4PKMk%o!?6 zK>@^{f#TgdBt(yjACJX`LZ;L)MEaYU?cIQZ-9a?%{;w(Wlm$6j=1?SnTCY;Htt3&} z@aPh;Pdh6T5&(ozUa1wMTyw~$!R#L@Bm@YE|DXT~nFdy+-}yh%MGDeo(PUw!J`Y5tJrcms+<2DHKMi1z(ta z0@Pjw1!;{uf$KO?EQ;+$UO=Lbf(0swwxm)T(EByzJb+{5Id<8#M3>O1R;2GN<{TB^ z`)LpE#{qgZF>4#f(}y0eM)ow+BWXwf_7~wpT9_&~!sO2fJRt8nVf>b3mjCIpcoBxM zr#M0+%2h_fo{FYn=YQtbH5dyVq*S8|RQUqUW_G&4qLjmlA*}qB6qDqX$0TpxBEiS@ zq9<=GRf@giXw09h_LGFROF}Q8qUg(i$=Q?Nj4F8c!i-P2nrPF7cK**-T>Bp+K;zG; z(Om8aeKC7dY-znarXfg;j&DI>O%cEmVYPSkv4Kt{eZ)mG6t*goj4}&(C~^EikBSFx zCaCN+Hq4?jbCGzud7=Z14*~d#WY6oep?u({-~dSVbg?+dw>qB?g@SVz5mAfx=zi^M zSVB4`F0DGq4F7E6mBl&HwiKCL z%Wo3j#R?-K*oNt#SVHQ;>_>?vGrVXN+h%c>t%GXZ)&N<+m>u}^wr z4DTpx<_Pb0&>NW>SY;m35Nw8D_FgGHkj8nsaVArf3{DR98s?X50wi2ngVjjqt-3Dh zPDPfxi8)!GG&s@pDeiJexfPI>$UQ0+4BjxW2rmGCtM`(d8xtkF@08_Uta0U&m5;bmjXo-;!~!503dg z7v3c_LpW}&W_R{uw82&zD0U$3?N%lhq?;>N{U%VL&E}ui?3^Tz9NVOMmMqZczYL*Y z9>=4|J1mirWv-pVqiqOI4qecKft7|ny{uyv0(!0nMtu+f6Kq!e9$i(go2NCN3hedH z)n_XsYiKbe+m{2-63#6Oa@JiWNFwoJf-AWLoZyqUdPDg2VJH32k?X(+eEb$Gu#}^O zDEOwP6o#TCnG7V~K|pv(L?NN6Cd3SBZHDu^mgOQ=oRWJ86O1^Oy+Nqd61VlPcLuC8k+kx?(n;q9~O_YpG9v^8v&|_2y$-6oK+8`DMPw=)|ksf3;3z ztgHHW*7&c5J4F$yeN`jij55hpe?l+OmbUozPYun;Lh(f8qO|FChbAk)6R|VaOH@%W zuG9{0WbHsgXqE0CL6GsS=v^1~xyiPf{BS4CXE;#%KiAPz3Y`>S2lEvgSW!fHJw%O} zEf4USN4Da!N)D*39F?Nu=g@wghDmc`RvO`TKQSZ)rMp|1ua4xcu`<994n4tH*?ecC zoKB9Kcc94*$VsXMQOR2L_q}Y;Ps$9{ZR#zJ(pDNKngPFRh5lS-iDSy3zY=IBUlovC z*=j4zjpi440hh{i7LfgOE}WPV!gM8{44xF?PvHKIHCwE58t~leuW}mEhT^2Fy@wNU zFDRUpVV%tEDB6LrI$Y9+K_Bo0g^7Gi8yhvcg*T-(mFb?QXxN3X{6ha(=etFt)0sbR zyUu$;CyCY-oampdk%^B=fi?E)&0vovcR0078u(Z+9v8Z{*jviHYd$uo|CQl&XO!|KK1$d--mxKKR& ze_{E-d%osJ!U);S)6+NmwMF_nAwqDq0J`KmbEW^i+vnXz z`>r62CU%fFAJ!zHWL2Y>%yKnBE<^$UrgFX3OcQvRYM^nXrYrUlTX25 zW)b?B;p5>??Jgy`Ibbs6_5He|6P8qZjg z&BaWgSuqp+(LGdA6JMg0MW3M@QTSjfeLl&lNs}7?+!!e`xmpYN8K)Szi826W#frHPQY5pKGGU#D6m)(Po%nn6S;xvz?%L<40y60!~MB z=a`bMXO0pOdwn7z7pFtk&6^Q}W>uzc<#qAz;F}+kd^v+Qs}X1OXCbKPgQ0Cbu9Z(y zbfgA6tAN}o=e$jE6pzI~t&C`{S`*{K6cqcRHvwws+kdN`ink{$(yir*{YyK2R?YWl zm-MfEdNbJNL5C{;NbH|$!99Ppl!LTTKNtXsZ|gaqGcl|_?$wOQZCX6tSgbYzh#s3q z9+a`&8MZdvl3W6S`jT@CFq&Z5eR(B1+T?zi|n+k*d9v*mR>n`J}v9zWyGcE7IABb%=;*LqyD`nPU95;%+!q)w%tM|Gck% zb$6CRQ@^bi+ap0Z8e!iH-v4yFQa~8K%FX}fMdAyFmEeRKMT==*X0P3IQ~zag6mfMw z0ygi1L%xP6vyqNnk=Lo{)g5oJg z!%pZ>E1FGYfJ$O$#ljFH&X&1L_RKdma%6Or4{z};_}1gzqHadRHeMuS?HL5^pok2$ zk-d^$UB7n;>$f=&&Xdn0Aneg*aJJMO7Bj3hOKnKB_l;8szzVuDAC&+WsV1Q7jo(qf zt+*Ljb^4ugpD9-dsBT!Z#SjehXIDcv^ijMrv);{A-cM*gB#s^>JBnRs$056+J0O#I zO4@kT%3h{0Xfd&U0P{6EHOwq*QtZkAM^PL($?ADiQ3Ri|58UFbDprtOXHH#Nm8Xj{JJp?Tti{$AL-$+79S49X?`sCi?dwwV*?jxCdj2 z%r9X4d^Slo^p{jlSGE?F1hW2ncEVD9!1UZFfoufNvQ%C-=eBwh3IXnk|L1Aw>qZqz zjKc|_dCO{H^;=;;zeNVkM@x-c7cmbC?wnM_FWw`U2#Edm|Jh~4B0U?}yN{-gceD`s zx;gSxMSH!$KE<~>%XqV4UsuTOO()zN9YSRz7Y2ldhCr`-OsaKv}He zlH~>-i$T(@4FE}LhhMdZ(KsATvui`jK$jt~ta+Q%4A+9~1isdfbbZF3WX%w6`YSg{ z9)Q>GIR6rH#~UMBVh8i`ldXae#}Yj1&rF~E{0(8WKJPWrCeg62(X^JxGY?&mv$EkO zbi;k-2{=UVHSuQh?7rt!_}H-eDj~tb^Xmth%@=A3m*+d718=+d^P7tU9DGm6T*6{| zsov=OB#kf1jhaM4Dh8ESfLjP@VLdT>4!3#A-AcTz35Ls!3ZZ)HwYwlcsfOteeIR&S01BkFV^2_>Z;>sVQIaZdP`ZmuaO%x=6_P9*)qYWU{ zQW9+dP$9wc$dS;zhg@NiV@Xu>N@lPm`dnA`97`t>>kUSkb24Y32yd=vY&&i04a8*< zXs1b|G%jBC2{ZqAj!ahg*~viC$xigCWqWEPI&fJziRDW6J>>gi&_#MHGum>k?dW~e zTIj{EV#PZ2am(fGD)F%u&}W;ZP&cprUrWH*VU=G@)5401o9_Qh2=2ZTg0J782~knG zh@h+B3bt_s9Nz#AP>3h|b@0-%O%h`&Z@GK8T;KFz^0d$*s6BKyl9Nu0{fUE*9ZN2* z%9O=sbgMTxd_nJqsTB|kGNn`9Z;5)ydR^)_8(=H5+&eae@!f%!{>d%QFB$2(bG;&{ z+MuEPnRYAL{;3eUWT1akNt`!YN;CJLim{qHeR85Td{*3Jn;HHg#?XAQZN%%nqv3~3 z7DvDwU8~mM@$cUIe^!$KhZ9Z37@hWygeIts071Dz7m8PeZz9|NHsDS2Sj%Z}0iDwT ziaa+xsK&fl)r4iLxaSRlk4md!-0;TfhALp&IDo~eZ54n(kjJXSh&y6oGMHGN_!SWh zOsUtVMn}rG{0WiCuq#=jJ)BvP7Z^>PO3jE;6G27z`B6IegXSRg4i)3^#o8R=)9ngD z&zAF}2SwU#$#Po{%Ra9Q5Qu(VTDCxc4E8;gv|~#eujS*L9kNUx27FDL{=%1gO9_^K zzdIZE>RZmsCl`^^)5L|7c>%7JQG`@Vd$D$l&l!Jy52J{?IGt!=kUsxYgt*Um7J7MR zU1p>1<20pD>i3lAt%;ehamsTcscF~)LGll6$@jlZ1#TdGD?=^2%~fEH9!ihoF}v+a zzTr5}L1biXN%QHcq=x}icv@_}?-!}0+Wpv2;fkiF8aw{27oFF%1s9ht4+ldTEE?Q0 ztW9|?+{o{EgJVjnNegQUPUbI@Xb2+edWdf-Q%06lPi0)a8yRse2>VUfX zCz1Um68l=(T1}MB*}y{ww2~}I0ZI%|z@$<8Txobk@A(l-A%-6-hna-7J@HLrAIsyz z&hLaR+mImHL%6Rhjhi^dewu($4r`+czPa_#wHq746(R>_D_O?!8)k!hBO7IPx+}+y z?a)GyGoGsJOQ`s(KrK6X><6Xc{1SMZbj#8}=OYWKqvVDz2f7c`2|wGmm9M$9T&d9Nqolb}38e^Te2OO9crAvM(Q|S5lT$b<8 z-_gb2?%!R8ZP(=97H(R=qjgDy6W4Yr^`*SFS~RW{NVV`ZgY1+cMzlqQI3{kyF&(7i zlf~eW2|rn<0ylKE--26Gna``<;tf<7Lq#&Za_keTXEX8C2=yr~*ZO9~BHFMRBYn{G zPHv~E6us>aAMMp8w$*vuoExrqlx82#+7iU0+bv&pYo=INX}}?D*mvA~dbNl)34Ww0 zaQV}}xdteu$Csp-AHmz71_K%Tf~JC**wk?k2Bha<1Qoa0T;I(J>sXNr+Da0#PwnN3 zwY|N4uvHCrwka7rScAa61^o2RL27wGo0lGS&P&pipEi$Q*uS9(Xd|=IZ#pT5qIBkV zw^-vFcfOT+?~hFTNk>G`Dm^pAot5#Mb6G)1d)C^;hyF5<)n4e^DZlxisS;~e15EJ4 zTu{Fvtheb?r=GVc!y&{-49}QYcgrCpJz3;We!Cpt4mOvad|%(kwu5cMPN2`Y;Nn*4 z3}R=lh)kPMaX9fCRO*IZh(C+uK}g?@T;fV1G=L(ta~zi%khaL7h_EYrn*#i170+e7 z0!Ky;pyWwMiK#iaK~#-NqyoWQR$GBghQVE-nl;`!i?%2H+TK*v`HmqQ{DZ-&V)&og z6#ca!t*ZTRC2<3NNHo5f;@E~^dm#7?szTYf=)?kdw;OkkKJO1Ig`%2P6eBK$bTyRP9^nfOWEt=J)$?p>t zw7)U4e!I?dy?*oaT|S1+ipEXznf(oGBC?LW@@s;y{-pS`Tvmz=DzGV?cut!hs{`;T zKpkq7n>s<@=iKR+diqMsr8;KF#}BCjITr`TXM5Iix#){{b)2Fy#S1jjY&K4y^_JP) zaU^;R8e##%GZL`i$kKPWxJ1giTieVkDM&mi_8FBv_7u2G-yhr$4QQ>az4*5AjG@nD zt|j~Z(Y8T1n`INaQ$#ofQ^-lL#TKF-(!xk^LgqY_N5X!gVsr8cLsv-xH!-z+ZdVz6 zbaY_}8`kJtdS{t)iSr?RZBXl4xPQxvLg%eaPsH>oFzu{i%URxX^?d=)BOu?D)N__D z&{09MnrAy=kmUB#1s!vJjKBpsbg_tW$pSI4PQ?dhd?SM&jQi7^E4rrrKG`(9U*-0i zUXcS(!1ShkrZtq0IqhA+Pb|)kUG%nr5j7%q!fT-c0ABowQjp4BiuBq0 zxHz(Vv+Tkr?XQ$7jWw@M+=4-1UAbw+VnO+{gSWH} zz1#JtwTZgB(Xt;E^{%YM3#<(LJlPT@U2UR%Tnu3wl(c*d)-V*Jiifg3#?DJk^$Ezo z=zgI*+9go}S_yg}2 z4s?wj&KYQN8u#ZYOeYNf4o*(8>izQ}3^kcUNxJ#Gk3&DQGsCNuwnUFFWce|46dHOq zZTBu)X;EwWBqEydPJXPcg?qIIsy^moy>x{$|C~$&Ue(I-Jg_5*8_hzo{}d zIxB0VC#5LQNc&wrO^>CT;G^mKfX>@ii)8h)PMHX}(!2@7>c@O_Y^x}iNpXq8SR1T( zedj{#B4ceK`McP=ca0wwq<6CqRaeldyL`EYV|eqAKNRzFU)gSE2!WAdjHVQdIs(Q( z^xs|)&?Tlwp@lUjQ<+L0GS8Rg7Iy8uh56pHKOzvrV|gFf27wViJfE4H^yzS`mB|u= ztGN{EkYX)$WwwAHgxP8!tbXSGHF1@oTyT&L)4Ukz7#-3BW*B_rT3S|E!PSC!f!B=+wIOe!ZM@8Goo7yG%^GmDxb zHc^hfG0g$Yt-ppK{j{1EcBH}xiJ&99PVqirqnXovi*q^&?~?oBCUhdy4@@50gcCGb z+T@GGWa~%G8C%!8h9B}i;UeTb+12b+n$7SH?{Qjz;KV?6?Md$vR%F{`Ohr@ZrxLKjO>t=b?*(3Y8C^T7!G^x|xLg*N`K z@ z{_`H9{kI%9@`+)>mXUglpKMYj@+7L_qYe?;g4+{f=Sw1?YaUwePq;iAMC51JG%s`4 z$H_ZTF-n;HNw*XQg?a0kPx`0_KE|r3jfvo9nZq|mO>m6;qv~bWaY0dWX$6}>Q==Tl z$6jp+$38)${*6 z_;g%qebFnbQDFb7!J6IYN1N3$854oOCzGwYNzY|YS%V!~;mL8sr}@{l6$sz!(%;!8 zHg_HuFf*wtwLxbppLlB1H1w7f`b&3gzpaEhqTHqLpWk9MDqD$1ra!H0+o3-tIw$;H zti+Qzb-seUJUEVG9L(9$akvqwRUbvuswA;EcER{BuE^OSf zSD0HQvwJeC7jn)0se1}h@!b5S50Rsb$V1_#!P`xw$HK>Qz+mizZujh1o?0aEA8(X% zrj|FHmYOg!W`&0M?L2HocNN`km{7QwM0V;y;lFK5LekSeWX)H2Fuua(_xJ8l!%o-HRgCNVQVy$#jJ$@wf8}TIa2^_-tkGb`IVOd9yiqO9F2s zf82J430po^ypA-7i{xd;Kaz0qVqoTmFkg{?a3(c=t-H{ zd%V%K&+mEYwB7jPF}FNF{j!*;$PRGPrn&(dl-(~wSj=OJL^NaU-wYb%?9pA?eQ671 zMKj8SVwuu<%UZTi{nTIsy|)=TXO|1V_~m|i{;tWb0$wC@R#sD2g7Kid2l|Qh=>==@ zaXgdpV@|^4EyUR|zoVYKYz4{3y{k`>!c@sok*3@^TD7A&wo3+i@KBzLdiQj`qceFN z@(gwF-HQ%7SGEjT!!9D>6;l~h3BNkHgTHr`?(S;Xg{A-W0B>Tg&>Q69WsvloDO>0a z>VnNtMrzIhiLl%WsaLuzv&h_H-+{&GSZjwf{XjqCqPd-&T66URGwYVqzdtU6(Z-io}?(r4-q75p+1v09kCx8$;8 zTP}CQlA4j-nCwEVn*;fpzoa$TPi(4TlQgCNt@YWISe0L0C0X!YVq1@nZ%D=Zqh-Ho z&yC-S1aRC7rTYA?9AW;G0>(%co{2T?5+}=btF0;<*e*!VPqrIn!6^${wL`nz78RO67|Kvpmml>YJ zDo8YL%z24K3|wMXkexBot#y{cSzaS?(Hb}OMBmbeJX~Z94V(1dX(oq!qB;IJm=)xS zS`rEV&Dgwexg#Jo>u%%-nV$$nvUc|5%6~O=ukMWJndLKJYi%R5Mys}*kUG!2R%~jE zmJt$e#)$9q%|GTQ&+K%5Q&(SokMP=ItbZUE|Fid*+`%b{C1Yp3ud`;fx>w)nWygn{ zgde6Km5xJLG8ehT;_RnAzWDNtedo+F4H+GfzCCw3UjOJKC+k@kbLZiF!`wy{)mM&3 zW{&jrG(V0$1Xkfrws9I;UF^L(6L1UOReMCwi=O>{OYClK5m87BHKPq>_pv7?XV%TD zvb#i)&BXGVad;HlD{q?O_09Z!=c%g^)c-W<$Fq9fv08iqRpqQidb zNX@;M!X@b!unLasAwu4?0Vjq=-6f08c4+p7~GN)9>qf z_2MT(SN4FLuBW4M$zgsGeoXbF9Duas$xkm6kKF)S#~Y^2X6S#& zCI~!sb<6m)(pFO$RE7(g?dKF82q^FNue$w(GRV?{pSodc%doizIOf&=nMgFL(fV`e z)87X#EXX9n#tRXv4nwYF4;GH@T!eF?1~AH{n&VEj#7sHrI)EELM!lxdNv{wz7NR#c za%7YPpb*zK5Lcm&)gfQAg>t&}G_FZOshguVOdG*!7j zM!e%G%dbBv%A^lq?$ka|zezVLgBiZr={FNX1pRe;hOeOc@pnR^Yb;vq>AZA$a_0wj zZ7YJS);6P2h$r2gCewiaO7{v72aI!`Zm||n*=*g2sVj;?oFC8c_*ZKjR$q$`_^5R9 z%jokB_!wGw#QtC!+)%zPu7g*KkZ9$6@ACo*yEzC?bk1Ka;# z>@B#We86{II;5mK1QZk`BnGJwkdhXZW=H{PX&4wvx>Z1t5-Dlv9J(6>q=xPo8ioPR zi@*O_XP>>+UTc4aH=exj>&XSmc}pcu=8eR(H>nMaGvL!ojmthIXLBmf+`VPoXv)Z1 z7Pdl_hd}7NKAocF$~aL@-h?H?r3)=Jb3f3Pdv_$%g4YyhLzYP;_B9**tNwhzeT@YX z)-NKA4>pGL&X4fx6&@;riF+3=0C#rhi8t-{14T3Tgz9pYCzp)Pc97Y25Jg^v^)OB0 zFE|n(hx2^b`E=pD`J9^3&ys_OVTV(Vo82XBG>Z;%+HEn8w&g*r8fbRl9P%bjIIFgH zmK;q`Q`m&+ISL)tw{UwkbqY3KLuis5vdq?Ob2V$< zpmzAEW`KaS<9_*SaE3TFM5zH;; z9Zk`wI~zEGfE?hzOO!3hq0fl-yrqNfdu)-BJGEMSm%f$Ggb#qu`}e;>uGfh*)d~Cfi-5Rmt?6lR`J0d{@t~i+@6~nz#8} z-_hmBEC$4UTQ76HdIOc`-=F%UnC%JJ8YxA7@h_BOTl}zbWh?K_$R*wUPe*Ed^hZ1^ zTus!On8BHJgj|tX>#hyk**z-X;qo|b?fTqW(p?Jki-WcDOpTkYvV7O8cO>ZqMxlGS z3ZE8RY+{FD`^TMAC3Rg7`;&O2FIveAevmh+N&hZS_U+_>EGd|Mw7gGai?A+j@~iV_ z(+YWWHCJmjQ?q9Do`TLx(&g%?(Qopfe%BnpRZ(iWB zGtcyz_sx*R%df37+)$gMfllv5M{Z4}jG?x_m>An%l{+|u4AeQwTm$v93d=2>a`32- z4;$to4~QL)ze$PvX0;n^d-}rbhsq=Nf^du5>ob1GhP~?LM&RRVHk8w1UL+#$R3e)X zK;(*0osymsgL3ZkH;Or{IYn}YNF0SMk2V`I9B!W4Y} z;!tt9c;N+$xOhoL*^@q=61Rv-r`q}4;xEXBQSm(DbEGZL?12 zE>2|oT*y?)$o#mibFe2PjTEv4nj$@yrH*)QJcWGY`0J3xH~0F3{9%lf5rp?(f3J3<%b(uYGS5jzdZPJ%X60cidFUGW z3iCcoO&x!md$93BY2EsJ`0)i$Nhn1G7_VGbpEtsN3nrX_|*Elf7M&JnzJhjw&&<Mwm_z6nMu}0c_GW|{b z3j@Eymp1;Ay_?GWVP9t@J?|?9UC!H1(2+J%&uc-Xq=Q-UG|&OHcN~Piso)Jeo00fR z-PFqW%W{gaS^^tQ5mP3r^|++BFV`nOCi?gzIoh*p^ZqxK(>{$@rg3XyUF2J?s_sQ5 zV1Euc44K@jCBu zH;Zc#>mOadjrf?*5*2Q9U9F`pfe7 zis3Wy@ep<>Vzd(@%!EZu!@*FIB63l;^M%titr3+)Syt*0fp@g296Juac`$j9UK9~N z-~Gl#*1g0{}u*;5jX$eYl!#WLa>L zZ$a0nc$U(=*+*0^5_fx8zaJQSqXme0%E$)^M5*IAOo>h@kG`{PRXUoI5C)tmeF{=S znQhmwsHOh?={}y|pk%bU`Gm7WpiQ{xk-!XzcCCnDpmAyWl}PMF1_JO7cMb)~R1v}k zT4o%@_!>^0o!`EOEv#j$$&z1mR4OpF&?C=lRempG_y=kj@keTKhGCXE%snER#%1oV zX)(u=>f^&PKwns1*{~Td~B|xXr)uQRs-7QYw53#U|&DJclj%b%wIul!0&SX6KDO z`4utu@s)PjdJDwPgZ6_dBg5)!e}i3iwhprhCDM+H&=WVzbKDTlxiJp4plxpXXl~z? z)P>bfS@`#qw}jX1*(hiJG1iSlP1(gb@><&E779ALw4rXn?)t4Oeo{CWT}!0A8SY6MzuO<7@!o%+iuh0@5iWNaZD#`W z1PVX}Mpy?I(*xg5YF#Q?W9J9zg9o4H8M1~AH@%yQ`w5_f*X1uS4}69jqSQqHc8ve! z8zybO+GPa2yLc2532p4)Kdmy#7Ap=OGopFok?pXV$Pn9rwn( zfG!cA7b3+-Q?c$8qE|V~4GF_X3SnXdwij>E$H%X1hN~V8^PJRXtyf5#o~(Mb6Fa6! z#LEFncj1);%$7S^L!`G4ytLc;z7BN#Vz0{@`oE|PF;`+%{`sy;?P>QBeK9q1O0BXD zvr%=STm-e*NyC80#UgmDnJ#mR>{v)#Cp9o*3{(F_5&pwR*_nT6gnRc~rT}nK^S4PF z0Mrno;b;970JAl<=|}O28@gWveWWqyfmys?EF&v2tP1iKY;6M&HVXdpyOZ^=$av3g zD83pbCmml}I4+&1`X5;&e<$Mia~{EBZ>tiAV^KNR>t z$RRWA$>DsVG{w{*43S*?sh!R*c8dkt-l#BgP@RcWbI|%WehJxIg-GzX*sjkzBd+F16 zzOT8bRh{!2yZfM5m@$^@iIH1@3yrH|D(I>XW%#dt=H!6_a2~ z>1?Pr{v?A9obQqfUgk3*q?}v)@ZArveefz)>Tq#+*bdpA>FPt)u!i}yQ;?fR%~@fI zRCro81Q|r@b=XcOF`(9ZL#}&D=xtmrn-8lj;TQ(1#KMSgM z>^r{PNP|Gneihcf4+M9ZO|T_)C>b3mIKBh_#dF6N*CDgXMX7)dpJW#pZ+rDP(JXGEBsyK2VX#& z=7C@`?Q+Ym!#4x>O}D;$&q?ZqoO%7G(~r@vf05i867SN%kW%3#_9J zaJx=7{GxsfUt!-2{~Z%uK`6Oh!QONTj`CMNe9_l;!!hWWmAG~WS47ozwi36=_h?Nc zr}iwv-NAO8RoV%Ol9%G>spTC$NtFprIgMwn%%OlwvEVqT}Q&4}57_?z_%gA42 zP9zK)CNP2c1iZD5X9_9H9~Bf?QTKZB1-c03RrMEClXhEJBg-&JSsf@M-*6n=x7Z^? zW3EepLcrg0P!B4)zS&){tNo7Y&eZ`aSe2k>zRa@<(0oW0{)p&3S@`oXODvziKuQe0 z8`*y?5=!1e_owe7hX3bM#7Bs!kiSEl{5Dxn4N)I4F^boW&vGBbcW!)~2WxW4+~eyz z$r%zAjCLStO5O|jMHyRCEu4WU4feJ;^m|hXNwS7s&6ZMX`7J}y=8cN#Vs>{VgsGRA z(KSZl{~tP{k^$rX!7xDK`VV^O*a2GkvL%W1i-^NG=MMY$&l}|q?^r_lJtuCLm|rqyFX=CwpyP~l>fL6m6q81CcEeIRe_Fr?L2lYfBtd-q zS*Sve8OgQh!q}>2-#AE%3UYTE*0j@)MP3yuaLZ~uCuE|Cph|$sCbCIwC-zUvv+$E#$Pp;ePcpyxpmy_9!rWq&MpSETVael{FHwVJcg(Z( zUD3SStNjM(A03wLj{2ozv1Cia-mN#f?hVKFc7}Q0zl>}7%GOu(9XrZzv7?s9JNvk( ztRh7;yoZpg7n9_XHr-sAOt&q;q`W5U3PnpJgZg8GdIARScAzSnut&E@j5KxQDV#*w z_lF6O;5uAf3|WuTjs~=I#@|(5yPa?(ZR@>J3~umkBY8$4Uaafc9J!OsJQqG%@Be%} zW=JjX;nbGQ^GPqicEJiBRs>EG>IS3HcsWqqA} zzv1TA`-7tAgzCnrqj5Cu60@mNLASiU1&n86H%E?gKbeg)K=TdtoK(sB9{Mmp9R?Gv z{AK~7e%(ySp`y0&P>7X}PZ7aS&p9J?2w>98pnR)VxfpdgnMPV2QBMr_2#l0)^BsZ& zoCLi+|9c9c49-t*0OPBYL`bTczk2q|LqmUaeCky@z;~1wcfRpY>z;b}&p~*8vF^|M zkomsOy!ro+6w>$zsxF)XSYmh67x;u52Qmt6#0p3&EEq7>?x3uIjmk-}0%X*GJRi2C zjZ@^VHS%rv=w(gDk>qN~@?z@m-DSC;D!c}kb2KX5{CwVHCEg?Rp-*$DyK)S@#qkbB z_Z92ax5JUIS1#4>% z3bx>e(3&$}hiKWLkSinw7cC6m>9#~XWD`mR{IH!tlAQKKVmrj(Z}+y#6QWA=a|g|4 zI7~!MiE@LN0q}hPso!j?wxC{@?rey;__f6RQ*U<4$SngH5?@d5^$uoDIbJTM1<1Uy za)r)AmOR33-m44rf>j$(WRRQABfX;=V%xYK7a6s81ao|;Yg{^@l`DJ{QPYG|3f^`1 zVhH8Qn%+ZoA5xVk&CB4ku5y&@u;xl|tdJ3=^u=IvxH>RM=a%$m5lY2Fi}R!XZx3L% z6*$lP9zDrQK?%HN*VtQjI_WpCD}6J|KTY@Ry|w-1Cq8QD*2@%jv_8$_F*W^`j$Dxo zxh^>}sZEbb|02C(5<7#}WlyrguYQy~@9!(5h)lJwwmszgtB0E!Vv55>s*+htJEq$} z^3khL=t2!h$)s~uQ^rlwbAa=v%$k#xt~lzHXM8@}{e3OGTlVe#usdNVZPVsQ|0&NZ z*3_oWgVlBzYl)ak7bS(qULD88@rphT`t9QzoF1+_|Q+~;_M~|Ah{ad!5n@N*x+v+ zvwV~P4~E&Dz)6)x_+-|*Xf=P?N>K;?)gUH(7tL}CB;JW=W9e>na5Np=YKyp+F)6^oTB;wwj|mwc zPd}>!R17SY?!~q3LqNG&W`+^#KF2Mw#v%AKmHzvx2`?~1E+fr6I(Or^a?|qRq=G%P z;|_}3(yixMz)feEMe>UfVy; z4(roS*J@{GxG!JCW7807E-peJL1N#Bgx`J)jgykzKQc-`vL~5T^(IAMuKOlItcf0( zZ)kHCo4~(yv^elCT43Z#kUl?&H&;#;>&zPeDm97}-2A)&Y;)%)JM3(JbdcJqc3C<{ zJbsz3S(NzXDtb_(jPPFUYuQn?mCo2cvDZ-D7)=~RY1U?L>dHmg>@+4nYSK_0L&9gr zC$xou;?ZN)2K${Z#ukJ5&l>_#XDo5k&$$PQ`Jv?0~^2A{$^8SF~7 zCPkp7d(ap=e&aAlI_-3`_}I7Yb?Q>xmv0U2w?L5A@F$fq97ZrRDKF; zT~C^q=~x|rANsTP+dM)wW?(*Hv0-9-d-}TO0hvcZ$(~=UA+%MNNMo94N@(3%p*;5> z`TWgU)J+1%B$+Pf<`3eKzlM1BLUXea1D!y_6?ai}(kTSK6)@?kZ zZstxqipCN2*BJ4i$;kR}QS|KyoeP5Z7Bkls(;`LdVqRVJBziiA@W%=t>WZvAH*R>H zCseWj#79zeuL3eBhFdO2JkBw1TL=72nvk(-7yrvIx)Pdg zd6rkgY%5hZ9#WtjFdO)6khH|MwG&L1w}Wz59Lg5(@SJ0!)U_t@NsHrNhQ_Whhp;oW zxvANE1k-v%Z_0c)0<=SJQ7f>C*(~FuEur=k8!A-CJp4v~8Gg;|R8v(Jnx-kaK5Y>x zZ^>oHd3`o(4Vm(28NZ;2#B}OTbB4MT&y{3tm4BHPz);p?N-@ckP|JJvW+NDouU=O? zCXXFe@iC>uV4~|h&EfY~j^csO0?AulAzG%lnsvS_POt5`DC+qMvfX)GvDy(n-+f(Y z(z?l9WQ~7?RU&83f(BNW^w#N1d0BF1Z`#Q9+Di~(pVYZ{=1^#_q?!yIhi4YQ#92-<~ULOXp*n)B5@heg={MRbb)u! z4(W^jpopx3yl$R)deP~GUn0-z8n}|1F{i_{?178t@3Kk6KRMlgn16M>;04URG=9@H zBK)uZ5;O>Bd7%lp^j6ATkbks=ur;Lj$3vY7qPC z;A}_jq+cQItL}p@P9A&YOb!;c6iReiP*N<{D?GkIc4o694u?EzeWz%ew}6?m4qZp` zM7Qwch#aw4sr8i4d&AUmsLC#^|7W6acj5%SU&@SP9s|7$ZK4$`$3DKnM{{S}wWkUN}9vT1Bj>H#RJ-xG#-H}#?kaMg4 zlo{B9@|%-@WTe*F5|o+5+=bb+`dbC>9%gRJNAgGsQXMeog{koQG}5Ng#@2ju&UMJW z_X%h4kDI4+J@A@F5zc$a#Nu8?NlptjPCvbyX;D^J!i=lI;i;m=59P;P9-`6|55c#W z!!dD`jf-qcUs!ZaT&!FO6Cd^_sGrA(;$f;5D40`77%gAa8yekKMs~c6kIi^v$F1N< zClfL636Z?&Y^DQyAf=c^Qq;UXvge&UHtR&Fj1y%%&;A%kYD=4!*{Tual$fx3+)6IC zU^n`6nu7NgTy8pJY)xhepB*@NSMD4?`X^68Ppc-(+@Ul}abjM*YO{ zFjbiI`|-D_Wd>I_GN4A2>LbcqRxn0sN%X=yHRE-@U5(iuoa36iL-V#k!|$7+;UQKj zrD$o*kWYy%5(~_19C76K(`o!$@Yck<>+tiu&rGRSf+x)L;W$(t zTk2#iS^1Jhj5V#Hj6M|Ok~OZ`+U~+k_XJV*JhtjTq%e2`+1B^+5zLFElfx?HOX=Lv zN{=N;r<6yA_ME$}o}6HDEY1n0BeN`13m0@GM!(WCxpU?-X-3|6=g6YgRq*jhEP546g8( zxzr1b&Fml$iC$DA>tKRqj!koTZ0br0e7vA+*foc$nFqoD+a%K7(BVm#IWd5vq21r| zeKxrjDnB+)>|B<~kv=V3iaw(eMaw4Y9U!K)Sk50HdGaL3iNO2RbW5?=5*0g+C)*rU zOCY@NEJshzImK29U~e?==rh7?T+IYex;6JiI*4;aOEL7PP5tBhH;X5o{Ls;tv`3yd8X1u%sF%Gk~rt5*HAMVni ze>c|Avf%${cwD@Z|7%I9KdA4<^(Wvb9wA-oy0fuMZXf@^3b>?q@FMZ(oJ>XX9KDuV zEQzBeMOaC%lnZ6F=Pv047hbqaCZ&y5;wfYIwE~=lt#I9Ho{^Zz@PH+?iTs*Fe_oUx zKvdO5S3s-Ig|aHk!|D{d!q@c}gHi-_>PLOstO4(YtA?yro}_CSahw7>He(_12QlXs znZT|=^F*7UqCA_A(>ejgX|FhQ6cXY(D57BT5+{*atju)=vMi z3~&7?B8a^3Wc3L~OvQ}od(>Gq5h~4?&X+O*=GBi7Bou7Sl*+=Ev}lI?33k1MpiI_u z^Y|iaMK6#QUbW?HN*VaK!kRYxDrh)@gZ1`o3VummhChWVv86cnV7 zdfFWaE54u|+aKowO>()(OyOJAvULyZroC#z`OjCn7slHCdQlCo?fAQ@h1s;Q^H~H< zUdGMVvP%u#ij)5_W0?xTfEFS{O8Y4=(MJ>K18)wzdU z2s;~iC?dt}7Z<48NK`u(zb?bIETU z1BRW*1gh4VOdr#|A%_~mar0A>Ounq}hG%X&&+d~+7!Er#_L=IQttCN*;shqiXO*CS zs;BinwhdDdSQ8@VdMS+c@xJGW6=m+WIN_yG|L3=j$9J|Si}D|atVrequdtZ?b}1&o zuE4Y`!6sIGk7fn9(H_bw@X{DwRPJL1_gWH^cB6WFKr$@ghm$37>@4i-1?Q$gd8T`|QL+#$A;kB?! zQE>htCTstr-KGr_u~V?Xv6OG~vVC$$N1(e!`MWL1eABr{jRzmgG-T1wr5{|Yx1tFt zJ6m~DSYpt~*vxw(IjrJ$h`W#7`;wE|g-sbnsUJ2?d&0^Q`J$E;MOthl*c=}!-F5Kv zJ+Y)LY1KTqGkO7*x@G!(u9;`sx9SM<+Ujx_SEyclsmfE6N~hv#OiSL>9%>K<@(}R! z$^>*ul7;IP&<>}3>f$e`v&IMiky&?H`awr^4Ps1y9*PrdQor;dh#;Dqml}6bq|r5QH*j1;C-}#|+5g>fku4W* z{v}N)VAeISnJ{A!uc|2=IxNXbiLuEJuyi)_S3&*!r17Nbr_LpP?$ti6UJzO1=9c;1 z8~3qi(IaAKHfifWF?b@e$)w9#LJ7of7EROz7`ROYS}{3k)vqTCMEkmkrl5!%~7vz!CIR-B+4w81B+}Z=;-HP{d{hau8YQ4b#agN|6=bWht6n~8Z;B+1{D#BOhkad3Rz z;AeP5vp^PK;;U5U#PwBe^=h298CHW?7ZLUfBPudG1yH{k&=H zi757pNlpC5LYEe$)n~!{T~pO+e3iM+9Ut=D&MEBxRr_9>2ALo**I&#mLE|rwdkGWx_maW(TA~tia zSY0PZ-$q-C({lZdtH8*gbqcg zkw1TLG(;(!3Z~=dTyCV_9c}vKeVv5BZ@{$izLn}^&-Ap}6A+ENv=Z;+dGC??>8iN& z4q}#u-Ei~)tKu6q^a*#^kCGGQ9$*okL8x_2^iY3=j2y8e2M^X6EkX8^*-cxD?7cmc zIsgTG6G%#L0h4Xpvd3Zj2-`iX13K@jGjY3FqQ`DB-DEJN9O%jZrT?DFh%Mk0Hs?bv z%llR6kx^9_O7|?MG)vXCFz zF&#}M<=uqxJwp-)lK%HrDfso-kGIxSojk6V|5y@fgZW|}8j7Q%=rtCRi#bPB^R(K_%3t91G#lQA50z38z#m3pA$!lyi>HfyW zd~HTi*L;3Cct~;HjWvg;@}q87YGJ+JRO}?|{&*FUwBma|Rg>(zWZq+TP=V+Nad*c4 zwYE#Gp(l-YvI~HaFKtK%PsM?1f9_U){;Xz!tHfKks`8!R^_QOuqb1<)(30HdxCtWS zwP7sF$)=@;xBnozY9&Z-O~{oU25r8BhKAP3&5TCtUXpu0k-Juq zUeWkrS}e5Cay}(@Uk81-^5XwJ`e9z<_Z9o?ScVR8P~y41FyqwSVI3P8`l*r}d4N^? zKS!bP$Y@wfL~v~h!*K)DEN?D0NeMd@`;!EM`sPB+v9axtB2-~j{jQ$?{%uERsCMIt zDQJl+{Q`2>4?&N?bwqRy?KvT3{XDrx^Zr+R4!?*wgC9@oY45>rFP#EM#k~Z_f_+PY zgD1Oq?2%9F0W3oGPEM{gU;)dQ1x#ef_>(B{SeV#>PYmWtLsL|De@=fcdTJRX4oWUk_ZTA4X zUYCmJyti)Ps0S}A$NkCAhJD4iVOM0i=C`e#{WIklwjIK_I ztWDhzWFGBHs1YpIcUJD-sZosKarIl>jC!(%0OII_cG3!gW#`vrV_=?mbl7yFl6Xh-EZ=(Hx6RHg3dXu}&7%^ux zZ_udWYWLZ^-j(@X0!Hacj_ejoO61;+P3Q&GGCSr6g8H{mUH4X(Upq`&9zB0P<-mw9`@8sJ(^)D`-z$4v{bR&Zf)rVR2Wxf{-S0dO3uFinIr?h^VBJnqO^8+&6ghEvHg` z?T(kvA|D9cGzzkD#|ZXw27n8VH@=fUqK4k4`URFeJ?Y`_lO4skA{DvBctJEpOiU@c<0F;q+);>OT0HM<|4WPlRd~7{rp+dvXhFB)+ zi=VW2ci;quBn1(izn!2-#wjAMrlM0VtD(^3hzZhUdr1I)B>Pkc>pYPlLW(Y$v)W{$ z1B;TE_rOz`H_ak8qi#}YQqr#Y8b17$3vy<10PSXSMK{`|H%-sMDoHZ`{| zmTq=GWfbkN&VC2KUHHfa{(#9g^JzHu`oik> zH$7Lbi4cE9UmSiorTXr}+ylRZ1~M@0dSj0^{V#v#Pg17?ts7VQn|?fl3P{Vg)tVdUm6HrgbpGV%4~Kr?H*wv%>w^OXusilH&yCa@(sK{;avp zhV5KF{Csky#(s8Q4ySd}1>H?4K5OWQ&0Wiw06rc@4##HS$3QlcM78b12kMYAMmOykK8 zueV%RO);*=ok=*0>`nXnddz7;88WgqVZXLwDo|ch+hx)6asy>i`ld6V!1skR@5f(q zWR!JMYb4xfR;9?Ny0lvghcfNvV>EOYs5C}@l(dwkCusT_yg1nUF8!>~>o1!Lo724D z2E7`^v)fh5>W-DiPwsQ9ES^0nt7_PNXS$#nPZc#jB5{d**kSf`*~AaFw{v8TIw&~M z`;_W?Yq-#A07IiSD=!a?4}5g5U0ovNn&a0}VON7FE6(M`VE9!l3RmdHdI52H=E>r( z*WA(zlfM26hh7vP#p>1ly`Cv7O-lWKs|UZ>06N+3U}$edBes$M>hPzvsFGYn^S-qD zH8e`lVNgqW*XQ$d$j!Dci;4f`ngIgL3k&6k#e&!J{I3%WeX(PFs9lmX%D7-`u^4+H z1E}i!n5p9|jBbVQPh4m^#7bMQm>3MVk#IqvM9Dw40P%?6R8iV&yQQ8Q2-=p|*od!q^Ag zIMV;%Bpo+rXg%ub*+9pFy`}d^jzsefr^u-v5+{ z_0eu4)7%iq)b&1=5F(ET?Glv4CiO!-U^QDoQ8%23C7dJEr7Rn3mnAO|_;N&dW@((O z9DHT658fvh{7uK?PNGGha%+qbu$!i`qD;=FhT?!TSbx&l+eL+A9ZRs99Dn;7+oRso zrhGI1lw2}$(T*$!QLP!cwj)m&uvcB9c>_i5oLoktFT;PgV* z^JVFU_m8+nV5n{wh3E&Q#2RDf?dA$=RMZFhPs3ln`%4!`Up7##UCe=N=*E-27a-sl zCwa?;d20&$;OQ8nDSp36+LO+R^P;AfDf->5CmBOw4nD)P2T;EwLLot5CHK;Qk+C2E z)Wg_S)-x=4s^|2Biq@q)6+{qGpu5x$7h?^YswH+@v~`-gN8^8WZF=d0IzF*a{HvN_ z177PoB;;uc9TB-4Uw-Ikhw~($Ysbc59#7VZ#=j>F9hh?EQk0DKd-Evu&;b-&a8rv?y=d$`_;WSpx59@R|KXUHrB}D0n3GdHA2+3_|`bIG@$dn}xWCT?Fy; z2*$IYk`KDT8#M?`-V8q-n7zNS*M6x3R`bp0^A*7O3PX;Dk=-tY(a&dJ!2345{kDg} zZyavwp>*|7-_7(4*2c5oBP(v0lXemoRbTL2zYxU`*R7;LVQ*0{mpyhC$o2l8hcKKH zZHeP?yit-&N;YOC*>T+745o^s#DIq??-xJ4Y2n%ZK;HdqJq6k(>RfyCN2WPoj35_8 z^~=i0bnx=S#~hJE-EiOXp>)aLSd_n5?j8JL10i4Iu2zVEZ$I)+L@mLdLe>v+jy}qD z-$0Az=vI?4BQ!<_flhWM%;}30MzSZJ56G|S{IjP@A4rqmPofUpeJA=~LwUDpU%!D* z9@mJ4aui__bf8An2tL7c zh*`y`t*(VB8ZO;?(EV&h80B#af;qsZYUN^cOSP9Sa4olvq4|x;3bOj+=M1G=(cNA# z>$n!mjhjOdng({iQ<}8c6YnZjlra82{~`0WR-CWkY2W24rDMcS0_S2e+xgEjt}W(I ztCjgMKgCg$ajr2l-ku{XV3&W}kgRN0}B#4U15)wp>v$25bY3Ak-zLkQ6B;!HmpS(KelqSv4; z4k%bb?mK zEc>duH59n#RsmV8mk!RmR*?Kt*m!mHC9&VPpG5DnEots${jHmB|_;qqOSN@u_ixTei3ltj=m`kZJE<*~yMEnPcSG6oxrMeT2{2G3)(uE3F z^U!ZdBm8{OWFXqgWt?Xvk!0krht!j|6lV5uG>)6f#C;mcdDjunh9i?T7-%SaMwz;A zXxwCgPW)!(pH+%!i-d=DEQS?b2+^*xiQ!zWL?H8GtX``tvVD3iu_)(){+Q(RT4QDZ(e=_RYnk8szy_(VEy z8E})?8kA)46vA<|S%@vj10Q%~A^sz759eEK?21HTfajDaW9UJ$unVRmo@2&|FOuZ( zDNt10uW`WG z-oeb9{$SAG7i6Ym)mSb4$iepLh4~^gwOD=XI@?Llemo-PxeRUi>2lEcP_3MxM%jFd ze6km>$7}42O03sb2&b)SiLx(weu&hsOIGMJnQo~0?rh`OjA^tgKETtG$W%M#m%rFj1%>yHiXfwRrSaA>*U!j3P@fT^eOx*yLpRWq+i2^pNwSEYldvDAb@t7=#|h> zUgyNl3d+OIyU7AY=4UteSp45})IHr>Q^WkdfIZC95;Um4z2=kRQogiGEz}U=z;^Q9 zu}$JqXh{uqwg_aI5v=ub292xK&U9f)ak2#$xlw7kQKD`ysH7A`G^<@h53l*TjCv!_ zz`lUjQA4>}ILQWqQJ%-TYp~6ZOOO@ao`^IP0i^32wt6i^wN>}HGEdpW^%mAD?V%2z z=+~nk-x=Piy@b3_0|Bya!A9(vfPqk?bVvk4&uwwEgj<2Kb*pngi;-^O9`N(a!Ts`#P zeAA)tFKV%UYg*(|$24`4S`E>N+Y*0!zL#(oL$3%#H6Y8kb@p2Ga+K(rAT$vXc_sz7 ziy|e}^pT&*#C*RKDCpDasPDE!aAikQ)* zGSA`w9R0ACb~xi~$bEF+G_GA~*bLz$VSaHp z?%#zs_}`rscFTJx7815no=T;wzr`#q(M^s0pWF?6fVe*?=nI2A0t-Br_%-tJ2GcP| z5Fw>ul)UM4;L}O0k$^D^%ajyBX9?;uM@3J1`pXbC)~uR++=A^aP8C6AvI|TvIaUp7{u56c!wVY<3y(=tqi-At+8}y8&H#2 zUNQ*9zN1dru~m3e*3nN#1ZAE(nP*2(r{yR%rD0Fyi0>39RpjI;@`5h8f{RVH*d8g| z7^JwQ<;o0%7FJFX^^N$0oJh~M!87Au574oUkyDq%@-$xj@36%(pl!UF&k3IIt=YoK zfiQ6D+|>L_+d=v=)OJKUQ!TSK#+1lHa_`rRysM>PpqRPO7(WQrxwTTCcJ*%)A2Dg! z#&Yog_9ECJ1?5O2kWE^>zYOL_W9~4XUWUr>}h*WAk4sl1@xKb;tep=8vVCiJcii$~WsjtM8W{A_5vIY;REz zeRSY#{@pkENUJx+;>cCi@1QI7^w*zf#~-iL&`d&UmDeRXh5IucdyGP{9=fK#K!9C2 zhSzB^ok4r}1ae7XzS)aK?5%f^>OJGs;d}b@P-ki#{6~aBX+Vf6p50p}rI~gFs4%)Z zy?S`wRaOGoiDcl!xC`qOm@@V(H&boG(*B#HT>f&2e@1r`uh&gbJJYJ2Pl&V`Gvhp8!6R|sVa$MLktEp30B@^ z2Gi%FO1|q&eR+fyi!?m<_x5p;`IX+V8()75U}?(Iqsh66?VMBJii5TdfGIcykq&PH z?k$8B9L(2NAYQ}DZwRt>}9oL_#GFB$kyYveITi zH06u=ls+{ES`F zV>z$_6xn6gFz3@j8GE+3)kwvg7pm7?J`FGnm4Jug>jC5t!r9*|TR*4;p1(Gk6+Gn~ zcT2x>9rnYnayi>D5z?GKO}%h@(A`1F-(Q^{c^*hSUMUTqZf~iVv-ay8Z97VuG-54KIT2t3MNx)2f}3uAJG7obS}c{&@-MdK-Y|v{88Lw$>(A>v8*@p< z#ugI6firrpzVxdmQjN(RE^L1XZ){=6P=E1m8p~9f*tfHhow-5~`sbdPXQLtUyEJ~9 zHOS`w!`@rPRr!5;qjX4j3L+BH-66A`E8l;i#5Lm#% zMZR-^KllH?-`M-+obz6s8$VnK^Lgf+V~lT%XUbel^-XQI7+?tk?h-MXp&llrSU{e4>R%a$+Pd(NaZYi z%C?#3(;u$R6&|vtTHo|}FP$>}z7oFN=g&a|LoQP7JaN(^IwB7-0jUhI zofTx33>DBPI8~TH8c5p=p1Z_}MWzjtyG#ev#C+w&6zoXd6pNZ1lx>$Zxrpu%+{j#SP85nM6P=<8})r6{fH@vVE3tq-=cVlB=xU$$Q^%2aBeU z7d3iC2k%0gGP+NE)AA$>%C3??$&KElB%j#17_*Q$!t`0_+sgdi_E2BJvZ}9X1ZGuu z!M>w~-GF4*i2gt~ZXhQ_O*4sL&+r!CgUdz+d7#(Ja7=vMm-yVxj!PW!IFqEpwB}tp zm70BW=MTSD<>(y-KVisC<9Pu71dAxR^?w9aHy+s@!N+IMe+4_a^2+pYG6C5zb#p+r|WXSFI$-tXH`Z2w+#4aIjny%OzGCYb&#N?30x*H4sFy zq9l$u4)So~RUwHHH)1J&2a=WiQmC#GfCB`!Y>NNBZa+|8VHoFkdx4yOER>>E*4w4e zACG_kVSd|)?|f>ZzuUl3*R90N`lVsqnOXbw*R#$e>}wHQ+LCBZPX@epme4ALO?@RJ zNxq{9XTW;B5>-h$n_bwNL-=kqd|dQY7Ji;T&ZL`!B^f_gXc5J}Y$AXRfB z44i((G|_p2Qn=q*9LcoC^G+<}suo6RLI$me{nj;e3@aWNlQd=!gxI1S)ldLnDam~a z5wl~k8KFON7BOGd&8#u0@e_id>-4x!l5K^H?V<9WhcZm{g7 z%SVT5@!8+au%MCZK|>as$~`~x`3qgYsByA$47o+|lPLJj49|}~@r%;eZ$J?^R- zZiM)=3LL(nL8(wZAv@iG4-T;(Jrd>GKkEHN;MeA76H+%8nf@NgVaS3nY40R}TG?f72;UTSPTH)K?=9x+af& zKAjg|yud~*z@gm2oL840CVEp|Pf|7v#T`LV~nV=mv z_M%(Z2B*_sy%}e*$uThR{3DMz|K44;=3hfB@ShXRYBAHLVqFwjY-)Zj10>WX<1AncJS$F{LxCZ2woWv~dED{eN6vhX zK85~C$Xhs?hD!**ZZj9rq77kNprY{BRRN$g&#!K16`IZ^4~Sj{g*_{Ia&~nMvYe!~ zvh5MRJ;skU>eUP7Q>I3)739ZC%-{Z3;@!$Ow zdBWb>4UU&KkVHM}*gZP&HKA?tUtf4V?}LJkb^Z?ZIQdZZno57#4g0ozHE)h``y~Tv zhp+K{VBYo3hX5NurW1gu`QE=urWfeD<}#)FH^Pv4OrXv@3+(b2FKQCLQTkS(Y?DVN zyHnwue-Gv(^yJ5ENe$|g*wNfCldYGT{c6(B|L%_I1%TskzCC+>>p^GBj=G_>+hkvJ zZt-C12d%V_Sx~%K@U4kV8v0Hi?CAL4!l59gDq{XhVMgPa zFSL)4AdZj3ap-NYzZJ7D8Qq8>Wpbr2gPDvzPYT#7#lCkQrwZ}h+0?0 z=?jX|Jg%Y!-4R~BR}vW&DEfxnBIyazoVog^0K89a65FTPqV8|awjSFM|1&q^U~aV4 zr*>CIg7d`Y(IcZ@ydQ6-iwJH$()L?PZR}=ujX5Nrz`dusn%gsSaUZhrK%xMfW6ei8 zM>#ewK^kAW7MwucV?=V#(1Q3%IzA`eMtdmbTwZrucmBQz3N@xU*maI&y&-Y=fv)Lve$z5<3MtUa<$Z z{VbCFdV=;b*52i`3JU7;B0dk=G--N6*m8Y0iud2$$+7kP*_DdA>4e8GIaLhZCh93| z_bR(mDM}2JJ2?p2qTJluej))HOeqat z+C$(+Hb3aL^&@4vIcFPc>pi=9)Mt#M%zm7`H4^$Up=Srp84a32+K3&xNC6Rb@Y|pO zX2AT*sZv$X9gIQjSo}NL8-dHJ(b^u5n&X)S_qy5U$y{s0OsJfI0!AaEd%0=YgXjN} zib9P#+aUHM`v$f7J+ON{uaku)fb*?2IyU3xT^O)%{QK0w73TEXqCz3AG_-p#G*@)8NvtWcuSD z6)a?1C-?;$?^~>bHV?`IcdNf`Opnf;!7oydK0OhZqz_Hu8ZW3%ewt(~>I{d~bPD%a z_%6#I1(wn-b4TdKiHhCaIC!TpocD3q)#v`kh+oTtb)(mIeACvjTrhYv3%-9)jbFVnbr-z+lr8nHQm9s4ivw zbB>jJv(m_=nTEA}NBDc0B>bm{x@7-+dt|`rC#0jku4x?C9pRm6^t^*y>1l2f`{Mae zbAmvs$e1qQ6C`djHZ-<|>Md>9gK~~^G+opx=BYkPDoUk#4aHX+MV~g=Hff5lC>?GD zm-9W#wEoRpcR(9xjGDp^_xbI76}Uf|_RV9DJZUqJcWb5P6BIUm?v1tyX21r>tE0J- z{Soy=I41!^e7Z=XL-BSbOs6JWlb2N*XpJnbwz4{NC=>NfTNM_+E%6MIivuOet>jqq zM-l`Z`SIEsZ#SUlO4<4%bj*@ulW%w(ZBlY^=yBd=9K`0xVJUk+7WyMd&S3MT$v%e@WIkAV|F*2iO>Y-6e72GWFOG5>U zxwxtZ)I|+cQ<-*WLvM+=Ch};12-2GXx99WgcJG1)8SCVHg;&w^ZjD(N?q}Ub@JCn+^CPv6GNygM6H9*VT^WT{-dnza>JR2*@tujQM!x0`#5MOq69t z%93S9F2O@W|67G^&^mtu?~e-Ee@=O^dcs}KnO3ODxn|;>PJOTj`*A!4Q$GEnEH2r3 zkEOff@o6`ce%fRGCG>ziv5A?u~|B)bKmx!OG)R5 z!3iFY-^e?yV4-EQZgP|56SBQuHFQ)&@ZhDuhmx!YjrY4@J#h4`?)7o_ID)*>2aGLS}emaP27wZiAI`H8q=55`*~Blcr~ zm4s)Z-Y5~Q-*-zx81qUR8p?Ls(yyN6Npm_`nt`uj}mK3%qd#&5^vh zk~btj1X7k$4{beQ0?MZz+8AH8(CcMq3AMFAHOMsCth9Y0=9jqUJM*)t@|MdHlyFV1 zS9rEHM{1mBbcT@s7OUB)lW$}fQ;P8v$1GBE8Pnmk zP*RQ2vV*E(=(N0-QI15!yx8L)2%e@@F~!^LbGupE?NPsqJbu4K3*&U?msvGuX~aqT z=X>u5Y>>bKojf>}`0wew5SpA4UcvuY%Hw21w&98X(g-|@=xK4gW8jN>))G5w+GNWc zo&oVKlr>R^O=(1&7%9pu{q4uGUA=bk3r>E6iMj3p-jPSsyDz?O7D)~_@-A7rq33!o zE!WO=K{0-P;yqHnOyp(=$>3;?4Sn5|0{psq%{gLK7u$5^czL<0*nSypYoo z)iyE|P(&qmDE4%-@|+n54=@}oW8kWgH@55q7C x8lZ~IYNX}Q`Y1l< z7VE8COjW<&>Q7n%Mkm?|I9qoC)#Q< z)+9H@oO*c5Cm}xN>0!k9-idci@zAay%y zXxyemHHo03Xec*TR?;WumKX6CYPC*NroKTsrUQ2Ct-2WPuqY`4Enb2djIKbU3|*o@ zv{$XeJOjH^HOsy|2Ql`^qfkP#^jQhNNxB}!-bYJ&CEmd#jLiozb$AImQ6z)3nAUBl z2i{y~{>S$ZPOawqY+NoTy%QEvgf|SKA&|Bfm=>MUf*JjT!50^DO%4x4aXB(sd+UdZ zyKE+J^e}SZNz9#e4tW<*`zEHL@>=m)pxqzpM76gKtU z*t9-Aw8n~(gB5w3C%pN;_~9({f#GwtGlIuwmJ|QI-w=2s^Gde#&Hj_jCuk3dDCG@F z1OAI2em7ACeCHgv6b_Z79{n$#=kGIvVVaMDE~ntB`2( z=W4XnNl%vkd&6B$66NcuooyBP;SsTW;JL5pADR2vmngOOpCA*Pzp1N5+=RZkpT`JK!+zii;;FO3%HNWFN zyj&f*=YAkq*mQCaS4&DlWlFA6+xi`=R%6!u6mGdU?zTJ=G^~i2*k^T=8v~oEJtHye zdtK|cFrH=^(Q9Tn8frQ{c?Pi;kq*A*he1tLg|PE7Zwal_R)rTx6`?Q3%~>#}`t6x~ z2sNO}Uo{Kw2n6aG(UG2-cu*Iavfr>>OWu*U@#^7L@J}fLuA=V6+3^09n^ZTi>{Er+tXjS_i!+9MJs{*325nLL+ipMq&;l)T z7_vAyRup=VSU6FG8ENB4?A+zsMwxhu_benp_w=(~*U`)=6OU##b=xuME4MQDh`>#S z%WUGH+{`f1CL(j=1dJXe##VBMXf3&3RP$2~)wYZVaqUKkp7BMY-y5k=%#%&=C@aku z_a?Af38q9E^_I++XgV7$?|zk%x6C0zRfiYEYlaj&{5-y!NVFK{9Gr^hN$FMLk}lm} z?UrxKL&`X4qq}qT^r>>bZExhHRL@9>#V%OJ4f8QGcV_!AQ3D(9C|imbe76|8q_k$q z%$uwrlMdY6ZY&Yitj_5MIC;dT#tlYHS&Zi2IPAkGi%y<-frp&Z`Qli-zEMw+}+5*jm?7YCx;_;uH_8$yj^?PqP)*+*Q@p+k?j`;)R&1339G|tUrL-SCL3T^u*`QKF&C4?!#&E(1KRQZ$vS<;RcV9;jMTlelgUMZX-w<8Zw z-2G=oo2X8uJk=lMe>{U~@fiFN?int9!J6)Kb9Fpb14TInyR=>%mv}Q4k6kv=?e(O+ zxchtG#>JDPxM7D%{xl4YxBja!kN*iES?-DrOV7UIcw}rwB%Zj?_^0=JU#~poomTgI z8M9)gOfnpAziUeqDYW;>-bpdVOC(wj z6Kt2*u0T>RQ|gUbX}X`8M|0Tlnb`6{rk9I|!BZA5}JWBjuX9%ekdF$W>+@oGyXB4$>uv7NC2`ii)AeTr=;Tz#$& zay+Vp(o9m}GSlbIHtF_uj#WZJBIAO?9?uDFg6C?_+zg5fiSRl)IUwurX>DuwY*P-q zS$>tj9GGaHte;)_Pn!sg4a;(Zq6bJSPnEb-)c?)zCTfl=B!>b44RCJNHa6HSkhMUjolxpYii0!t+v z8L5rWhbf|49C{zKL1H#{1YC;%xu)`YMR*ISDheK(iB8&;1pK8FUwi^59uF~u6Gb#UY zr0~wyetM84@aQ?qO}?y$;GmCxvb)II^?4)r%RszIx#Ah_Ftw`d9aO%nDz)$@<9mRv zR^x(&=Yete4Db|XuuBb+Vlb@@eyjO)2*J|lTA!y1R#blnKn#>Tk@r3LDU{2KA!ZH6 zOfA9Fof53q>(H2U20aU#fF&73Bk>#kt%CJ4=^V4~4a*g9A@vMJKIeQxD!dpU8O;^= z3={rYC-#%e1n2xzRXV9-3yB}4-C7TymW?t-8TICw&_M#Ai{bU|dI%)>;1eQKjd zEVeW$-19A{lG{7K$(ZJ}U+%+H;euCPLWd6N^QM9=;W(+0bfm)l$}orE7p)Qkuy0U* z5HT)^(y83aS-AYAvpgim->$*|?DPj$b6^ky7As=o)1UHOO!50cs&SHVhXgZX9eQmB zt^FHV9i%pm@iC8&K|vzk!6iuQ^kBWq{6on6-PP8QZa@bWTuIY}n+pIS1e_3C;u7Fx zy~#VBjGX$PVA9}_>(PPm4GNMiJQn$`(o*oKFAa}gbJ?i&{y0;Mc!~FOD7U8IY|`5Z z#jIwvX6hL?qbU)w=2Ay5WT#XDpg0P25Q1r{kmiU}1sh%oFf-FOYAn>MRejL?g=NkG zTXIra?NAE66294|wUNmr8m}AVqR6}A9QB=aPL^Y(lD*9&r=%|neJgl2xP?j6! zdbmIOShjTBA+g5HLRKZj71zsPc)biShRhq}uT~W!$l%xRiXsNvgInvWGun^tGVoA^ z#i~6M-Ku__D&On{FotkBnddbMDMnP>ina&%D1*R+Gn-Ew0sqV8WR?W7GUdfjZh&8M^@l2SL; zud}a32}4O>*&p5#k{JEPWz=J{Hhm>m=+3(pP2XmBj-@G)D4|&gjf8hC;&#MZ6 z5OX2C11p$fD^d5zx@%Sk+5(C#?VPK_E7|?x;_v*VDVfIj=)V)YwW^;1AZ@rEiI`X# z9xszG*_RBC>F%w$h9GRpd{@ql0p4>$t80}oOjq5ESwSv%i>Svds6Ta6jgn#l8uIVc zmGYy+nZ^rt`LnUG66AAn(F;-L3yys@)r^n%3Kv8%!%u+_Yxp247!t`Q4FNq5$XMCO z26?929Wp(CELcsGz7pP8*yoduDajTRJbanQu&1$dw>w0l;I{VRh~ z=nph&zl`0P%#|y|eZ2yW0p$|&ieP266Pq6P9}cfO6-V;~@`&0`q)Fo=A^0;$+Y_xM zfaL^&3fqHa-8lWWfV16yhae^are-@fj3|LO{-Xrm*TjA!b+AdmjttnC_SIV=CjP@R z0bLGUZP6c0mSEbH^waeMS!`AYSPuffewMEM1{El57^OaD>!Dc7yK!*TeZmpL118-m z_-m`gt-i1mz{#$+DIz=dQyj-k1p3EE1p5fFVn>9D*wY+9hEbZgC&H6KeoUQ=Ku!>D zN6dQZYzb}`R;kI~vR?4zlpBhuX&D6MQV4{66p|=2J9C6NupS$&Hq-V>s5WbupDT7lw^VDe*ew4TOzg(+^v6^qOu-#j#t@fRkBp< zL1^j2;yW{`5?ADorsEO(R?OO?R{RLiiDW=05-`|XstyEuGfrCPwWTC(A*gLZ_0}_N z9)=D;8Vk|h-V(na6H#dm$L-~MN20*&5vlws4|;3K-#%RYkiG(%ID^gsZSORuCApV^1mJu2fGgJ)_ zE1bec9{s904vg9N0IhaJYEvYGoR-2hZQa=zrH^1%Lf6~jzs;=5GDDN>dDUKv8UT3< zv6MUtmNseiE4Al=#xL%_4^|XTM~ai+ZBfU5J(D{8`{PhL5+_qWkPd!q(0{_zgGdqG{ z|0hbuwcF(I5jHZR5=_3a{`{0x5 zd{En{jXUSzHGh3>WZ+ZIakJp{)2jE)<2ri1@I`4ZkP0PE;Q7m)wdi&MA92oJFSNpAC} zW>%Ylmqmuv%Sv?CrAt)8gg{kjO~9csNr++h6(5kW}y zeoOsT^bMi$U!ip>hZQ7u8QY}=M&gcmMd}A@|?*Le%e8r^sept0U-muly zgbr`|I`dvhBP{)@H(-tJ3|r&<+$1}=nhzdIIMq*g_F+KUXYXoDxeGAC`Ofddn>2lS z^NS9?!NkAY8~c8Sb}tzEBq`KP?!8!NLJq@nJge*M3whezSbWCk6Rgx-ib&$`=>IK= z1EruY<9^G7D^W=2_Xoc#Ac_t0&J`9e!76Wip~d-G@R!8NC5b{ldvDx$WWID#p3zR< z7;eP9>2Vf7LZ|~|yL-5smTAl(Mh`AU&0v#jgS@{(Ce2g({9JX^f|bnHf0C&vDy--& z1opIQ!ZZls#d6$QEWB05{v^*S)-YZNfHa)|h+tj&OB&vXII$o>AKt$r(?<31rHfgx z*Z-AuUm+j%$uN|)9IjPw$ICFz)<4Mb{ni;2@+0#EOy<9eHf}D!ZBH3rZb5A4mW8$!QQfj05auA zW;qXDJU#*h5jH#1z1U|H9NkT0jH8;}bjc1w#+9VHRyKBbYP*K zzY%A@%haxXtx8RlI|50{8HDbHAM5b?aaIRBP^m&YIJnKd6jDl1Wf2&_-8Ml+28h#1 zzddQj?N5)6(gFNgm1S(&j4;~}`6~6XppVYc2o6NA%#yXoQGQq(K{r2tLbGY74anG2 zdzBc~OLue7JckIqCsT_fvE27I3}1e{jt6tmp;hYbTVmte|B_u1KnX#wz}oSSn0XOB zVU#6()X-$+$OA_qC(nf1HpwaSaxif7o#8KIW2>P{g z?h#=Wj&&NR;CXsmWrupmw+@(AMo5ZJ@W*QrhRv@L2on{zB0rJI->*oScjryGdJ0)w z&Lb&SM{*H^_gN=#2y9P8cz#tNNr0TAjTZc9Tx;gXSw4U=u0Bvpty#iThr3k2=N(3A zHN7?!!?7!)Qh2uuc6F0<)wW%GoK*5Jgl|5dMmF{8wQ-lxE{IQOoj@NVJV3MX>Sg~b zbNjUv4Uc7%@adPo`@h*H>Myt@&p=4jX+n}pV%3wn58UhF)MExd0n$C8F^|0Rg{G54shA>L@Du=D3SY*n7}E)1iM{DTZBmd(S)aFSCJG` zfn-TATGXd<#kdrl6Jr5JNRJr`330TIB2s-*j>{s8ntc7FLt43Ij4Ou%_s|DPA`zruqW zkD2gmoAB3Gl9@aBNkws8ctR`Kbwi&O6+9|I3wy{S^L8&jSo@N=mif7TSz#vsJDWKX z1AtHdP%F;A3U$Bm!8-{EBGQR;5NdD=Ua)03kWS#X2)H9TZQ>CuSB)(~5TO=_0Z@#5 z=EmH=CVpOK$R9ABzQ3LNSB^z4cwVXfXYM}FjSgu3`!H%as?U9SGk>^owtiuEYMe&` zgs{l5JOIzcpn_B{^LE8h7;;@B&Ej_lvPVZJ4Se@#tw8>ntnkYxe?#}#Md=dx{&s~+=S%t$%6-#7F|2JoVJJu0s_iKOg>u1<} z0OS)7g0%!fhK=U=CrLzI{W4agd3c~Mrqy^wVhbc{vwm+D6yMOK3pA!vY-Z!crvwlT zIU?n0E#)$@y3wv$cXKFU#|bdGNBj#_yqNww2xjDpchCV}_Qp$Or&3eOk@i;mQpE<+ zapyIZ{hN;Oj~5RLpWp9=-}Cz~#d*L_8()WF-$mFS?6MJ93i(XH^zh>#fJ|nS*^cQT zgc?u@f3IBpi|+lF7$qS93tJE*WStsqG`0q?*RPAV`S$6$I#qTOw8x~y`^g-K(zln{ z&M+5{KONC=sb)X{Mfbjzw1VYS}Q0{A?h0T-QxW9+YCq6d3^$nG4J1{{1@8#5b^lk*g?5Z7tm6CTjv1o2mcCKE)qZqGsr*z!c(K zto3Lw*qY`b%Md|}zJ1QNdG+Xb?y+hQ#XCKgHsf39UZce4Q*g8Q=|&8?kJK0^5`D{& zHNZ1AM_DU%=V@{t9vk4)uzouZ2x=3&wM~Mx(0?%Pt!$XTV9cJltpt4{-1H!;mx1J2 z>*oRJScw=A-XMRGC$;CLi=x=nLoN*Q0d5kqGiVRV1+F~4l_rGI|7|{Z(u$TKN5E}9 zjvFo{T_whVw#pwpjQ+F|}qFBV^kyHLUJP6-d!uuEf|CUDe z+Z%oEqn^_F<8aUpnT0CjzG7-C(=WYdQKW!H0SkQYiLZz6{r|HAKHlh?VwrbUOBw$! zsHJ`av`in+QnawI{aAz0cWUtu)G8uXyOFXG=lohIaW*&$oga=6RDOvX(S4rj4ej1u zjNtlyv3Dx{dsVn;rEfBX#`bL=|9}Kn&E{h-T;E3MclJq1x48s8mzBhzK>b+r`=YLI zMujjsFG2`30K%yl%oTYzI4mod!8U-0LHCEuuj@u)J(~w23}6dIri|C3QpY)C6~s`H zix@VUb;r50-2Pv^lF)~h+HJ=`MyO`Z_uV|QI)9D76jpRa>8!nhl@IyW2SYFglP^Wk zGxk#%@a}GGC1#V6Yb@)B(h64`oDHK_;`tk-VND z_6IHgl_-5@ii(aS>HwkN*!Bus3kzO22*BmGD>-6QTvI(dJDYy@?FSCwMmbDD~Hz$Bvrta(FA+cZWX5$~^rC zUAONPbw;G{0!RYpa$@D0;^3U}mZ&vs45!Y*G<1CQjS*_9SV|SeEFmi~A5d zyRYI3-)x`I9EXlu!%;{%o0ZRMibWY}lY@UUo#$_($uy^a?f0Vf@G>RtJ}!~Vz=hWS z7j=py@-@L8i4x8Qz-#vo80~-uWBb-NA&l=2Lj;{-k_dj)|DX8P|Jwz<-VOK<{5shd zpr`4e1NN?THzyevf;lL*T58ysZ=dwhq*6`nlzNr_JH4p?%$4nas6E4lf$h?jblvk( zeN*Czv;q6UbpIZ4p+jR0&OfRiu+#eAI z0#~XT`dO6cJ75<+P#r2>?0R_~BB#b0X++b+7HFCF zhdK|Bvo>o2#!sp$d0t`DNoApIqCF_KJ=o^WdMrJU^Lp&CSjV>XHS74}W(WGVVZ9%; zC-lVQZ&+-u6&lU{;{V{PP8ZsAz^d-Y{8}r7kZ^J*GUmhdsL%6tF7d>Wm}i8z=&2~d zc^99-g5HG(?W}tiJ2yw7u^a6eydU!^CpNt2v$Viy2IQs{Inu}m%5_QLUdl`KaFm;Z zlU(S_5&syI1^pl@X9Qj{=(xF3Sm8n1qKZM*##8O?ex#IPb{e1WDoU0nPGuP1LLsH3m?lITH;1PCt1YkwUS z6kZO$J*_1BetNLuuYBk8kndP;9x>}u@bmu~xbpD+u_LdVV}J;4q`gHM4T3`VQT|_p zZRiN&%Aoyx$m#u$K><)TNz%C>4Z@x%IRgcbzZZHX_cFqOJH#hmkNn{WgEf}Xm3b;g zN8v@K0xEH~{$=7q+`=7u54*Z7cUbM(2Zf3(kF)WZ11E5hHjK3**Drl9(6|lF>7GYm ziA3uL!=`q50gjgat(Tdh=pHE?`bi>wS|*!r ziUA$I3CL%wST3(UWOmT9;%(c!Up2BHh}*a;Mqe4%`*!~cZmh2SGKCYOkM3@sta$Sm zUpPDsroDNE>}PD+6Sw7CpyK%3bxDWCxT@s~m4ixHn#8pBzA0?iIS^b`^%cIl=K%D# zkUZebrs8ehU+S*<54Ai=L5mvUV6O?c-s7mv(wc$Np5*pnNz=KNA%`uM4^XMfIx1G3 z($zWHBY9T?Nn-3 zb&#i8*t@sU)Z=ULa8(T6z7SuFK)jr?P5eB#_vy^$0>0+v2ua$h7-1TW#o^;zkk48VkCY!D8&uA1`AbM3E{;4t7Enim)^SI=mj5MZe6mSM5`+ zY0??=pu43PzhTgPOg^Bv`m2aArMsgawJC8HYcuA;u2(nzR8UUC6GysBDxhL)rEqjr>_oAcZgBjn30q6=Em=Mqv^vN01 zNg+7*NXSS4InaA)^I7aYqH)5lOz2POjmM9q8?xNNOPZGtNO{4)DZKpPh{zSa`-dn? zHC3X>Kgj<${(ftkww76;i^jg1x{e*&U5qhdk@FPe(q{_7vqW)&PJ28fEOMS1mpn!q-ktkCB8yY>r0TbhV6LCyGIE5T%7AiC_`LAgc~I#J}bl z(}Q0c20oA7ex5Zxb>l!E=tQ)36z1I3Zz2@zpr~o>qvgBw-PKR41S5H=zEqvTKNmUZ z9q}2$yjK{kKzAyRaX@zVp7Z|t$yRaC>`{@M+40<^4D5}n&C-;%G}%EI2Py|;vyG3; zx__tJeg{PlxJRJ;tO50SYE(n#r|rRcLbs|EJarP&C!g#u>P_QCL__L4V9966}dITJjP5^1MdhQdy3TB zSM-{wuU>G(IIIgHuYJeDW{J=O&cPtiq5@ZfCd=y?VDRUBdo2quh3d)wh#a4<+bBlw z-PHj}S_q+VQ1F`HL$uF;map5&HC(Iv4t_~_3+op>HZ+KeKLq@(vAvH&J2Fbxtg^2E zM%PpF&sNcfJBQLWfcac0U&ydZR00H$1x46jbLc;LI8&Vg_W>=0C#@}@ik<4(eEaN2 zdwEn`XKM6%(Y;y%b1oxYd=iaFk=!oZ9-tAHiJj_89Gx=Sf&Xvnk=%rPBXE@pPW*a#fZ@NfKckE1=9N(Wn z690}hO?KX%(+P2>O1T7()W$Np#(=1Q@`pDq66UIrU~DEvR6ek>wUfc7U{NC+pDQ|0z@}H z9dMTz+Ue;+kCFnbXFUtH!AXu5u+zCqDe;}dksyMbt+#v*>DDu}6*Y z{crRGLQ|F`mkpT-ghKbW6aSJ|L@Ta$c;IUT1c$HMdvy7)5_0!HhQbSjkWy~yup)yE zHQ`J^8-Nu{0o1&7Mu8_alUeMOLcJF17q>-6z8$K+;;_Ei7N^hsZ#d;ozci2nftp7y zwLxzLimUm(ZOF<}%M^taN9%S8IikHvT;Zy{>M?W!(QrnOr+|G|7W~g^^z^4Y5um3Q z_$QFg$NoSkXwq6KPIy>2pDBHtoS4;(@HDmT;+!{JmSd{z3qaIV-=4#pJOhS%ZqsP4IY*@7rLSue;+H{%vrRs#5 z>W0~8JWj1Aplj2BhLdTVjX^yK@lkxN?vAgB_ovEg(XUi-Xb!Fn~SwXr1GOK|) ziASIYuwU(1Ku!+dpM|WR;hs`|trtA0s`W}e|6EW+T*+P5b-U{5@C{4G9`_I{TYzv? zq4DdDiO~4Luo9u3p8a0_CSJKxx^K@^&jqFpgYbR|j~@5EPB_7N#l;$OL8E0q%0;I1>ORa768sG0A(36iNxG14t$1C1+5O-oV@fC)a-hMO}7oq z!j>E(;CkOwG}vv$5}?uaYIuw2`Q`K$2|rV4dJ$B{-#njwX;v8q=Md^cE2eKmzT)OYN|?I{0f%>Fn{&rX8L+Qla+N0 zKqu!*o0Ac^jUIRT8BIN7$?F$(fukkDmhb zBCBktYWj`d5qGTA^Ut%7Xnzf;APk<*bBCUSURNmgQBV(-POykE9xnkUY!vjYJHD0P zc)8tyj_`;!qAz9-e}~3OO=Q1QY<|#7w2n={q&eBOJ%ns4ME#`1`%TAF(JdC^T{Y(h z9H(3OEZcIRagVw6x+Qe8c%rkhpcH0q9Ri^JG$FqpsNjMqaUa$Ilf$M5OzxoMnlB?h zGBBUM;>!}T1-k;ddRDx$u(rQ_r;mROXf|e~X!?PsRbbszy8DQYyyW!gIq{9}piv1dy^PaDmd(}&#J z>17bK7O6;Ver+_l14*ESY;)RsSi_d+rB^jrC0BMnrP((}8kK0N)lZUum$~qMy9qXm?U>sVH$)I>WxR`yEk2g}(+8L!(B!F3;Aaz3W!#;prDg48Np0 zi@Uyy<{2dMONv_fA#sEjO58Hp+F3X_%hU%PewBJVV?Hh zOTClf>_zj9sy)9Nj-{%_VAVeivV3key_}}rQPP%u;*}+gA0-XtUy9`aYP%OvYmIzx zU?eRa@oEe+!|v<&*TAFtM$2=rV~NgCI`1yqoC||XdV$@Zbce_D7yi7n4s8U3oL;a= zi=Q|WtvH3?>}S$Os}w)lTIDIqq^yQ=a-mH?-z-*$%e|~ z{%wGuDxC?4+FW;1%-;=FKJK=ArSpl1zc2)U;8WjB!@@vWxJ$TKJ<{rgfN=7~YSoR) zpY~MX_|wE0N!a)W?+qRa@Z7(vZ_5=q;qP>y9{7Pz#J;a)oSyrR9yT1$vfHcC_0peM z`WmbmM@!%772mD@b@Dr?XDvvITODo+ziqd&GHKyAJ|a3ob|c0SU5*yQUF=k!>vkC} zbz+%Prwywe*jedxtsB4FvqkIFyO8mv#=q&?A`>%&`x9m-|870~;qiT477t$x&fp1) zUl#}A62}6|s*D2XhxQKR3tMOWA#La0YSCxLTpVB5TQ6qe6DBdITMP7;gUM?pzDauE zRVHuaet>uu|XtUBTk5r?8KR2L6nYRCH;ls^N9{8jCm_!qv&t0s-}?GWf5J}FA?xxC@lM<4F*$xAf)8%4fq)96~HSGWDXe- z&7aCx(L?4$gv@#-j?WHq0G&LHH((0lb*On6T_EXl)j899ozY5Ps8w~Nca&C3r{`7w(1Z1-MFy_#GGE_rMr5DSX6GLJ_C0&57~f#{(kvh<4zX-{#`rR$;_H= zwhfK_*6Camj}8zTbR8`)3|eJxV}_HuZ=gkkOey3w;5EC`#66$U@C{QxfB%cU z&j=auDm7s?tLL|yZYQ>dtRhxZadS%CcuOrJ-JAMB!O!&f>Msn3{ z-yQJZpXDk9j_~?PLDhrtMXdo3T>Ebg&y;cLv+O(`4B;Jf=qj+1bC%wpDAGSHo-3}0 z-Vml(J0z42yVz>F=rM5Wkoa8fR%5}L;SH@mgPH8as4o9n&xvuAuPpaD7}K#&->IH! zlur!UMbvHBYi`>4h(gxQ#b$o3Czh?cEdgG`ixJ!lP0}apj8eW@R<&nP_7fq$cyD^2 zA93JA&qCh4hsa&~p_xEo_({=oppxw#QJ)17B#QnSwdHV)JtW z9_b#TL1e+UmVE=BuF?5jBGqm+<#T9q(=yI^hZO6)AHYxXUw*JrrR{~CT1b`WHMxDl zka~jKu3HCwyU=6OEZLDeOl)+C#;&HN*p$9vRima(x~zBgRkXE3Bb=PFMyk{p4&JXq zTJe+7`o%ovxW(!2CA#o&E4_q+2Hqj!RxBjj9KpfMqmv1qTq2&1=%)Mt+ zQ|tOKDqT8A6RGM_qm+m!MFIg48`3O*^df>%0@4X2fFex<3q_DFg3<*EJ#X`3ecPdYyrIDCH-&k$`)nN zi!xwgM;kHy9}=`s9h7cd17wOrfMUB#wa_U3>)6jc8VzM+%KVjN5AE(Lj>Y*wd+xQHL`3Lrp{l! zP*HVs1I$$)sTN+9U^GRBI@oROXJ7Ku;4K5?=i+DD=Et$6K2!8a;X%gotsjvk#G2KB z+GIUj0e(#m{e%uP4LZ5{$BKl3j+MjSQk(eD#Q3mvR9ayxC)lK(V>e4kbBPLD<|hc$@cKM;fqpXAM=$^neBwKTSUZ$wde?<*hum9y|@KpCzv03VYvp>Ten~W9Q zhX>b#MN~nsT>4h+zt?jVI%J=RBducl$D#T$=6(xy%y$Ya&p-#b4l-Je!FOj~i(Ahw zdSj7>cV?ssjcmJMsBtNA=~P-(Xx?kFS+-nTvE33edF;jAH@9`yf7KS@TO8rg=C*vy zh!eURBFGG@7P#Kb1;rgP`xuDN9!VhjNSqb~V{22{ETg4V-*Y+fMWu0I+7rgdFAu>>Dkj@1D1XsId;O;!2#o?I;gCInVW3C(AZRr4KX?WOfc*=!oxR@zS>e{C0DW z=Krk;T^g)Alz#w8OP*0voEi32Kw&)ombH#5igH+%$WG{Ts5K5S5~J;|ml zmnIGEDIyp;j!5n8o)MEC4+nrB`JTA-NyFgR>=Bi-!d_>YIn~cwx!pMve*i4!n_LlU zQ@*T1wzb5Va4;ntKZ6Pqe!!a>Q9BW#Ll!?b0katk7>vWqlnrzU+$C&YG>-C_dpl0R z?o0_$#Joqk1&+Wc>;}rJJI=LNuJ(-J&!Gea83)*Q*Q3!50VNzeu_xN4H?6};Y6yGP zQgh_G!tw?~Q&HpmkX|>R7vmiA9SP1Vp2JJFxdp%Ml&p~hV1}X+o#`)h@_ZR=I^?vH z%S##DC(E?yS&*G01g>+z_rsP(HotH3vFA1dll_WnE?r~cr}Hfn4ql z5s2`i+@C9Rr9cC7*za#-C&`V(c68|~U0MjnY9AdL#v3zTSblV9bR z*PqD&AC4T8G@P)$n;{NShwV%}5snDo$s&cq_tW`i*SY=VTA=%oGgAo{J&|}&j@#{B zHPml<)Z_ZaH&#v$GoFH-y=UZ{@kB3LWr6cPGlpqPocQ3rDCClKNylRf>2do}l&=Oa zg4CS8tBKAt`x$KGvtl1(=_UL)PAEw8J7@x4yfgRxLUdouS41MM3j*LO_;;K8UOztG z&aRxYQtLOg*v%XSRx75KPFLtAq%4(N1QG<-0*XV#hcn&GC5@DdOfFcaAC53~xN6z) z+Ph}aJkVvf5Ahj_0zn8qQ0c!`&$7E*6l0C75*!Tjg(bKfYwT{O!tq;WYtfQjv3bKT zD!uspi{nM_B${P#kc+YT`mj0y8^w5gOPdbTQb{2(w6`==+%KmSm-*u2P$zD6&p*=# z_2c^Z+IM}P<}-Kr13=0?t%xi8(wk__H2JD_Z4dAsz6x1*_KHWG18~c0%zD!Jz8(R3 zFJ0v18^;d|{@E~1-rPY@H1@bK4SlU$y{)&! zfTMqLe-pR5l8Z;GzB>zj$pEwD&eg>!5NOfx!L*ym~37LCz2VI&Ov`>8AP~gadI&q5RU|wb_i=YuIS^tS=^C1diI)%G;|0Vai5mr$| zgHC_x(PWxHE%(gA;kM|k(Zy1?06$AD`aLoFKk9y)OF)!yoJJ=iERBBMI5FB$$$|R= ztYsB1U(#m2&p658EJ)`zbU{#2KqBY#gt{1O>l<(@HLp&H6fGYN739C`u$5JRXyOZd zqg};BR-DC|;ehBJA=U-8t!Y0@^1`rv%7Wc(Oj2V0Er=iIvU*f&h2^<5c3W&HN5V<< zdm6k_@ncj95g9S?im+6IJ2-k8C3Tcd7ZNv77r_tX<7gc%xb_|kv#lD#QnFC%9T?<( zBsYbC!43*G;VSaWhMo8#T(ZlT?N3!M7b=zZf9apmsshKg-6e7^L_?M>Zk4{^wmxhk zknG%i1jX8$-`gB~j7=Hf&9y{R7^f8EQbDuQ{^#$e*wrd%bp2E$x-F@ZO<_McoT2z0 zI8y<|^@`q@q3T?3K2sChu`Ul z-9Kz~Ph-8FMPiL;yJn7D_B1Qr#VemCa!S1id;%^ar>V2zX7e{_z=AdiDs*u!!ImshSDo=LrV1qPkxa0s4LL~L zbS=fNSzqCzvEB;jV!D&8xJNz217<*+W-rO@V?vaJUjR~6x%y1=jY8vq$;Tqv|)s>IKGfgB26_cjr2960pAIOfTchaf`l>498+;mB-Z*cbx+u98*Fc zthu9F<0_a&88+RVYPL`9M_l#?J!$4h*~pria-L1YBVo}=-;iw5sT7A-Np_2Dj!HMrWvh6h83DduK9q*DH^a{L2V? zgnS8Afi#>2#I;FJK>))nSyK1=>*DP5o+^{KtcIl)!m~@ts`RRF9)M!&3{5(8_|F+6 zG`X$Tc#|5=qTINp9Q@s9A5LUR+t!}&PLz5#x@?5Eez9;vvpOa_3X})>A@M~sbcY=a zj$#t*t5!ZoN=*B@Wc^AHefBPG^0|DGm?D3m;+W6tC05_|5)-@(&QH~rDX-w$-pna) zFPwJu=&+IU26osb^}E{cSG_&LVj)&-cvHUMz`{WR4D7gK<&hs!l|5d=I-XF>!R8y) zkb_`Ofqd`eYvDcWIr0tTI!eQDUB1j29al862;WuCMzjVnGQAr09v_X8%9FjU;W6rI z9)xjya>;CMgG1DZV3mNJJaJ-g>6^dZ(Q|hK=Hu);PUpomOGxva5(USqSc*-22HQBq zyjX~U+E#!^HuCGUm^tc_94AxdF5a?>?d+*{uEC~9Yd)`5QT9a2mw&>y$6vxl+fGHG z%HxV6^i$mrD$i92@(Wq`ba!cd->j0sjmOL2Kzo-~75~gWgA1a(HekCh&u^dPY)CzJ zV%|n;N6>U8H}(tliiq=k>eYjJxqE~G+q2NxHH)2a{*4U{1U>pbt8e#Cdm#IsWB!*o zL4 zC`ShaCm`Uhz{m96(mZdsm$eD7Qfd4!5k*%<<0t>Zhi!m=9L>VO9R=o+F_wS$!4s_g z3UeA+Oo4;Nu~SrU$<4hLnzX0Cwx|(+?~i@JW@WAyU6&^xJShYgT5;UvZqCo{sWB5W z4*51w;Idc)##bUdw>X8oU%4j18fd;JJxZ}&Ir!Le;xd>d6)+~uZ?w3kIrs6UC2~*>FyK25c zSI5NBn@n27_722IyXY|mPQEr)oc*;miLc>?U@YHjF>QEsYWJCspfFqEz^gC@xyEne zqRqimq>)D#`KMiB^J6m+%Lt_xDl3jFLL1RLt6Bl$lG(HIma?SztMFgW*k$LE9f26* z`Vh?8)OM4#o`tz!$IK1r1*&m}Z& z4mcb)`U^G1N<5UJvJ7gH;A1K4Vf5l$uv2aW+!FvN?!m^eYWc{B9>acQ(rWVh^>ev~ zTMd*{HofoFhUlPD_3oE$bLA1RyAQs%JEOiFD--61-*4F9J{$_C?$+!JdTp_5sf}E< zAs4en^ypFjybJy7s#^N2^U9>fA32+162*v4qC3;=09Tp@CN(WeMdtpmbrhm%BI#xr zST+<>f{%GY<~LpB`cYGqx5#ATwHqohf+y1MMxleQA6xGZXK_?nGqHi{0no!9$1;xxI_P@5Eh3( z9|NW=G0yU2lfSW=cwWHd6Fdt^r}2>i&B~1O@18&ZP%wA_mHt;>21NY?L*5bB*D^T8 z^1GMqD`PJzeQ?1fgM@e^zetq0Jw38H-2hcz5W8^vUHbauq-n~N!sU^HqD%Vhp>}5L zc}=13+t?I*P97V(5_#;KO=O6SlX1W~fG+LHyadCkkviy%@yDRpD3gxUo73zOq3vwV zul#K<*|u-iZ*VjxAzor&jyr8ihK&pIoPcd6wW3owzJ4Sz6x9sg#Ba>v=jGJxdUtWErQT#}av0bDxKgZ{T zFc%C_ytAZMIw|Clr?2J4sQhy+7Ian?>23X~Q~g+!pQ+pyVBriRET4|s#k)i8gr|ig zx-?$iNKG%FxWqmTU22wT(3UQq>3WxbFp&PlcVf+M}m0pEoF* z70&G|5;zPsudj|q2R;o`+h_v~r@&U6w_nfxCbPl27CB={&U!9H6PKxif&PdyW+V6* z9w*|NJr#%788uCjK<~F&-1&(G9JwXoq#;C}9!z38(eaX--*zv2&S=SI)?&S`h7R`& z_A_6ph2W87rTcL1?Iy+%FU22O(~ez?vv)|744YONuQwcO-uIprv}ghL^Us7P^Qt$l zlD(a_TOT#($C$NYCf}RB$WNcr_8Aj@^P$}F^gz>>^L=snqPvOg5!R?2bRMcH;-P4( zI5IE)X^ZOQr`*D_RJ=vH>r`sI&)crzR`F${JAyy=RfqA-on-qIUxhvHP~{lb;6>qK zq~d@T17gm7ZzE}nF}P{c+BBtCkuu;h72b*r!=x;_%ik?X^*PN`pe6bV^NF+@3GbVz zyP*l2KChM#Q~M^Xd{($0HzBqX*Pwkb0;lg!UbMth0ykBu95)Hu4eZp#6i>ebq}p*q zIM>kaQBbaRQk|G6l_Y9lt>~56{jW>F)x-}y>z{4&p`DNr-*0s8Wf6|~MEd$O#2+s- z+uvO64(1x>fj=@kS63<|6=X=6gSL;{fFsFGdOCeeP|uD9gHe7~Zio?0DpAmZxH!x8 z+X*S@znqZb;09gYAI8x6Sf%@B!s7oQY6%jt6M8jIrXw6^-qHkV4uLf5ETEAPCq`eh z{cnv#67W(c0xH)JA3!m6$pQwDqPdOHum)`JYgR++>NiYF(N1f(;_xHx1qAQhL%+ms zn4G$-q9hApHuM>LQ~QQV#yIwA17Fz*>ereureVo-ZDlT52#QdW+F3U0B?27=O-za9 z{!~0gOUj{+?FC@`4X{Pf*r!O@DJ=r*N;PbPLXudc6g9iQ)DrY+{*YCj4_qRy6r}mA z1=Z@^)hIUZ820SfYu{{N6YSg1lGb617>M{JR|h3wU7_(x)csA^sU~%dVJ01}E6KC3 zXpc2FN5A9nV%?cE0E5+lK{hUjG|7$F&iy#SVtT+AIr&2yy6jFbJHQn&4OpBWW{9=% z*!0dT53k8UY)ms;s9Xqbi_u{*VC(v!H@)Ww1X8*D#qW*)zrnkznL{a##C9`Mrs>_X zBBZ#3TK^DewwXiixdkba$4WIBS=gfi-r!mKwgmIM=1xX?uuYiv-hNZkc<~`#7MHaF zlW3XI+!{HleV5kUJuu=kUrB0N*&V`i#3+a&(%xI zsFsCKcFUm4?vazkVJaHVXcY zt9un$z~i{(95Y`|{^lJD0EtELu&@rF)D88k9SZ;0Z>9+id7Q7AGx{3%l=nbF8;yT6 z*YNLdK{OkX`Kdid&1AS*>J8@q=Yi9y|JQ-j1vua~CUz}eolZ8>pK(TOW!j=8bQhM~ zal%!m;afgL7^LHSCDg;fou*wuZKpO4&YlrHTezxwr0&|veV>P|B4cL*o(U+8?>{gO zrwdqSUmTbU6;M{%m*=-ro18r|5D{)GK|B`%gvZ>YM9!5vW`nJ!3B@|XrmAkRHFXGA zLB)fe*#J-Ctq991nQ^~&kH2A-gx!tIJ!6MkRE!-)0qVG9cd$0i0jGb5eQ)9Ftooij zf28SagMqpmuz>K6tauA21P5p?jDEfh5X8WQ#vM39c%Bpm@W|~*7{!>k+Z0_PNQKii zM8(Pu+fc?%$i!0SW$Q9ozVIQ5JvVA&p9>0k@g;-1@53%WYhjb4u=g#k2yyJX_pP6F3_yt+X1l2cu5%dh z6WpvKVQgFFDWNXD-xv0RZD!-}!L{D%*>7ZUJ{F(m&N$hl67$~I#b5!i?E$ql?Bi|B z7e&kIp&omOV-k(*5x$fsn90MYt>arC6n$f-BF>Haan;|D%3mtWw!o(b2^ktdcj#6Gi_wF0C7ls(kbF?Ge+T{VHPuiwm5snaQljkSL*%NQ} zr}3zH_^A;b_BomXm{PAw_0%g2Q@k^6*~5Uo58!A|a-SV+h@NHRmVd#@1X}&EUUP2< zJ{28g*6xOC8QR#7!&DEZKqKycT&%*IK5IO-G|8pnv}%FkOA(2%@67NCkDc%%!}jKF z39s_srSEsRb80!F+DioZ5s#xe24t{m-GiJ#sp(46Sc~3;De>A)1qpAcg~=#I{h7VK zI5_%oi1{g{^(MZhbs@)cMIfITOeGP*RorTUU(s*(Kz{iKwVq;=JB}l_3l-ZX_|5($ zi=`pHTY!B=)Ag3gMTY@-1?UT*U$5Q(#+i5)d^8Yy{9j;g*7H}YRZc(J&c{dThzsYb zc5PR{`}Jav==oeS+V}os>r)|qzC-&HPlzP@pVrOK)p~Lh^kGIz>7nATLS+8Ip~|P` z&}g+oDSY8KRzJ5_2;6?759_cnatE1Z{j%JBfO2k`&KG5{G+*aefbVtRWogJaebTMu zbVAbb#tN2-s?{3?P_nYGi!b3s1ZvXxoi%ebChcHDyd~=1bq>Q~*M?y*Qk=m&%)}9E zy}i7C8eAP@QtD%Z<)s;SK$qOmrPd@oD2bjFX0aGT7lQ77R4R&CtQse$C~%W+o`%R) z&S!l8eyow%hxW5V%$TuA0KhA+?)3=(U#KzqW8-4K}ok6~L27H~S! z2=eYjd8#MCZmbD={WaeOSkVb$%PBSGF;)HZpWH?q4NaY+=25$i5@R+9GH|4Et(j^* zXX;d(g+c8DAP7!Bzx|xF`qLTHNf;w-S^&}v<=dcn=L-JD0w7JTOJxM%lMxh{*{3ej zDSRaBZ@lDU>c7xm?ae3qlMWG5=-M-MC*LcTrv{cB$~mTFq0AlixAkSn_sw<>;Cb0f z(`8TiV1W7TLpm!jr)FSg@-OZE+#=9T*yXdhn4SRxA!d^IIHgXno30 zv%x!5BrKBx99RG4eEVBbMmypEX{-5<=j?xI5IHxK%=AlTa8t%T!&}dK{X?eQDB0sH zD^YKCUgXaRy*e4tPLfp(m<;ah^TTQLMlfCF*`M>XtOKvYF{r6JXwOcw*F-&~Kn!tM?VEEU zysIWl(3H%R{s5=nvB`~Y-i?`FW1ia=jwt9dbL;OD;V~@x#a2A^NhgX5YNKD6ADOO! z({o8LQ%9GDVAb#F5KhfO)qsa+L%B^Vta)K-ei|WqMZ>_TOhe71-QBtzq{S!BGVotH znJf{R364P2b6k)$hwzHbyk(n8&yqSsZWFvKwstT=Xo6Iwh$DX zH?UEFJI#rc^B)P%Wq%JgM+q@6C7(6KO_uC%Gy_~<1pCuQ|2Tgd?&6~K`19Rx{HiLo zfn7Y;lRxl<@*KolPq_=xdR1+$m0o5)V`mdok{78V^f|0bh6M%csu4X0{9NF6ehOK+ntbH?Hlw)_ZnqG4$sa z*0u-?X&UH;Zh~pS)^?MgyAc*K(@Lr7*eq5 z2<)4Gdro>Zfgti9X6!4mdz;-GP-bEG+D|iixaz$|(RASbc1=EmVyq?#T265R{!o?} zv~`dmoA9u+Vy|}{^fG`l!=)#g4PFMhdn*7G?u}LWjb7%?6%5n+71*7EXB| z5d85ZE4vIqk)y3pd;528%(X*7`0Jzi2zrR_R3O!EMEf*lDdlAj%ZE0_k-kCzv(zh+ z!Ed?aZdJ8xSB(oG;s^-;zDw-$iiQ6=kw7I@jr7^&J$klu4Rh=e4nZEor4;z1tidIsbXAt`pe^gY zMSZ;RpIkhh)*)atuf{xVJQ&IllF>LaEmY*kEyVs_!Hw+?wRTKrB~-oY~HF?>wYP>B2@msGGO~Ib^c%+gOLFLx}Y;G^DfxA zI+%Yd#pjjf;0uxjTbbYTG`?3E|8B80um`s3Uq|+@8dzfz@*k(xA3#F}P^6Ejl?>=y z&kt?%K#i#M$dkxixtGyBdhkZ9IxAdc{khI|D9S{i5gRIj>auXyEJ7X?MwN{%q>y)t zqXRm~&-b1}2ZB3_1d<^4e@QHzWih%pYpd(Nvn?zecJ3`_zu#gnH>=-i@i^}Jw*2$o z?BAkXcxt98e}tv>QR!D0`I(RX^$s{AIZr;&v|r@~0)PKM)^7f1Xx47w;}rOBrPOBI zZzG&P{-8AfFWPbon~tZ)LTZnkIsVt>1XuHp=}8KZLwA$k(A0Zx;2G?oQ=in%91e;* zq#wK#{7)I-m#%YF-e9+r^?g*PNYrO#w^4b<{NO8gMEM^iyfnW^YI^ z`C~4}xRi^Civ?bxHnp?&lAj~g`M%8hYGa(aSoCtvi0YgbS8Lu$bS(J19Prnc!0bq{5P+l!(w7L)VE}fmL5z6~O+4TybMk zGv4VTf*xAk@+@p|7NE0mpH>*KYP_WV74*c+Y!R_Ied&2_(#7&wUwOC*&knhL|Zqb|^lrGEv7+qCIkE);jdN zIR7!vkR^Wre}2k%PF?E+z||lTiw^RH@2?# z4WM1q@(-@HvF52Ym)vusHt)p5SIm9-)*cc9_yE?CIpqg;N_%wInOx4VfPX(n9D(#p z)XoZD^s2Z&>_5dv8N@a(N;}Np<#GFE<7T5&Mx5{ej-8}bP$`yevQ_(! z-FMcb5zf&++b&Ea%KNR_OTKCFZSxy`Q6$ZQFT{w102gs$ z#2vSZeg`3lP?D!{CjWAoqB+dX-sX2A{MN08EF6XbL-C)Aadg5OJ6A>c0PoZd`21#1 zS}#SaZc~PSleNnu-usci^Cm(@oVsG2e%rshQ_9gz;yp%RwHnGqCax6DDiXa3&wb8>gY6m8>bip3y&K4aA$s9t26i?PlYPEJ zsDgmKo+=VvFoSdY%F!BVg& z&H18t+buVs+u?ZpX01{xPA_VQAM4C7rCuCc;j{lW|7SB9uQI+{;Alur3yOW~Q=42c zcG=NRqx)^0Jj{~#dA4-b1BD&iAN|SyFvx`^(e9CZw1|FM>oQQA>yV$$W=4OEuXmVpitp8L$H}f-F zGd-Vf&KE!|R&w@*8P(B}^a-6J>ESivb~Qd%WxZD-F~9)_eoE2#-gbMvZogF?hTZEe zj4Q}##ECxFHhPr-e;j`G+EQ_={YVLPw)QxeTfj7DukpgYYT0gliwI&%xlxs=+*tqV zD3f5qIM$2_Rsl3gV~cFDEF7>a3<0iI%@+)Jr)z7Q4(;W&NlL+mj-S6734E2UYjcMa zIQ`N(AA~{%$c8unH^(HJcdBpTA2Y2?p`nh--)j?STZ#x*cD0%=h=jeglVr@B9Q<8= z56CUjd~e@;7UlrXZ<>_p)fUFVWB*fsqpEisfoe65D^9Vg+XHO3$w2@M@E6xKJEk9< z`b|a$+r$2l(GkDRiw!Q`01Eir2A~q3wh9n8f3tcmJ)c=zZdmM1wh;fQp&t4TW6Y>) zps|{7O1jeFn0+{tmp0F@&h_DOiUL*Ar~2#R+(X67va{;xi1ZMl@2KUn4b_dd##-&B zvcDu?M_U_wQbuf6LXJ{*TE|NyMm;gmBK7ek!_d=DPhGys`UsW4*xuTbDCN|sS?}el z=J5BL7u5mNtak4Zj0mXe5^n$r3Fp^ZCmN_8nnj8NlZfG3mDb#Roa&0F#E6(HxT!c4dhzcx6HgEJ> zc<)|+!hb~Z8p2-dJVY$&#KlP2hPZ3N{P%0=m@E%m62MCxI26J2_>8_JlUoM=W!(k6 zz!SGZS{{eUSXW8f6e0`96W=;^qE_G~tH|%|ReHttDB_-X{ue@rvN#r}jNVkF_A^8i zZC5W4SS**YKghY*y;K%T9u`m9wj3YNe!hMczGtxe^bE-XdbD z(Q&9&w>@Vph)2DO}3%jhh|RyS^PdJ3|!mw7pdTnX*iym^Wec7HiJj!H0M> z9MD=)eUEa+$ij~OUozgxl&UnLST4A|g}!7~|17PRqub_ta3pt7aQY#lCj?d1RDE5g z9M|T3R=gzFOJqSBO8=Q_x#av}*~1@af0>V4?)shVzu3vz`D1CmsUII_GME?PDVa=I zTwdQkHA>M-N%c=Ne(Z?4@|Y@cnHY+}TV`?dBh2AwFRZ%X`;bb_=a|nE{OAdE)f3~u z%Mv<^%s($bUqxkD~@`+(b!4QkAw>WiWoRYNcosBBl7m6mRgitZmR6lJZ zGTPK}wLFVekb#edq)4eCD6Id8lBf_58<>6f6)jo{LHlx_aWOp zIvI8P;~F=+bN(jv@TgLmFZ$EKb3x;WY?z4r_qKxkpmY31a8865W0HE}{1DDcvE zl2`dt(mrzJY;#5{Dhb6r@cvGY`SC(*fag5#gTuqCGM0|8#g)YFtqj$N@Ch|P&*!HE zBwsFamy92`S|;7BdOXOHK;3=Ee-z=D)t{>Dq)|hXr`~F3Kc_ayb}f+6^b_YLb!ln! zLHmb&&OLXJc>n$rcuC8Q+45J7pBQw*JRhP9mW{3tzj$UyAQ4R7DM>~bJjyQPFX zFXrL{7mYSG?Gl%ylbo3jdPCgh(H3IU+DzAG{0331m&J!HyCc3FskSu6=tyOLmOE2J zO>7kWSq0yOeyNt6zO6!kNV5Lq0s+0@zrhkgrEpWy_6y3#YEjgxahVcQJeE{dlRjH` zjk38+Y#cP|AX#ac8S9K6S~1=l*Mm>p^?rBq(v=}_`J)$dyL111!=E~S8pwt<#P9D& zIy)qCvrg`)u9JR=^;~v9|ND~LDv|Ro-UeCjtNG zQC%Q5?_73LOqh7(HX9`A(OROgjQc{q5eTPl!llrGZ7BO+i2WA$26{*qJ$JX}IB5l% zTm3fc&n3)ISBRD*^S1<{-evFTAu4jO6G3U*(4!8v!a7;M|5%b#P}ht{^`n+ix0Yom zdXg)kQdaiwR-IJ)2ITihHy5@STIO5$nii4zMy;OQU$%TbFTHE~OSNxH-cKc|20q4} zm1dO}d*JZmVm0K?+dh|Fqa(Dpd}xzU)V8u55}@yH+0lPRrLkRvO}#HIAnw7ag3ggE z0wk|+->SwXa*GnvwIVx{1HTeN9!m6fT3b zsgzB0CHYHtnU%(3+}o_{jee!8l{cojs_Bpy5c)0d*e$d!cIpkEjSlSrI`@P;0MS-e zdWEZ%law}BE1miX^Rl+RUE~FGn+7T8!Pvk7PVU5B@#jg`R8Mcy_V7*73*S$7HQim3KApxsqTsnxq`ci z-7d7`oYmiSPz!@$fRDa z;D1G@i=LlHy9=ED6&=%N&5Nz!WZ#7S-C*%vI@g~RPT~{Q<3*FBdT$5@on^KR=V1

    bnVTFOv2T?6xU(cLB5{_Ng@Kst3_{9z?jL^G`_6{aL2v zsvdc3LOGQj0u`6q{d8~N_4A&n_4E7^P}UmHu$=u+H!%G7Q!*EM+0vY|wHc$*1|O`c zSs9A&O{ zqgx*(-Ea@1@3E8~VD%_FnMnIeL!N% zzJN}1Kp*v>+JqY}PpXvO;=tu%eHRW22t+BKIdgkG~Xt<_^AX zUj4HC$!Y7;j|y5OW|+v4tY?%)55+&E<8kONNz@mWL!2aHYAlrG>=I7qUqy^PdFo_1E7V4T+=Nq1H{C!T-)PlButdQbn? zV`ozAYEXNkt;X6j71NTWGP;--_kNH*{#$~qMPeC~L3Z(8C}z$r9SMyc{9c|aXnspB zb@4K87_OXmkw-G_<^Z3`LoWBv4o`$5Btt!L7LJFfln`8P&2KC^Ch9Zbt$`TMZg3rYbC8t&~KcQ=A+4F~&J_wg zI$_OBr)hts>cIuS?vzpqSBaX7Ew9;P+O|UnS9#Z-2Yia_4BSn{UFY5SVC2_$Ayg*E z8?cZc`D(PBGNS{*NBfJ$!LSe}$nQ&`MYoZwg)i1cXS7R2jUF3&*0C1LE*Cm9n?#k- zK`xDrdi;JcdgZjV*MYj9xq3(DAngb+ZuX3Q$lY403)p_N62BhqHHcECdqq21zY}Xj z00@nvM_0u4cnBJu#4f7iL-yCs%C*PCIMEWZyU)vAL3mFNB+d8A)!qrbToAt;uRfDb z7RWcwttW+e4ws%gBa-=pRQPYtQ0>ccP?vPj_OCwoI$l6W>{9E&je%lx#VIe=%^W#SLY@?1{o?!g9`sjDkb^MQ{ zOS^fTy;X4A<>9ayo#;a~<~Cz1lGJ;J<5&ErYBd~d<#=`H|LW{BjwYDDeqm8U5F)bE zy*OVV_mIB$?7t2%?YkFVZ8>F9rOFilT#B19y+5+IO#b1})eA@))X?zxhtj`-#>7DJ z(&=`#c7Vy22VZLc7MN7>gZHqhbpMl%X_c&S87QDMpNwfg{gYjFVU0cDDRiv<&r|r5 zU!PPaZ<7_HBCXmzdY&pICLBEVGyQJ+r374$hZ-dF^S$!q>$oAy5h$b5kK}-4Jc^N@ zZ{t?sqeJo%%g&YHbqDWI?dVw*p=rMSFQ>r6+Emv%uQvw@`3Ix+LgOzF91!Wgep%zr z|0MJ$mCFI-GU{u4lDdJ1;rTO%)-xY!@a;Ht*1k<8m>VsO92Hc{sesN&dDR~_5ut2; z&{Y+96PWPscNy=IJ}4`P;J&R`106VyUTOdJ5i~kg)#cE~v;?K7px*f8!55b4lRwl( zj($c44^Y$QP_Iu8gm%B1knVi;JFx#q=>C3eNbLKV#Aa-8uw2-Iv+LiX8mw)`;wNWZ zKlf0jRTZAxqP@e{7ky~Or_g3pcVXDZv%$KB#F_ze#-BpHn#4?eO9-WZ00jx={!Wj7 zfxjYcAn_xY(yZq&}DZz<|u?RT_m4 z#)}7fcRZs54r23fpx+^njFj zcrcq6_>e5O`G*tU5pE4pp8R?WI}wDu@b$1Bso?rm=+J8d!%C)+JN7zX#}FTfbGD<@ zd*5>vlK21I|7Qk%0nN1?*6eJ{tQNg;YV@?;Ot5Z=ybhM{7C!?KjfYfnZup+V5Ii$- zp)O?}_Yj&DfU?p*bB&vYixxDO_fGgB?C+;u0n{r`nA6qiKCrr6C%4X`h@1+8`=|N9 zr&^z4R*x;s-zEFg=jlRaW|l(ESrQvq_Y`QQv{Tm#OK-;VhgmltVmU1-R=``v!}jlq zpxBb!tu(uy8mC{>;MU*IfrDOda9#`f163EW_3NH56|OAat9~@d;eb{H z+hda~7RddgWocvNx9E?vOv0(IOn<2d%kq8k|NS|qOrmZFezoomI>6Xe z`ET!<$>8Bw3#@n@`KN~`mR>T37LDkB9kRTC#6lBB) zls&lZ%pfUN!VfBRa=B&~GPsEQ(Td_j@X?^k`#Y4;h7Nf|%VFA;`NEra{(huxSCO+N z7er`*%p>+s6eG*2b%Q^y-6GF@=kn%#mp>);du#sX>m)kbT^fJSO87ulK&S0!Q^g{# zB3zwf7;Lc;+QWVDIZm9&8+R!JXePW^Jl#tR*NF5N#HNpe@1gcw(CX$>zKaIAaas3O zp-)(}+C=7d(2z%@kAvZw=phgn&Y362ymkoQf@?=#Fw0+|1vAh~q|Q5=fvbsS3GSj8 zCxMEv`ct-l>8gpLZ_nRt+YGvf`WT!YMLv@xx?c18~RBo%*lF`N67U z%jw^5f_^JFWjPNldT*-@4VPxbMj2ck=e8YBN&8R%-RnuAJ#AfwxCfd;VZXY^J_vL= zrH^Wm94M!7$0Z^K6=?oDf9|^vOJu$NQ0}IlXEL{-^yLtvf z_wwm~#`N~u$+F4X`bg3_M$jiH_v8-sG%;+3Oiq54uSABH!WFN0>G6;xe)hVJXa?lq zX(9cCGs7pXVV!nO(z(dw>)B*K^;ISZdisnCsyvaKX0d43Jaf<%58-4oufHXwx-rTF6}> z$CvUEO>a5+JD2lSGp6}|X8ik>8^1~ZnB=`oWbW!~g%$pKTJ3QYwC@ampB-QZ1!f#J z{>AJqUATvZ&IePsf2ZlEMgNti+s5{Trl3=)F!pn|P;oEDJY)&W$0YZ%6-B)dQm-Vt z6e-Xui0p7B29bpPRE+LLzs?~EBDI+4c>4$H$J2dvum4rqna4x9{(XEHC3$R3DOuBr zex)Q^))`x+vYnEWOq*pahmzee=-8!mRF-6SpYEKF<8&5ifMn4vg#pdYjCj}n-Ti^+`May;2kM-<#qGbe(TP3K|j#3{&A zNhQDMpi9vI^p*=8=p7@k#UPLDUc+Nd0N@mPr34r}HMu+tG1T)Ra`>-8h^s+U_Xzu8 zoQ`R&MkA3IjR_jcPZIOwCOqw1-$;Vy9g5wH&KAL4(3!^}&IFOs?QfSp29gEi9P*gb zU+!bAbD8+Dt{LD|%hRj2_34bFsS#=^u=ngi zf1ooC8h@{jp<>|bnZYXtsU$SxUeH6(Yn*OqlXx=Mh(mC!?$ds1cy$D5LqD07a&VFr z&-xQ~0LXid@Dr)r`yA-D*UkUXyrbVo|8D^RDB#=GKmci31jQE2hkW#GoRyH6_)vtjx(H$Istp(Ty5$+Q(gj-L2tC(AX9{c-YS}Kiev++; ztXQ`E9KdA0V?UjV77u_Dq95EUW20K5s=-^&i~shML|lrpE6I%&91*UoOLn=;6a_f` zI9)rDBKO(EfC8pM%adih3v#vCAlE(vM@0rQ@2M5AzN7);V1kvwDsfpK{`i@r<)62V z?W$?cmIh2Zu)#!+E$#cC(W)HN^^*}^!Q$6(YmC2L7LX`VdE5eAbZk>dtOo3Frzs;} z<7Sf~$G4>bK;7Cs1186UT#Mab6*-l9x}^7@OQ6Ix-(~q1WkX-!yzW+i+QqH72b8M} z%Q{{=+ZMpbh-j~*C)MC?B(C+R3o?hvnPEbP*3Xm&ZUsIA^NKu9vO8`g{0vz}!Q26U z;)4GoIRYbwyUP$_oYe>yp>i3#7Wd|}%YSM@t-HHbZz8gSYPaY3*0uUWp{Olfc2V&I zyGZ%8^MQc32^lXD!*H_4@fSb$Q?g*G7<7397NB87FK=S%bv0kfJIRU@lHYUdbcvV) zP5=5^{auHG#zN^A;WaS>Y+s~A@tX7+7xymDZhVgaVgNRXoRy0O(sjF}EB*Y{TV@C|^JBZ|x(4 z9>C+hA6-%EoZ7xtwiGIDw@df=i2EjFu@PnuS8ozXhlr?e!- zJ!YY{1Kwg(E|PI_p~{){1u!tkK7)>{SSo$Q`&IcgO1xtDvr?lQh{01I^C#B-ZX#tIj_Xs5ybAma`l@?jb5$L#Lfc1HC-Esi(D;+n+$``D!k_H$efGcI+3Sk{Va5UG1 z*5`=r^F+<3XudxMvK_-y$?@};L0{nC0^kg{fvg18Upi~`!NOyei8H4i`!?#h0^BYQ z^)v!G@*)Bg2BB;tYM6Cy_xbe-tq0m630Bp++H`Z%ITwiuQ5SmBe3b*eS`0B=+gPuJ zvFe?#VJnf`s&Ds=_qCfoo9SU)IIyw^^)6O#D}luv`3alOCm~bJF%A@>`ZY5cS^nrU zTuL^rmEo0o~=m ze})-0XbXuwg2}Ivhy1fHYJ94?r-IX(qg`g0|7jaf?!Qd?l8aryk@2+6Ov>m4@#_b}Ptbrwb@tfWhc~VN#NZ1;s z!o`o;o*Tr*WRwRK432OPu-1k($dAIjgWI(G#25)RQ7$fOTPRrD;PikqReSXHAGCo& z-oz{92`0ZTA$1F;PgQN~vVo_XAO@2_ppm8FoHij zi|+DSc+dvYvCjPb34*}@jflUm!>7b0Hh!L_n>XHVdv^fpGEByOdP-Ki2J?k6@m(8O z-1!jmo+jqfQ_5{{QJv|C;sw9`HFlb;bHH0@j3qN7-_x^3_Nk!Fb0X>uat)kiTljwi zb=Q?Qn%G^M-(dD+$8BiQ>%y+CU3a8r zIu{FZzT@K*5rEjnW=BPh=-hOY#$Gq$2^EvZ%>`}VVaJ{IhC}Tyo4*KojKKDxUKP)w zaQx>2A@51Tb55f z2FjEUi;{%zAvdN|FQ_Zjww5|b$0*hR6LB3Pc&7=QNh?9AIS5J@>Zr^$0S$(>P0lro z?^o!(}DbtmvvLsw3uFzkru z9_{ait=~fbL)WUM(rST6shyFK8m%jU2B;R(t_Ix`QT7ew*;&}<+mMk0^ zlrO=>9rk8o&-~e;<|AypEZ8@#AQ&_>mrabr3e!9%Jj8xp;b|`g{PYh9hAaVEHW+en ztBjNGToqei2GaYRPi)~ueEByuUxy>T93`f;R6&5IO%$ArDi{L+S|o?4Oo}Fr1tBFA zy#ZDjFNMOK zI&FDF!RX3gx9L&oYrf|)p-S7xFEiF$)$D@=TQUM4*lEUs_Rdo}ckQ?wbSk!si~v&< zn5CGm?8C!bAje<%k|6e_!GGMA?y6MJEwSNdiKatyw@AD@G|bYd=Rgg@=cd)vN) zy_0yxW!jxAfqE)$#R$IzF>`QgMcQmcNf7Ar3%gZm@iGu0OB89D%sM&2g**N+)Jz3n zBHG7+r5e49vGl&_Jm?8mOmr$D#P~%67aW3q%p8msnjboUE}57+5wd-}7oh64M`SN$ zrmnwy&BRs870Wj2OWH0BMeGz-&mAkaCsy0p6I zrG$2-Uevoh?a|Kyw_|~-Y)|g+ z?58}W_!*S!%MVNMcc=+pTv-+M9F++_$#llM(Q~?m0BW|gld(Mz)O=2?&fegzd5q3U zC>ghJeccd~`($v}=nQ);4h3xxS!E3m>1>XI!cZWfqyNHg4yTC?Tz!+`3US^EB;Y+q z*Ol8PCrlCP>6gFid`;#pjoJc(+7`cxQsZ>x0d#(Ss`>Zgy<*-XFv49t}vwq0YLpT-}F$&7a5 z+B^kBJ13C+iG^xqjh)`J@inMiBN@m9<h=8%Cp~W?kxTT0M2G#01J52Sxw@Z*)Sn z#5_T3alIC$CMrv)$k;bRE^E#v4D2)^w8no;%QB&~4EZKB35V|QCIoaAOSN!9z&lE{ zNi!m93@6c3)~;49+41AyknLb4yWf_?;ZCIS5FMx*0RC@iXM0=Y=GQ%HcrXXZ5(>r- z(9-w%D?yjMk$JQ|1lxvZK#j)-fE($y{l~c52AqW_z5-TP5fo3Gt4XMamO5Ll(B#16 z0R)s-0fg_7#)#sN`Ez-DLX?dQX^G4^yi4^ZYfHlc1<1Pa?_xV+lrPNq+X76Hn_5yqU-BMDfV^X)kV<87bxe|E4M0$;8 zxI6z(e-UD)>^*0fsgpDgH?#cM_S4V&aFnVbgewO%m9L$iKm30j^@qQ>sx-M1y|nOT z4F8w>yaVOmdm3^rRihiGZFsl1& diff --git a/performance/oss-performance-setup.yaml b/performance/oss-performance-setup.yaml deleted file mode 100644 index 46eafb238b6..00000000000 --- a/performance/oss-performance-setup.yaml +++ /dev/null @@ -1,79 +0,0 @@ -cassandra_version: cassandra-3.11.4 -cassandra_install_type: git -# Driver branch to use -driver_oss_branch: 4.x -# Driver dse branch to use -driver_dse_branch: 4.x -# Driver version identifier (used as part of graphite prefix) -driver_version: 4.8.0 -# Driver examples branch to use -driver_examples_branch: java-driver-4.x -# How long to run test for -duration: 2d -# The ip of the observer node from graphite-setup.yaml step -graphite_host: {provide-graphite-host-ip} - ---- - -ensemble: - server: - node.count: 3 - provisioner: - name: ctool - properties: - mark_for_reuse: true - cloud.provider: openstack - cloud.tenant: performance - cloud.instance.type: ms1.small - cluster_ttl: 2d - configuration_manager: - - name: ctool - properties: - java.version: openjdk8 - product.type: cassandra - product.install.type: {{cassandra_install_type}} - product.version: {{cassandra_version}} - cassandra.yaml: - hinted_handoff_enabled: false - client: - node.count: 1 - provisioner: - name: ctool - properties: - mark_for_reuse: true - cluster_ttl: 2d - cloud.provider: openstack - cloud.tenant: performance - cloud.instance.type: ms1.small - configuration_manager: - - name: ctool - properties: - java.version: openjdk8 - install.maven: true - - name: java_driver - properties: - oss.git.repository: git@github.com:datastax/java-driver.git - oss.git.branch: {{driver_oss_branch}} - dse.git.branch: {{driver_dse_branch}} - type: FOUR_X_OSS - - name: java_driver_duration_test - properties: - git.branch: {{driver_examples_branch}} -workload: - phases: - - run-endurance: - module: java_driver_duration_test - properties: - duration: {{duration}} - is.four: true - graphite.host: {{graphite_host}} - graphite.prefix: endurance-test-java-{{driver_version}}-OSS-{{cassandra_version}} - kill_nodes: - module: killnode_rhino - properties: - target.strategy: whitelist - target.number_of_nodes: 1 - target.selector: "*:*" - repeat.delay: 120 - repeat.iterations: 0 - graceful: true From 146edde75a567c08e3026c34b719f358b776d6bd Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 12 Jan 2021 17:25:57 +0100 Subject: [PATCH 052/395] Exclude ByteOrderedTokenIT when running C* 4.0-beta4+ (CASSANDRA-13701) --- .../oss/driver/core/metadata/ByteOrderedTokenIT.java | 6 ++++++ .../oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java index dbc5dc06c2a..63473704c8a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; @@ -27,6 +28,11 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +@CassandraRequirement( + max = "4.0-beta4", + description = + "Token allocation is not compatible with this partitioner, " + + "but is enabled by default in C* 4.0 (see CASSANDRA-7032 and CASSANDRA-13701)") public class ByteOrderedTokenIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java index 76e9e08fff4..62fd20719dd 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; @@ -27,6 +28,11 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +@CassandraRequirement( + max = "4.0-beta4", + description = + "Token allocation is not compatible with this partitioner, " + + "but is enabled by default in C* 4.0 (see CASSANDRA-7032 and CASSANDRA-13701)") public class ByteOrderedTokenVnodesIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = From a39e4895e3d600e549411eee4bd3b8392ba6e403 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 12 Jan 2021 17:27:23 +0100 Subject: [PATCH 053/395] Temporarily suspend vnodes tests when running C* 4.0-beta4+ (CASSANDRA-16364) --- .../oss/driver/core/metadata/Murmur3TokenVnodesIT.java | 5 +++++ .../oss/driver/core/metadata/RandomTokenVnodesIT.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java index 54bb1d0db26..28c219e8a91 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; @@ -27,6 +28,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +@CassandraRequirement( + max = "4.0-beta4", + // TODO Re-enable when CASSANDRA-16364 is fixed + description = "TODO Re-enable when CASSANDRA-16364 is fixed") public class Murmur3TokenVnodesIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java index 924ed515169..08b226bdc51 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; @@ -27,6 +28,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +@CassandraRequirement( + max = "4.0-beta4", + // TODO Re-enable when CASSANDRA-16364 is fixed + description = "TODO Re-enable when CASSANDRA-16364 is fixed") public class RandomTokenVnodesIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = From 5d037ccdd42732ae7e1145011bfe45027f21142f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 13 Jan 2021 15:12:45 +0100 Subject: [PATCH 054/395] Remove dead link in DseGssApiAuthProvider --- .../dse/driver/internal/core/auth/DseGssApiAuthProvider.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseGssApiAuthProvider.java b/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseGssApiAuthProvider.java index be1b64fad7c..10501af8c01 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseGssApiAuthProvider.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseGssApiAuthProvider.java @@ -150,10 +150,6 @@ * } * } * - * - * @see Authenticating - * a DSE cluster with Kerberos */ @ThreadSafe public class DseGssApiAuthProvider extends DseGssApiAuthProviderBase { From 2e896c1c8cadbdd677590cdf2706fc55a423a0da Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 13 Jan 2021 17:45:10 +0100 Subject: [PATCH 055/395] Include Tinkerpop dependencies when generating distribution javadocs (JAVA-2907 follow-up) --- distribution/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/distribution/pom.xml b/distribution/pom.xml index dd1e4e8c7b4..70acdb59f06 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -140,6 +140,16 @@ snappy-java ${snappy.version} + + org.apache.tinkerpop + gremlin-core + ${tinkerpop.version} + + + org.apache.tinkerpop + tinkergraph-gremlin + ${tinkerpop.version} + From 889fe572e3720cfd4bcff06ce5cac3274243d110 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 13 Jan 2021 17:59:56 +0100 Subject: [PATCH 056/395] [maven-release-plugin] prepare release 4.10.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 7e2aa86d4a5..308a76f75e3 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-core-shaded - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-mapper-processor - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-mapper-runtime - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-query-builder - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-test-infra - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-metrics-micrometer - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss java-driver-metrics-microprofile - 4.10.0-SNAPSHOT + 4.10.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index ba8101ea31f..df8600563d7 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 40090ea75a9..333d92bdc6f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 70acdb59f06..727c3c15a01 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 3255b92e6ae..3b24e714472 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.10.0-SNAPSHOT + 4.10.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 553199ea830..a6fb63f7093 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 9cbd8fe224c..ecb6b308967 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 0c881a55311..5574d4694b8 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 5dde458d947..da70e6f654e 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 3559b2af797..09d29e0c631 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index cfbc99e7368..efd69a623e5 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 6d5d7f4c3d6..a20234999ff 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -951,7 +951,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.10.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index ddf668c530a..153f9db9bd3 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index bc259d4ac83..a91fdc388c4 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0-SNAPSHOT + 4.10.0 java-driver-test-infra bundle From 2e300fe1cc822d5234c69ba539c4e05b828b85b9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 13 Jan 2021 18:00:11 +0100 Subject: [PATCH 057/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 308a76f75e3..1527d39f924 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.10.0 + 4.11.0-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index df8600563d7..dd07c3c8be8 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 333d92bdc6f..5e545545541 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 727c3c15a01..65de3f5bbb2 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 3b24e714472..a8aa460b95d 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.10.0 + 4.11.0-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index a6fb63f7093..5dbcaf6996c 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index ecb6b308967..5de6def1d9d 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 5574d4694b8..f65a8d9f584 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index da70e6f654e..8b0134f3307 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 09d29e0c631..138deb6f11a 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index efd69a623e5..1fb3438eff1 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index a20234999ff..add6f984b6e 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -951,7 +951,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.10.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 153f9db9bd3..5e0e4cf0a89 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index a91fdc388c4..4bd0d80bfe2 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.10.0 + 4.11.0-SNAPSHOT java-driver-test-infra bundle From e4c4569fa56a35337fd478b705989182f7de5634 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 13 Jan 2021 16:43:31 +0100 Subject: [PATCH 058/395] Update version in docs --- README.md | 4 +- changelog/README.md | 2 +- manual/case_sensitivity/README.md | 10 +-- manual/core/README.md | 26 +++---- manual/core/address_resolution/README.md | 2 +- manual/core/async/README.md | 2 +- manual/core/authentication/README.md | 16 ++-- manual/core/bom/README.md | 4 +- manual/core/configuration/README.md | 20 ++--- manual/core/control_connection/README.md | 2 +- manual/core/custom_codecs/README.md | 74 +++++++++---------- manual/core/detachable_types/README.md | 14 ++-- manual/core/dse/geotypes/README.md | 6 +- manual/core/dse/graph/README.md | 4 +- manual/core/dse/graph/fluent/README.md | 4 +- .../core/dse/graph/fluent/explicit/README.md | 12 +-- manual/core/dse/graph/results/README.md | 6 +- manual/core/dse/graph/script/README.md | 6 +- manual/core/idempotence/README.md | 4 +- manual/core/integration/README.md | 6 +- manual/core/load_balancing/README.md | 10 +-- manual/core/metadata/README.md | 6 +- manual/core/metadata/node/README.md | 28 +++---- manual/core/metadata/schema/README.md | 20 ++--- manual/core/metadata/token/README.md | 4 +- manual/core/native_protocol/README.md | 6 +- manual/core/non_blocking/README.md | 44 +++++------ manual/core/paging/README.md | 12 +-- manual/core/performance/README.md | 10 +-- manual/core/pooling/README.md | 2 +- manual/core/query_timestamps/README.md | 4 +- manual/core/reactive/README.md | 24 +++--- manual/core/reconnection/README.md | 8 +- manual/core/request_tracker/README.md | 4 +- manual/core/speculative_execution/README.md | 2 +- manual/core/ssl/README.md | 6 +- manual/core/statements/README.md | 8 +- manual/core/statements/batch/README.md | 6 +- .../statements/per_query_keyspace/README.md | 2 +- manual/core/statements/prepared/README.md | 8 +- manual/core/statements/simple/README.md | 6 +- manual/core/temporal_types/README.md | 8 +- manual/core/throttling/README.md | 6 +- manual/core/tracing/README.md | 12 +-- manual/core/tuples/README.md | 4 +- manual/core/udts/README.md | 4 +- manual/developer/common/concurrency/README.md | 4 +- manual/mapper/config/kotlin/README.md | 2 +- manual/mapper/config/record/README.md | 2 +- manual/mapper/config/scala/README.md | 2 +- manual/mapper/daos/README.md | 8 +- manual/mapper/daos/custom_types/README.md | 10 +-- manual/mapper/daos/delete/README.md | 18 ++--- manual/mapper/daos/getentity/README.md | 16 ++-- manual/mapper/daos/increment/README.md | 12 +-- manual/mapper/daos/insert/README.md | 14 ++-- manual/mapper/daos/null_saving/README.md | 10 +-- manual/mapper/daos/query/README.md | 22 +++--- manual/mapper/daos/queryprovider/README.md | 16 ++-- manual/mapper/daos/select/README.md | 26 +++---- manual/mapper/daos/setentity/README.md | 10 +-- .../daos/statement_attributes/README.md | 2 +- manual/mapper/daos/update/README.md | 12 +-- manual/mapper/entities/README.md | 36 ++++----- manual/mapper/mapper/README.md | 10 +-- manual/osgi/README.md | 6 +- manual/query_builder/README.md | 10 +-- manual/query_builder/condition/README.md | 2 +- manual/query_builder/delete/README.md | 4 +- manual/query_builder/insert/README.md | 2 +- manual/query_builder/relation/README.md | 4 +- manual/query_builder/schema/README.md | 2 +- .../query_builder/schema/aggregate/README.md | 2 +- .../query_builder/schema/function/README.md | 2 +- manual/query_builder/schema/index/README.md | 2 +- .../query_builder/schema/keyspace/README.md | 2 +- .../schema/materialized_view/README.md | 4 +- manual/query_builder/schema/table/README.md | 6 +- manual/query_builder/schema/type/README.md | 2 +- manual/query_builder/select/README.md | 4 +- manual/query_builder/term/README.md | 4 +- manual/query_builder/truncate/README.md | 2 +- manual/query_builder/update/README.md | 4 +- upgrade_guide/README.md | 6 +- 84 files changed, 390 insertions(+), 390 deletions(-) diff --git a/README.md b/README.md index fc8427f7f73..5b7c323ec85 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.9.0](https://github.com/datastax/java-driver/tree/4.9.0).* +[4.10.0](https://github.com/datastax/java-driver/tree/4.10.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol @@ -82,7 +82,7 @@ See the [upgrade guide](upgrade_guide/) for details. * [Changelog] * [FAQ] -[API docs]: https://docs.datastax.com/en/drivers/java/4.9 +[API docs]: https://docs.datastax.com/en/drivers/java/4.10 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [@dsJavaDriver]: https://twitter.com/dsJavaDriver diff --git a/changelog/README.md b/changelog/README.md index d54e6d8713a..5dd62b63f38 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,7 +2,7 @@ -### 4.10.0 (in progress) +### 4.10.0 - [improvement] JAVA-2907: Switch Tinkerpop to an optional dependency - [improvement] JAVA-2904: Upgrade Jackson to 2.12.0 and Tinkerpop to 3.4.9 diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index a2a16ebfdbd..576ee41823d 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -106,11 +106,11 @@ For "consuming" methods, string overloads are also provided for convenience, for * in other cases, the string is always assumed to be in CQL form, and converted on the fly with `CqlIdentifier.fromCql`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlIdentifier.html -[Row]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/UdtValue.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html +[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/AccessibleByName.html ### Good practices diff --git a/manual/core/README.md b/manual/core/README.md index aeb21167fea..7ff1fc3ab0e 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -314,18 +314,18 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { } ``` -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html -[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html#builder-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Row.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlIdentifier.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/TupleValue.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/UdtValue.html -[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- -[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html#builder-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/TupleValue.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html +[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- +[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index 7d83c8ff748..b3b0ff0dd17 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -124,7 +124,7 @@ Cassandra node: domain name of the target instance. Then it performs a forward DNS lookup of the domain name; the EC2 DNS does the private/public switch automatically based on location). -[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html +[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html [cassandra.yaml]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html [rpc_address]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html?scroll=configCassandra_yaml__rpc_address diff --git a/manual/core/async/README.md b/manual/core/async/README.md index 2b70c64d1a4..d3d936a2758 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -207,4 +207,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 4e77c3d3a61..90181f3b98e 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -215,12 +215,12 @@ session.execute(statement); [SASL]: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer -[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/auth/AuthProvider.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/context/DriverContext.html -[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html -[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html -[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html -[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- -[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- -[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- +[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/auth/AuthProvider.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html +[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html +[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html +[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- +[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- +[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- [reference.conf]: ../configuration/reference/ \ No newline at end of file diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index 922bcffba24..cc896b138a1 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.9.0 + 4.10.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.9.0 + 4.10.0 diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index 50432c499cf..8d8b11e1065 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -520,16 +520,16 @@ config.getDefaultProfile().getString(MyCustomOption.ADMIN_EMAIL); config.getDefaultProfile().getInt(MyCustomOption.AWESOMENESS_FACTOR); ``` -[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfig.html -[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/context/DriverContext.html -[DriverOption]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverOption.html -[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html -[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- -[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- -[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- -[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- +[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfig.html +[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html +[DriverOption]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverOption.html +[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html +[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- +[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- +[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- +[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- [Typesafe Config]: https://github.com/typesafehub/config [config standard behavior]: https://github.com/typesafehub/config#standard-behavior diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index f688aa88172..77977089641 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -23,4 +23,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index 5bda597058b..53d2a785d02 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -660,13 +660,13 @@ private static String formatRow(Row row) { } ``` -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html -[format()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- -[parse()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- -[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html -[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html +[format()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- +[parse()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- +[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html +[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- [Enums]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html [Enum.name()]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#name-- @@ -680,36 +680,36 @@ private static String formatRow(Row row) { [java.time.LocalDateTime]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html [java.time.ZoneId]: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html -[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html -[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY -[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY -[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY -[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY -[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY -[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY -[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY -[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY -[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC -[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- -[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM -[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC -[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC -[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC -[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED -[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- -[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- -[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- -[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- - -[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB -[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP +[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html +[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY +[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY +[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY +[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY +[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY +[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY +[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY +[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY +[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC +[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- +[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM +[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC +[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC +[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC +[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED +[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- +[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- +[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- +[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- + +[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB +[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index ec033d6e522..f81f376831c 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -137,13 +137,13 @@ Even then, the defaults used by detached objects might be good enough for you: Otherwise, just make sure you reattach objects any time you deserialize them or create them from scratch. -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT -[DataType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/DataType.html -[Detachable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/detach/Detachable.html -[Session]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html -[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html -[Row]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Row.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT +[DataType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/DataType.html +[Detachable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/detach/Detachable.html +[Session]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html +[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html +[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html [Java serialization]: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html [protocol specifications]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index a37704eede2..a7c676e8cdf 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -166,9 +166,9 @@ All geospatial types interoperate with three standard formats: [ESRI]: https://github.com/Esri/geometry-api-java -[LineString]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/data/geometry/LineString.html -[Point]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/data/geometry/Point.html -[Polygon]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/data/geometry/Polygon.html +[LineString]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/data/geometry/LineString.html +[Point]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/data/geometry/Point.html +[Polygon]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/data/geometry/Polygon.html [Well-known text]: https://en.wikipedia.org/wiki/Well-known_text [Well-known binary]: https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index 145f8a84f38..1bf8d7825ba 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -74,8 +74,8 @@ fluent API returns Apache TinkerPop™ types directly. [Apache TinkerPop™]: http://tinkerpop.apache.org/ -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html -[GraphSession]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/GraphSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html +[GraphSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/GraphSession.html [DSE developer guide]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphTOC.html [Gremlin]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dseGraphAbout.html#dseGraphAbout__what-is-cql diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index 072c2193c71..2d907231e58 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -109,8 +109,8 @@ All the DSE predicates are available on the driver side: .values("name"); ``` -[Search]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/predicates/Search.html -[Geo]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/predicates/Geo.html +[Search]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/predicates/Search.html +[Geo]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/predicates/Geo.html [Apache TinkerPop™]: http://tinkerpop.apache.org/ [TinkerPop DSL]: http://tinkerpop.apache.org/docs/current/reference/#dsl diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index 04b447c7919..5ba18bc6891 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -105,9 +105,9 @@ added in a future version. See also the [parent page](../) for topics common to all fluent traversals. -[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html -[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html -[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- -[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- +[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html +[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html +[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- +[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index 7ac4a6c4e8f..e40f29d7f9a 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -137,8 +137,8 @@ If a type doesn't have a corresponding `asXxx()` method, use the variant that ta UUID uuid = graphNode.as(UUID.class); ``` -[GraphNode]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/GraphNode.html -[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/GraphResultSet.html -[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html +[GraphNode]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/GraphNode.html +[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/GraphResultSet.html +[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html [DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index 929f80531ca..2869ce22a4b 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -101,6 +101,6 @@ Note however that some types of queries can only be performed through the script * configuration; * DSE graph schema queries. -[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html -[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html +[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index fdddaff26f8..505ad2a40be 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -60,5 +60,5 @@ assert bs.isIdempotent(); The query builder tries to infer idempotence automatically; refer to [its manual](../../query_builder/idempotence/) for more details. -[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- -[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- +[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- +[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 382983a106d..87be4598121 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -589,6 +589,6 @@ The remaining core driver dependencies are the only ones that are truly mandator [guava]: https://github.com/google/guava/issues/2721 [annotation processing]: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#sthref65 -[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- -[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[Uuids]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/uuid/Uuids.html +[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- +[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[Uuids]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index 3210c916a61..e65c7ef50d9 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -423,11 +423,11 @@ Then it uses the "closest" distance for any given node. For example: * policy1 changes its suggestion to IGNORED. node1 is set to REMOTE; * policy1 changes its suggestion to REMOTE. node1 stays at REMOTE. -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/context/DriverContext.html -[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html +[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html [BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java -[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- -[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- -[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- +[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- +[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index 79cfc96524f..51b7c4621ea 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -56,6 +56,6 @@ new keyspace in the schema metadata before the token metadata was updated. Schema and node state events are debounced. This allows you to control how often the metadata gets refreshed. See the [Performance](../performance/#debouncing) page for more details. -[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- -[Metadata]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- +[Metadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html +[Node]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 49da884802b..31503c10be4 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -112,17 +112,17 @@ beyond the scope of this document; if you're interested, study the `TopologyMoni the source code. -[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- -[Node]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html -[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- -[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- -[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- -[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- -[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- -[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- -[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- -[NodeState]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/NodeState.html -[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html -[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file +[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- +[Node]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html +[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- +[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- +[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- +[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- +[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- +[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- +[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- +[NodeState]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/NodeState.html +[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html +[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html +[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index 4259e56c107..fc02e8a8cdc 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -307,16 +307,16 @@ unavailable for the excluded keyspaces. If you issue schema-altering requests from the driver (e.g. `session.execute("CREATE TABLE ..")`), take a look at the [Performance](../../performance/#schema-updates) page for a few tips. -[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html -[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html -[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- -[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- -[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- -[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html -[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html -[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html +[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html +[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html +[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- +[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- +[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- +[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html +[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html +[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html [JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 [java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index 38765047f86..8c98f389cef 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -169,5 +169,5 @@ on [schema metadata](../schema/). If schema metadata is disabled or filtered, to also be unavailable for the excluded keyspaces. -[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 6704b8394c4..616b04beeda 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -135,6 +135,6 @@ If you want to see the details of mixed cluster negotiation, enable `DEBUG` leve [protocol spec]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources [driver3]: https://docs.datastax.com/en/developer/java-driver/3.10/manual/native_protocol/ -[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- -[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- -[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- +[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- +[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- +[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 8f0aace18f3..8ddbcfd8069 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -49,22 +49,22 @@ For example, calling any synchronous method declared in [`SyncCqlSession`], such will block until the result is available. These methods should never be used in non-blocking applications. -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` -[`execute`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all safe for use in non-blocking applications; the statement execution and asynchronous result delivery is guaranteed to never block. -[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html -[`executeAsync`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the returned publisher will never block when subscribed to, until the final results are delivered to the subscriber. -[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[`executeReactive`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- There is one exception though: continuous paging queries (a feature specific to DSE) have a special execution model which uses internal locks for coordination. Although such locks are only held for @@ -77,10 +77,10 @@ reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactiv though, continuous paging is extremely efficient and can safely be used in most non-blocking contexts, unless they require strict lock-freedom. -[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html -[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html -[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- -[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- #### Driver lock-free guarantees per session lifecycle phases @@ -110,8 +110,8 @@ Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` should be avoided in non-blocking applications. -[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- -[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- Once the session is initialized, however, the driver is guaranteed to be non-blocking during the session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. @@ -121,8 +121,8 @@ during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseab asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is shut down and lock-freedom enforcement is disabled. -[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html -[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- #### Driver lock-free guarantees for specific components @@ -131,7 +131,7 @@ Certain driver components are not implemented in lock-free algorithms. For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It should not be used if strict lock-freedom is enforced. -[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html The same is valid for both built-in [request throttlers]: @@ -143,7 +143,7 @@ use locks internally, and depending on how many requests are being executed in p contention on these locks can be high: in short, if your application enforces strict lock-freedom, then these components should not be used. -[request throttlers]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html +[request throttlers]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html Other components may be lock-free, *except* for their first invocation. This is the case of the following items: @@ -151,8 +151,8 @@ following items: * All built-in implementations of [`TimestampGenerator`], upon instantiation; * The utility method [`Uuids.timeBased()`]. -[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/time/TimestampGenerator.html -[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- Both components need to access native libraries when they get initialized and this may involve hitting the local filesystem, thus causing the initialization to become a blocking call. @@ -172,7 +172,7 @@ One component, the codec registry, can block when its [`register`] method is cal therefore advised that codecs should be registered during application startup exclusively. See the [custom codecs](../custom_codecs) section for more details about registering codecs. -[`register`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[`register`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- Finally, a few internal components also use locks, but only during session initialization; once the session is ready, they are either discarded, or don't use locks anymore for the rest of the @@ -213,7 +213,7 @@ lock-freedom enforcement tools could report calls to that method, but it was imp these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a non-blocking call and random UUIDs can now be safely generated in non-blocking applications. -[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- [JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 #### Driver lock-free guarantees when reloading the configuration @@ -228,8 +228,8 @@ detectors. If that is the case, it is advised to disable hot-reloading by settin `datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on [configuration](../configuration) for more information. -[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[hot-reloading]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- #### Driver lock-free guarantees when connecting to DSE diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index 9dec6c80f78..ffae1dfb6fb 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -253,12 +253,12 @@ protocol page size and the logical page size to the same value. The [driver examples] include two complete web service implementations demonstrating forward-only and offset paging. -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- -[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- -[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/paging/OffsetPager.html -[PagingState]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/PagingState.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- +[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- +[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/paging/OffsetPager.html +[PagingState]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/PagingState.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index 9e200a3ffb5..691b4735aea 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -345,8 +345,8 @@ possible to reuse the same event loop group for I/O, admin tasks, and even your (the driver's internal code is fully asynchronous so it will never block any thread). The timer is the only one that will have to stay on a separate thread. -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlIdentifier.html -[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- -[GenericType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html +[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index ef6f1068f2a..8fb17c02f8b 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -170,5 +170,5 @@ you experience the issue, here's what to look out for: Try adding more connections per node. Thanks to the driver's hot-reload mechanism, you can do that at runtime and see the effects immediately. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html [CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index ac50c53da90..a3264c1f0e1 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -187,9 +187,9 @@ Here is the order of precedence of all the methods described so far: 3. otherwise, if the timestamp generator assigned a timestamp, use it; 4. otherwise, let the server assign the timestamp. -[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/time/TimestampGenerator.html [gettimeofday]: http://man7.org/linux/man-pages/man2/settimeofday.2.html [JNR]: https://github.com/jnr/jnr-posix [Lightweight transactions]: https://docs.datastax.com/en/dse/6.0/cql/cql/cql_using/useInsertLWT.html -[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- +[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index 1c88908f4cd..57b3a98cebb 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -367,18 +367,18 @@ Note that the driver already has a [built-in retry mechanism] that can transpare queries; the above example should be seen as a demonstration of application-level retries, when a more fine-grained control of what should be retried, and how, is required. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html -[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html -[Row]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Row.html -[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- -[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- -[wasApplied]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- -[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- -[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- -[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html +[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html +[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html +[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- +[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- +[wasApplied]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- +[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- +[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- +[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- [built-in retry mechanism]: ../retries/ [request throttling]: ../throttling/ diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index 24290baf9ab..08a1e30f4c9 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -84,7 +84,7 @@ Note that the session is not accessible until it is fully ready: the `CqlSession call — or the future returned by `buildAsync()` — will not complete until the connection was established. -[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/context/DriverContext.html -[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html +[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index dfcf23d4b4b..1d52fbceb26 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -117,5 +117,5 @@ all FROM users WHERE user_id=? [v0=42] com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined column name all ``` -[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/tracker/RequestTracker.html +[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index aa324c53c4f..698ac2f42a4 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -250,4 +250,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index de3a05f59ad..cdbc5ca817c 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -204,6 +204,6 @@ the box, but with a bit of custom development it is fairly easy to add. See [dsClientToNode]: https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html [pickle]: http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html [JSSE system properties]: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization -[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- -[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- -[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html +[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- +[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- +[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index 8587aa7ffc6..90dec7a960d 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -59,7 +59,7 @@ the [configuration](../configuration/). Namely, these are: idempotent flag, quer consistency levels and page size. We recommended the configuration approach whenever possible (you can create execution profiles to capture common combinations of those options). -[Statement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Statement.html -[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/StatementBuilder.html -[execute]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- -[executeAsync]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[Statement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html +[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/StatementBuilder.html +[execute]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[executeAsync]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index b691e1ea292..b1cb7c70967 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -61,8 +61,8 @@ In addition, simple statements with named parameters are currently not supported due to a [protocol limitation][CASSANDRA-10246] that will be fixed in a future version). If you try to execute such a batch, an `IllegalArgumentException` is thrown. -[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BatchStatement.html -[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- -[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BatchStatement.html +[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- [batch_dse]: http://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/useBatch.html [CASSANDRA-10246]: https://issues.apache.org/jira/browse/CASSANDRA-10246 diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index cc61e732e2b..66e9d451387 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -124,6 +124,6 @@ SimpleStatement statement = At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we'll probably deprecate `setRoutingKeyspace()`. -[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index 17ffefd39bf..e74813d8e6d 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -330,10 +330,10 @@ With Cassandra 4 and [native protocol](../../native_protocol/) v5, this issue is new version with the response; the driver updates its local cache transparently, and the client can observe the new columns in the result set. -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [CASSANDRA-10786]: https://issues.apache.org/jira/browse/CASSANDRA-10786 [CASSANDRA-10813]: https://issues.apache.org/jira/browse/CASSANDRA-10813 [guava eviction]: https://github.com/google/guava/wiki/CachesExplained#reference-based-eviction -[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- -[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- +[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- +[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index a9599d9ed12..deff971fea9 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -182,6 +182,6 @@ session.execute( Or you could also use [prepared statements](../prepared/), which don't have this limitation since parameter types are known in advance. -[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/SimpleStatement.html -[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- -[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- +[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SimpleStatement.html +[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- +[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index 17467e8d6c5..a9985099fd7 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -146,7 +146,7 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]" ``` -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index 7eee629ae5a..6e779811aa0 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -145,6 +145,6 @@ datastax-java-driver { If you enable `throttling.delay`, make sure to also check the associated extra options to correctly size the underlying histograms (`metrics.session.throttling.delay.*`). -[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/RequestThrottlingException.html -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/RequestThrottlingException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index adb267bf07a..3708988ad39 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -113,9 +113,9 @@ for (TraceEvent event : trace.getEvents()) { If you call `getQueryTrace()` for a statement that didn't have tracing enabled, an exception is thrown. -[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html -[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/QueryTrace.html -[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- -[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- -[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- -[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html +[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/QueryTrace.html +[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- +[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- +[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- +[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index 763f6d3ebba..2de2788c87a 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -139,5 +139,5 @@ BoundStatement bs = [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html -[TupleType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/TupleType.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/TupleValue.html +[TupleType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/TupleType.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/TupleValue.html diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index 12584c140cb..6cadf225623 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -135,5 +135,5 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index be51e184ac5..545eda62533 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -101,8 +101,8 @@ public interface ExecutionInfo { When a public API method is blocking, this is generally clearly stated in its javadocs. -[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index 533ccb62e57..1ff4fa80910 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -106,4 +106,4 @@ before compilation: [build.gradle]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/build.gradle [UserDao.kt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/src/main/kotlin/com/datastax/examples/mapper/killrvideo/user/UserDao.kt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index 3a3b1d6e39e..de7e3159816 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -27,7 +27,7 @@ You need to build with Java 14, and pass the `--enable-preview` flag to both the runtime JVM. See [pom.xml] in the example. -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html [DataStax-Examples/object-mapper-jvm/record]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/record [pom.xml]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/record/pom.xml diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index 46749d10286..b925895c80c 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -54,4 +54,4 @@ mapper builder. [DataStax-Examples/object-mapper-jvm/scala]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/scala [build.sbt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/scala/build.sbt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index a29af184550..091f669f269 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -148,8 +148,8 @@ In this case, any annotations declared in `Dao1` would be chosen over `Dao2`. To control how the hierarchy is scanned, annotate interfaces with [@HierarchyScanStrategy]. -[@Dao]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html [Entity Inheritance]: ../entities/#inheritance diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index 18b3900eafc..705549502de 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -236,8 +236,8 @@ flag: With this configuration, if a DAO method declares a non built-in return type, it will be surfaced as a compiler error. -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/MapperContext.html -[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html -[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/MapperContext.html +[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html +[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index 5fc0550fb02..00831156973 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -151,15 +151,15 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@Delete]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Delete.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@Delete]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Delete.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index b4228a0fce1..87ab6f7f826 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -69,14 +69,14 @@ If the return type doesn't match the parameter type (for example [PagingIterable [AsyncResultSet]), the mapper processor will issue a compile-time error. -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[GettableByName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/GettableByName.html -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/PagingIterable.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/UdtValue.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[GettableByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/GettableByName.html +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index 5c1f2713e2d..ede46a8a629 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -75,12 +75,12 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[@Increment]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Increment.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Increment]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Increment.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/CqlName.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index 1cf6800ade6..0daf347c5b3 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -108,13 +108,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Insert]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Insert]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index b88b61d4e9e..265f2b5a278 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -93,10 +93,10 @@ public interface UserDao extends InventoryDao { } ``` -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[MapperException]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/MapperException.html -[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET -[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[MapperException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/MapperException.html +[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET +[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL [CASSANDRA-7304]: https://issues.apache.org/jira/browse/CASSANDRA-7304 diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index d053928b379..e019ce9c5e8 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -110,17 +110,17 @@ Then: query succeeds or not depends on whether the session that the mapper was built with has a [default keyspace]. -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Query]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Query.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/PagingIterable.html -[Row]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/Row.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Query]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Query.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index 8a64b94a10f..79423b674c3 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -137,11 +137,11 @@ Here is the full implementation: the desired [PagingIterable][PagingIterable]. -[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html -[providerClass]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- -[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- -[providerMethod]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/MapperContext.html -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/EntityHelper.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/PagingIterable.html +[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html +[providerClass]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- +[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- +[providerMethod]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/MapperContext.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/EntityHelper.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index 5e1cdcdc79d..d31c1ce9faa 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -142,19 +142,19 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html -[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- -[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- -[groupBy()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- -[limit()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- -[orderBy()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- -[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/PagingIterable.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html +[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- +[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- +[groupBy()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- +[limit()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- +[orderBy()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- +[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index 5232afcb277..f1f5646265b 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -63,8 +63,8 @@ BoundStatement bind(Product product, BoundStatement statement); If you use a void method with [BoundStatement], the mapper processor will issue a compile-time warning. -[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html -[SettableByName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/SettableByName.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/data/UdtValue.html +[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html +[SettableByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/SettableByName.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index 4f26a84004f..be9c2a2a23a 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -60,4 +60,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 2b39db5c4a0..22c974ff894 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -143,13 +143,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Update]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Update.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Update]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Update.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html [Boolean]: https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Boolean.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/ResultSet.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index 29a83725750..27039d76d51 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -555,22 +555,22 @@ the same level. To control how the class hierarchy is scanned, annotate classes with [@HierarchyScanStrategy]. -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/CqlName.html -[@Dao]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@Entity]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Entity.html -[NameConverter]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html -[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html -[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Computed]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Computed.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Select.html -[@Insert]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[@Update]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Update.html -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[@Query]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Query.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@Entity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Entity.html +[NameConverter]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html +[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html +[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Computed]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Computed.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html +[@Insert]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[@Update]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Update.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[@Query]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Query.html [aliases]: http://cassandra.apache.org/doc/latest/cql/dml.html?#aliases -[@Transient]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Transient.html -[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@Transient]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Transient.html +[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index e2834b0d99f..8d6ee979a75 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -230,8 +230,8 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) You can also permanently disable validation of an individual entity by annotating it with `@SchemaHint(targetElement = NONE)`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlIdentifier.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html -[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html -[@Mapper]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/mapper/annotations/Mapper.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html +[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html +[@Mapper]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Mapper.html diff --git a/manual/osgi/README.md b/manual/osgi/README.md index 0983292d859..65b1efdb85a 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -138,7 +138,7 @@ starting the driver: [driver configuration]: ../core/configuration [OSGi]:https://www.osgi.org [JNR]: https://github.com/jnr/jnr-posix -[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- [JAVA-1127]:https://datastax-oss.atlassian.net/browse/JAVA-1127 -[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- -[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- +[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- +[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index c3f7d5f5e11..ab7c39ffb1a 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -212,8 +212,8 @@ For a complete tour of the API, browse the child pages in this manual: * [Terms](term/) * [Idempotence](idempotence/) -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/CqlIdentifier.html -[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html -[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html +[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html +[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index 9b25e53235b..f4d406da249 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -132,4 +132,4 @@ It is mutually exclusive with column conditions: if you previously specified col the statement, they will be ignored; conversely, adding a column condition cancels a previous IF EXISTS clause. -[Condition]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/condition/Condition.html +[Condition]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/condition/Condition.html diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index 413366779b0..c349f6c8c44 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -141,5 +141,5 @@ deleteFrom("user") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index d038fd9d44a..ae17f467843 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -114,4 +114,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index 20d0b184cf5..8b6862e4fed 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -201,5 +201,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Relation]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/relation/Relation.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Relation]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/relation/Relation.html diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index 1210491a1c6..140b1cf430f 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -44,4 +44,4 @@ element type: * [function](function/) * [aggregate](aggregate/) -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index 9a6fba24819..b2d005495a6 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -76,4 +76,4 @@ dropAggregate("average").ifExists(); // DROP AGGREGATE IF EXISTS average ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index e1a17cf7d92..7a782dcd6d6 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -92,4 +92,4 @@ dropFunction("log").ifExists(); // DROP FUNCTION IF EXISTS log ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index 2aa435e5b7c..0c2603ef0fe 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -99,4 +99,4 @@ dropIndex("my_idx").ifExists(); // DROP INDEX IF EXISTS my_idx ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index f283ba5b5ee..9347b3bbb56 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -83,6 +83,6 @@ dropKeyspace("cycling").ifExists(); // DROP KEYSPACE IF EXISTS cycling ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index d240c6bd282..609395d2b6e 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -85,5 +85,5 @@ dropTable("cyclist_by_age").ifExists(); // DROP MATERIALIZED VIEW IF EXISTS cyclist_by_age ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index ab0664d0280..d743f584002 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -107,6 +107,6 @@ dropTable("cyclist_name").ifExists(); // DROP TABLE IF EXISTS cyclist_name ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html -[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html +[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index b5d6646fcc7..cd23078f1eb 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -88,4 +88,4 @@ dropTable("address").ifExists(); // DROP TYPE IF EXISTS address ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index e1819f0c128..1b71ea8434c 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -391,5 +391,5 @@ selectFrom("user").all().allowFiltering(); // SELECT * FROM user ALLOW FILTERING ``` -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index 66f8e4dfaac..eb95162e3d3 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -105,5 +105,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index 3b8e1518e80..b1f87d276e9 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -17,4 +17,4 @@ Truncate truncate2 = truncate(CqlIdentifier.fromCql("mytable")); Note that, at this stage, the query is ready to build. After creating a TRUNCATE query it does not take any values. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index 19f9c2f8bb1..2c75f869220 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -251,5 +251,5 @@ update("foo") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Assignment]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/querybuilder/update/Assignment.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Assignment]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/update/Assignment.html diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 3b3125de12f..5dcaa3ef8f9 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -84,8 +84,8 @@ empty replicas and token ranges for them. If you need the driver to keep computi token map for these keyspaces, you now must modify the following configuration option: `datastax-java-driver.advanced.metadata.schema.refreshed-keyspaces`. -[Metadata.getKeyspaces()]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/metadata/TokenMap.html +[Metadata.getKeyspaces()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/TokenMap.html #### DSE Graph dependencies are now optional @@ -213,7 +213,7 @@ you can obtain in most web environments by calling `Thread.getContextClassLoader See the javadocs of [SessionBuilder.withClassLoader] for more information. -[SessionBuilder.withClassLoader]: https://docs.datastax.com/en/drivers/java/4.9/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[SessionBuilder.withClassLoader]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- ### 4.1.0 From 89e01fb320a9ed402179a6760501f18ea8f6bbcb Mon Sep 17 00:00:00 2001 From: Patrick Decat Date: Wed, 20 Jan 2021 15:12:26 +0100 Subject: [PATCH 059/395] Fix incorrect link to https://datastax-oss.atlassian.net/browse/JAVA-2899 (#1527) --- upgrade_guide/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 5dcaa3ef8f9..e36a9bebf44 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -4,7 +4,7 @@ #### Cross-datacenter failover -[JAVA-2899](https://datastax-oss.atlassian.net/browse/JAVA-2676) re-introduced the ability to +[JAVA-2899](https://datastax-oss.atlassian.net/browse/JAVA-2899) re-introduced the ability to perform cross-datacenter failover using the driver's built-in load balancing policies. See [Load balancing](../manual/core/loadbalancing/) in the manual for details. From 3c3c3ff61250844be667e9e18d5aa85536c59fd5 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 22 Jan 2021 10:33:07 +0100 Subject: [PATCH 060/395] JAVA-2907 follow-up: Add more revapi exceptions --- core/revapi.json | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/core/revapi.json b/core/revapi.json index b20a307277c..4dfc79dc859 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -5485,6 +5485,60 @@ "code": "java.missing.newClass", "new": "missing-class org.apache.tinkerpop.gremlin.structure.VertexProperty", "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.process.remote.RemoteConnection", + "new": "missing-class org.apache.tinkerpop.gremlin.process.remote.RemoteConnection", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.process.traversal.P", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.P", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.process.traversal.Path", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.Path", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource", + "new": "missing-class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.structure.Edge", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.Edge", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.structure.Property", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.Property", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.structure.Vertex", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.Vertex", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" + }, + { + "code": "java.missing.oldClass", + "old": "missing-class org.apache.tinkerpop.gremlin.structure.VertexProperty", + "new": "missing-class org.apache.tinkerpop.gremlin.structure.VertexProperty", + "justification": "JAVA-2907: switched Tinkerpop dependency to optional" } ] } From a86cb80d1182353a13b525f5b79e62fa6e825efc Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 22 Jan 2021 14:24:36 +0100 Subject: [PATCH 061/395] JAVA-2907 follow-up: Add TinkerPop version compatibility matrix --- manual/core/integration/README.md | 52 ++++++++++++++++++++++++++----- pom.xml | 4 +++ upgrade_guide/README.md | 13 +++++--- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 87be4598121..37b28810105 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -440,7 +440,8 @@ If all of these metrics are disabled, you can remove the dependency: * when Insights monitoring is enabled; * when [Json codecs](../custom_codecs) are being used. -If you don't use either of those features, you can safely exclude the dependency: +Jackson is declared as a required dependency, but the driver can operate normally without it. If you +don't use any of the above features, you can safely exclude the dependency: ```xml @@ -461,7 +462,8 @@ If you don't use either of those features, you can safely exclude the dependency Our [geospatial types](../dse/geotypes/) implementation is based on the [Esri Geometry API](https://github.com/Esri/geometry-api-java). -If you don't use geospatial types anywhere in your application, you can exclude the dependency: +Esri is declared as a required dependency, but the driver can operate normally without it. If you +don't use geospatial types anywhere in your application, you can exclude the dependency: ```xml @@ -471,7 +473,7 @@ If you don't use geospatial types anywhere in your application, you can exclude com.esri.geometry - esri-geometry-api + * @@ -479,9 +481,13 @@ If you don't use geospatial types anywhere in your application, you can exclude #### TinkerPop -[Apache TinkerPop™](http://tinkerpop.apache.org/) is used in our [graph API](../dse/graph/). +[Apache TinkerPop™](http://tinkerpop.apache.org/) is used in our [graph API](../dse/graph/), +introduced in the OSS driver in version 4.4.0 (it was previously a feature only available in the +now-retired DSE driver). -If you don't use DSE graph at all, you can exclude the dependencies: +For driver versions ranging from 4.4.0 to 4.9.0 inclusive, TinkerPop is declared as a required +dependency, but the driver can operate normally without it. If you don't use the graph API at all, +you can exclude the TinkerPop dependencies: ```xml @@ -497,17 +503,47 @@ If you don't use DSE graph at all, you can exclude the dependencies: ``` +Starting with driver 4.10 however, TinkerPop switched to an optional dependency. Excluding TinkerPop +explicitly is not required anymore if you don't use it. _If you do use the graph API though, you now +need to explicitly include the dependencies below in your application_: + +```xml + + org.apache.tinkerpop + gremlin-core + ${tinkerpop.version} + + + org.apache.tinkerpop + tinkergraph-gremlin + ${tinkerpop.version} + +``` + If you do use graph, it is important to keep the precise TinkerPop version that the driver depends on: unlike the driver, TinkerPop does not follow semantic versioning, so even a patch version change -(e.g. 3.3.0 vs 3.3.3) could introduce incompatibilities. So do not declare an explicit dependency in -your application, let the driver pull it transitively. +(e.g. 3.3.0 vs 3.3.3) could introduce incompatibilities. + +Here are the recommended TinkerPop versions for each driver version: + + + + + + + + + + +
    Driver versionTinkerPop version
    4.10.03.4.9
    4.9.03.4.8
    4.8.03.4.5
    4.7.03.4.5
    4.6.03.4.5
    4.5.03.4.5
    4.4.03.3.3
    #### Reactive Streams [Reactive Streams](https://www.reactive-streams.org/) types are referenced in our [reactive API](../reactive/). -If you never call any of the `executeReactive` methods, you can exclude the dependency: +The Reactive Streams API is declared as a required dependency, but the driver can operate normally +without it. If you never call any of the `executeReactive` methods, you can exclude the dependency: ```xml diff --git a/pom.xml b/pom.xml index add6f984b6e..81587e11aa4 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,10 @@ 4.1.16 4.1.51.Final 1.2.1 + 3.4.9 1.7.26 1.0.3 diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index e36a9bebf44..80909ad15da 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -35,7 +35,7 @@ The following methods were deprecated and will be removed in the next major vers Driver 4.10.0 also re-introduced a retry policy whose behavior is equivalent to the `DowngradingConsistencyRetryPolicy` from driver 3.x. See this -[FAQ entry](https://docs.datastax.com/en/developer/java-driver/latest/faq/#where-is-downgrading-consistency-retry-policy) +[FAQ entry](https://docs.datastax.com/en/developer/java-driver/4.10/faq/#where-is-downgrading-consistency-retry-policy) for more information. [`RetryVerdict`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryVerdict.html @@ -89,16 +89,16 @@ token map for these keyspaces, you now must modify the following configuration o #### DSE Graph dependencies are now optional -Until driver 4.9.0, the driver declared a mandatory dependency to Apache Tinkerpop, a library +Until driver 4.9.0, the driver declared a mandatory dependency to Apache TinkerPop, a library required only when connecting to DSE Graph. The vast majority of Apache Cassandra users did not need that library, but were paying the price of having that heavy-weight library in their application's classpath. -_Starting with driver 4.10.0, Tinkerpop is now considered an optional dependency_. +_Starting with driver 4.10.0, TinkerPop is now considered an optional dependency_. Regular users of Apache Cassandra that do not use DSE Graph will not notice any disruption. -DSE Graph users, however, will now have to explicitly declare a dependency to Apache Tinkerpop. This +DSE Graph users, however, will now have to explicitly declare a dependency to Apache TinkerPop. This can be achieved with Maven by adding the following dependencies to the `` section of your POM file: @@ -115,6 +115,9 @@ your POM file: ``` +See the [integration](../manual/core/integration/#tinker-pop) section in the manual for more details +as well as a driver vs. TinkerPop version compatibility matrix. + ### 4.5.x - 4.6.0 These versions are subject to [JAVA-2676](https://datastax-oss.atlassian.net/browse/JAVA-2676), a @@ -135,7 +138,7 @@ Apart from that, the only visible change is that DSE-specific features are now e * new execution methods: `CqlSession.executeGraph`, `CqlSession.executeContinuously*`. They all have default implementations so this doesn't break binary compatibility. You can just ignore them. -* new driver dependencies: Tinkerpop, ESRI, Reactive Streams. If you want to keep your classpath +* new driver dependencies: TinkerPop, ESRI, Reactive Streams. If you want to keep your classpath lean, you can exclude some dependencies when you don't use the corresponding DSE features; see the [Integration>Driver dependencies](../manual/core/integration/#driver-dependencies) section. From 346db046074f35f9b02993f1b607d0300f7c1be0 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 1 Feb 2021 18:11:14 +0100 Subject: [PATCH 062/395] Fix wrong link to the cross-DC failover example --- manual/core/load_balancing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index e65c7ef50d9..3d09f0282b6 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -251,7 +251,7 @@ possibly scaling up its bandwidth to cope with the network traffic spike. This i solution for the cross-datacenter failover issue in general, but we acknowledge that it also requires a purpose-built infrastructure. To help you explore this option, read our [white paper]. -[application-level failover example]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/retry/CrossDatacenterFailover.java +[application-level failover example]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/failover/CrossDatacenterFailover.java [white paper]: https://www.datastax.com/sites/default/files/content/whitepaper/files/2019-09/Designing-Fault-Tolerant-Applications-DataStax.pdf #### Token-aware From 73b8cc196a3cce4403b7ee5e2db8c2c4227225c4 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 10 Feb 2021 16:19:22 +0100 Subject: [PATCH 063/395] Use Entry.comparingByKey instead of Comparator.comparing(Entry::getKey) --- .../core/config/typesafe/TypesafeDriverExecutionProfile.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverExecutionProfile.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverExecutionProfile.java index 63fe6de2bd8..a920ab30df6 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverExecutionProfile.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverExecutionProfile.java @@ -30,7 +30,6 @@ import java.time.Duration; import java.util.AbstractMap; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; @@ -278,7 +277,7 @@ public Object getComparisonKey(@NonNull DriverOption option) { @Override public SortedSet> entrySet() { ImmutableSortedSet.Builder> builder = - ImmutableSortedSet.orderedBy(Comparator.comparing(Map.Entry::getKey)); + ImmutableSortedSet.orderedBy(Map.Entry.comparingByKey()); for (Map.Entry entry : getEffectiveOptions().entrySet()) { builder.add(new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().unwrapped())); } From fd9cb23d369c0e749ddf4feaf6947ee0faf54769 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 12 Feb 2021 13:36:21 +0100 Subject: [PATCH 064/395] Remove unused Maven property --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 81587e11aa4..0152ac1a420 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,6 @@ bom - true UTF-8 UTF-8 1.4.1 From 257c7fafccb701496b844a3d96766379ac4efb23 Mon Sep 17 00:00:00 2001 From: Annamalai Muthalagappan <41874936+annamalai87@users.noreply.github.com> Date: Fri, 12 Feb 2021 11:51:56 -0600 Subject: [PATCH 065/395] JAVA-2918: Exclude invalid peers from schema agreement checks (#1528) Co-authored-by: Alexandre Dutra --- changelog/README.md | 4 + .../core/metadata/DefaultTopologyMonitor.java | 16 +-- .../core/metadata/PeerRowValidator.java | 41 ++++++ .../core/metadata/SchemaAgreementChecker.java | 52 ++++---- .../core/metadata/PeerRowValidatorTest.java | 122 ++++++++++++++++++ .../metadata/SchemaAgreementCheckerTest.java | 109 +++++++++++----- .../core/metadata/TestNodeFactory.java | 7 + 7 files changed, 280 insertions(+), 71 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidator.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidatorTest.java diff --git a/changelog/README.md b/changelog/README.md index 5dd62b63f38..3c1554bdb12 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,10 @@ +### 4.11.0 (in progress) + +- [bug] JAVA-2918: Exclude invalid peers from schema agreement checks + ### 4.10.0 - [improvement] JAVA-2907: Switch Tinkerpop to an optional dependency diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java index 87585199b77..da5fc2115eb 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java @@ -539,24 +539,16 @@ protected InetSocketAddress getBroadcastRpcAddress( * node's broadcast RPC address and host ID; otherwise the driver may not work properly. */ protected boolean isPeerValid(AdminRow peerRow) { - boolean hasPeersRpcAddress = !peerRow.isNull("rpc_address"); - boolean hasPeersV2RpcAddress = - !peerRow.isNull("native_address") && !peerRow.isNull("native_port"); - boolean hasRpcAddress = hasPeersV2RpcAddress || hasPeersRpcAddress; - boolean valid = - hasRpcAddress - && !peerRow.isNull("host_id") - && !peerRow.isNull("data_center") - && !peerRow.isNull("rack") - && !peerRow.isNull("tokens"); - if (!valid) { + if (PeerRowValidator.isValid(peerRow)) { + return true; + } else { LOG.warn( "[{}] Found invalid row in {} for peer: {}. " + "This is likely a gossip or snitch issue, this node will be ignored.", logPrefix, getPeerTableName(), peerRow.getInetAddress("peer")); + return false; } - return valid; } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidator.java new file mode 100644 index 00000000000..735eb4ee1cd --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidator.java @@ -0,0 +1,41 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.datastax.oss.driver.internal.core.metadata; + +import com.datastax.oss.driver.internal.core.adminrequest.AdminRow; +import edu.umd.cs.findbugs.annotations.NonNull; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public class PeerRowValidator { + + /** Returns {@code true} if the given peer row is valid, and {@code false} otherwise. */ + public static boolean isValid(@NonNull AdminRow peerRow) { + + boolean hasPeersRpcAddress = !peerRow.isNull("rpc_address"); + boolean hasPeersV2RpcAddress = + !peerRow.isNull("native_address") && !peerRow.isNull("native_port"); + boolean hasRpcAddress = hasPeersRpcAddress || hasPeersV2RpcAddress; + + return hasRpcAddress + && !peerRow.isNull("host_id") + && !peerRow.isNull("data_center") + && !peerRow.isNull("rack") + && !peerRow.isNull("tokens") + && !peerRow.isNull("schema_version"); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementChecker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementChecker.java index 61f75c573ab..006ce380449 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementChecker.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementChecker.java @@ -32,6 +32,7 @@ import java.time.Duration; import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -105,8 +106,7 @@ private void sendQueries() { } else { CompletionStage localQuery = query("SELECT schema_version FROM system.local WHERE key='local'"); - CompletionStage peersQuery = - query("SELECT host_id, schema_version FROM system.peers"); + CompletionStage peersQuery = query("SELECT * FROM system.peers"); localQuery .thenCombine(peersQuery, this::extractSchemaVersions) @@ -142,31 +142,10 @@ private Set extractSchemaVersions(AdminResult controlNodeResult, AdminResu Map nodes = context.getMetadataManager().getMetadata().getNodes(); for (AdminRow peerRow : peersResult) { - UUID hostId = peerRow.getUuid("host_id"); - if (hostId == null) { - LOG.warn( - "[{}] Missing host_id in system.peers row, excluding from schema agreement check", - logPrefix); - continue; - } - UUID schemaVersion = peerRow.getUuid("schema_version"); - if (schemaVersion == null) { - LOG.warn( - "[{}] Missing schema_version in system.peers row for {}, " - + "excluding from schema agreement check", - logPrefix, - hostId); - continue; - } - Node node = nodes.get(hostId); - if (node == null) { - LOG.warn("[{}] Unknown peer {}, excluding from schema agreement check", logPrefix, hostId); - continue; - } else if (node.getState() != NodeState.UP) { - LOG.debug("[{}] Peer {} is down, excluding from schema agreement check", logPrefix, hostId); - continue; + if (isPeerValid(peerRow, nodes)) { + UUID schemaVersion = Objects.requireNonNull(peerRow.getUuid("schema_version")); + schemaVersions.add(schemaVersion); } - schemaVersions.add(schemaVersion); } return schemaVersions.build(); } @@ -207,4 +186,25 @@ protected CompletionStage query(String queryString) { channel, queryString, queryTimeout, INFINITE_PAGE_SIZE, logPrefix) .start(); } + + protected boolean isPeerValid(AdminRow peerRow, Map nodes) { + if (PeerRowValidator.isValid(peerRow)) { + UUID hostId = peerRow.getUuid("host_id"); + Node node = nodes.get(hostId); + if (node == null) { + LOG.warn("[{}] Unknown peer {}, excluding from schema agreement check", logPrefix, hostId); + return false; + } else if (node.getState() != NodeState.UP) { + LOG.debug("[{}] Peer {} is down, excluding from schema agreement check", logPrefix, hostId); + return false; + } + return true; + } else { + LOG.warn( + "[{}] Found invalid system.peers row for peer: {}, excluding from schema agreement check.", + logPrefix, + peerRow.getInetAddress("peer")); + return false; + } + } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidatorTest.java new file mode 100644 index 00000000000..f02b7169d30 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/PeerRowValidatorTest.java @@ -0,0 +1,122 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.datastax.oss.driver.internal.core.metadata; + +import static com.datastax.oss.driver.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.internal.core.adminrequest.AdminRow; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class PeerRowValidatorTest { + + @DataProvider + public static Object[][] nullColumnsV1() { + return new Object[][] { + {"rpc_address"}, {"host_id"}, {"data_center"}, {"rack"}, {"tokens"}, {"schema_version"} + }; + } + + @DataProvider + public static Object[][] nullColumnsV2() { + return new Object[][] { + {"native_address"}, + {"native_port"}, + {"host_id"}, + {"data_center"}, + {"rack"}, + {"tokens"}, + {"schema_version"} + }; + } + + @Test + @UseDataProvider("nullColumnsV1") + public void should_fail_for_invalid_peer_v1(String nullColumn) { + assertThat(PeerRowValidator.isValid(mockRowV1(nullColumn))).isFalse(); + } + + @Test + @UseDataProvider("nullColumnsV2") + public void should_fail_for_invalid_peer_v2(String nullColumn) { + assertThat(PeerRowValidator.isValid(mockRowV2(nullColumn))).isFalse(); + } + + @Test + public void should_succeed_for_valid_peer_v1() { + AdminRow peerRow = mock(AdminRow.class); + when(peerRow.isNull("host_id")).thenReturn(false); + when(peerRow.isNull("rpc_address")).thenReturn(false); + when(peerRow.isNull("native_address")).thenReturn(true); + when(peerRow.isNull("native_port")).thenReturn(true); + when(peerRow.isNull("data_center")).thenReturn(false); + when(peerRow.isNull("rack")).thenReturn(false); + when(peerRow.isNull("tokens")).thenReturn(false); + when(peerRow.isNull("schema_version")).thenReturn(false); + + assertThat(PeerRowValidator.isValid(peerRow)).isTrue(); + } + + @Test + public void should_succeed_for_valid_peer_v2() { + AdminRow peerRow = mock(AdminRow.class); + when(peerRow.isNull("host_id")).thenReturn(false); + when(peerRow.isNull("rpc_address")).thenReturn(true); + when(peerRow.isNull("native_address")).thenReturn(false); + when(peerRow.isNull("native_port")).thenReturn(false); + when(peerRow.isNull("data_center")).thenReturn(false); + when(peerRow.isNull("rack")).thenReturn(false); + when(peerRow.isNull("tokens")).thenReturn(false); + when(peerRow.isNull("schema_version")).thenReturn(false); + + assertThat(PeerRowValidator.isValid(peerRow)).isTrue(); + } + + private AdminRow mockRowV1(String nullColumn) { + AdminRow peerRow = mock(AdminRow.class); + when(peerRow.isNull("host_id")).thenReturn(nullColumn.equals("host_id")); + when(peerRow.isNull("rpc_address")).thenReturn(nullColumn.equals("rpc_address")); + when(peerRow.isNull("native_address")).thenReturn(true); + when(peerRow.isNull("native_port")).thenReturn(true); + when(peerRow.isNull("data_center")).thenReturn(nullColumn.equals("data_center")); + when(peerRow.isNull("rack")).thenReturn(nullColumn.equals("rack")); + when(peerRow.isNull("tokens")).thenReturn(nullColumn.equals("tokens")); + when(peerRow.isNull("schema_version")).thenReturn(nullColumn.equals("schema_version")); + + return peerRow; + } + + private AdminRow mockRowV2(String nullColumn) { + AdminRow peerRow = mock(AdminRow.class); + when(peerRow.isNull("host_id")).thenReturn(nullColumn.equals("host_id")); + when(peerRow.isNull("native_address")).thenReturn(nullColumn.equals("native_address")); + when(peerRow.isNull("native_port")).thenReturn(nullColumn.equals("native_port")); + when(peerRow.isNull("rpc_address")).thenReturn(true); + when(peerRow.isNull("data_center")).thenReturn(nullColumn.equals("data_center")); + when(peerRow.isNull("rack")).thenReturn(nullColumn.equals("rack")); + when(peerRow.isNull("tokens")).thenReturn(nullColumn.equals("tokens")); + when(peerRow.isNull("schema_version")).thenReturn(nullColumn.equals("schema_version")); + + return peerRow; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementCheckerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementCheckerTest.java index dc143327ecb..26d4aafea03 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementCheckerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/SchemaAgreementCheckerTest.java @@ -35,11 +35,15 @@ import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import io.netty.channel.EventLoop; import java.time.Duration; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Map; +import java.util.Objects; import java.util.Queue; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -49,14 +53,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; -@RunWith(MockitoJUnitRunner.class) +@RunWith(DataProviderRunner.class) public class SchemaAgreementCheckerTest { private static final UUID VERSION1 = UUID.randomUUID(); private static final UUID VERSION2 = UUID.randomUUID(); + private static final UUID NODE_2_HOST_ID = UUID.randomUUID(); + @Mock private InternalDriverContext context; @Mock private DriverConfig config; @Mock private DriverExecutionProfile defaultConfig; @@ -70,10 +76,11 @@ public class SchemaAgreementCheckerTest { @Before public void setup() { + MockitoAnnotations.initMocks(this); when(context.getMetricsFactory()).thenReturn(metricsFactory); node1 = TestNodeFactory.newNode(1, context); - node2 = TestNodeFactory.newNode(2, context); + node2 = TestNodeFactory.newNode(2, NODE_2_HOST_ID, context); when(defaultConfig.getDuration(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT)) .thenReturn(Duration.ofSeconds(1)); @@ -86,7 +93,12 @@ public void setup() { when(config.getDefaultProfile()).thenReturn(defaultConfig); when(context.getConfig()).thenReturn(config); - Map nodes = ImmutableMap.of(node1.getHostId(), node1, node2.getHostId(), node2); + Map nodes = + ImmutableMap.of( + Objects.requireNonNull(node1.getHostId()), + node1, + Objects.requireNonNull(node2.getHostId()), + node2); when(metadata.getNodes()).thenReturn(nodes); when(metadataManager.getMetadata()).thenReturn(metadata); when(context.getMetadataManager()).thenReturn(metadataManager); @@ -124,9 +136,8 @@ public void should_succeed_if_only_one_node() { checker.stubQueries( new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", mockResult(/*empty*/ ))); + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(/*empty*/ ))); // When CompletionStage future = checker.run(); @@ -142,10 +153,8 @@ public void should_succeed_if_versions_match_on_first_try() { checker.stubQueries( new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", - mockResult(mockRow(node2.getHostId(), VERSION1)))); + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(mockValidPeerRow(VERSION1)))); // When CompletionStage future = checker.run(); @@ -162,10 +171,8 @@ public void should_ignore_down_peers() { checker.stubQueries( new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", - mockResult(mockRow(node2.getHostId(), VERSION2)))); + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(mockValidPeerRow(VERSION2)))); // When CompletionStage future = checker.run(); @@ -174,17 +181,34 @@ public void should_ignore_down_peers() { assertThatStage(future).isSuccess(b -> assertThat(b).isTrue()); } + @DataProvider + public static Object[][] malformedPeer() { + return new Object[][] { + // missing host id + {mockPeerRow(null, VERSION2, true, true, true, true)}, + // missing schema version + {mockPeerRow(NODE_2_HOST_ID, null, true, true, true, true)}, + // missing datacenter + {mockPeerRow(NODE_2_HOST_ID, VERSION2, false, true, true, true)}, + // missing rack + {mockPeerRow(NODE_2_HOST_ID, VERSION2, true, false, true, true)}, + // missing RPC address + {mockPeerRow(NODE_2_HOST_ID, VERSION2, true, true, false, true)}, + // missing tokens + {mockPeerRow(NODE_2_HOST_ID, VERSION2, true, true, true, false)}, + }; + } + @Test - public void should_ignore_malformed_rows() { + @UseDataProvider("malformedPeer") + public void should_ignore_malformed_rows(AdminRow malformedPeer) { // Given TestSchemaAgreementChecker checker = new TestSchemaAgreementChecker(channel, context); checker.stubQueries( new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", - mockResult(mockRow(null, VERSION2)))); // missing host_id + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(malformedPeer))); // When CompletionStage future = checker.run(); @@ -201,18 +225,14 @@ public void should_reschedule_if_versions_do_not_match_on_first_try() { // First round new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", - mockResult(mockRow(node2.getHostId(), VERSION2))), + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(mockValidPeerRow(VERSION2))), // Second round new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", - mockResult(mockRow(node2.getHostId(), VERSION1)))); + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(mockValidPeerRow(VERSION1)))); // When CompletionStage future = checker.run(); @@ -230,10 +250,8 @@ public void should_fail_if_versions_do_not_match_after_timeout() { checker.stubQueries( new StubbedQuery( "SELECT schema_version FROM system.local WHERE key='local'", - mockResult(mockRow(null, VERSION1))), - new StubbedQuery( - "SELECT host_id, schema_version FROM system.peers", - mockResult(mockRow(node2.getHostId(), VERSION1)))); + mockResult(mockLocalRow(VERSION1))), + new StubbedQuery("SELECT * FROM system.peers", mockResult(mockValidPeerRow(VERSION1)))); // When CompletionStage future = checker.run(); @@ -274,10 +292,35 @@ private StubbedQuery(String queryString, AdminResult result) { } } - private AdminRow mockRow(UUID hostId, UUID schemaVersion) { + private AdminRow mockLocalRow(@SuppressWarnings("SameParameterValue") UUID schemaVersion) { + AdminRow row = mock(AdminRow.class); + when(row.getUuid("host_id")).thenReturn(node1.getHostId()); + when(row.getUuid("schema_version")).thenReturn(schemaVersion); + return row; + } + + private AdminRow mockValidPeerRow(UUID schemaVersion) { + return mockPeerRow(node2.getHostId(), schemaVersion, true, true, true, true); + } + + private static AdminRow mockPeerRow( + UUID hostId, + UUID schemaVersion, + boolean hasDatacenter, + boolean hasRack, + boolean hasRpcAddress, + boolean hasTokens) { AdminRow row = mock(AdminRow.class); when(row.getUuid("host_id")).thenReturn(hostId); + when(row.isNull("host_id")).thenReturn(hostId == null); when(row.getUuid("schema_version")).thenReturn(schemaVersion); + when(row.isNull("schema_version")).thenReturn(schemaVersion == null); + when(row.isNull("data_center")).thenReturn(!hasDatacenter); + when(row.isNull("rack")).thenReturn(!hasRack); + when(row.isNull("tokens")).thenReturn(!hasTokens); + when(row.isNull("rpc_address")).thenReturn(!hasRpcAddress); + when(row.isNull("native_address")).thenReturn(true); + when(row.isNull("native_port")).thenReturn(true); return row; } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/TestNodeFactory.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/TestNodeFactory.java index 54ab7755c51..c98f5943c70 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/TestNodeFactory.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/TestNodeFactory.java @@ -28,6 +28,13 @@ public static DefaultNode newNode(int lastIpByte, InternalDriverContext context) return node; } + public static DefaultNode newNode(int lastIpByte, UUID hostId, InternalDriverContext context) { + DefaultNode node = newContactPoint(lastIpByte, context); + node.hostId = hostId; + node.broadcastRpcAddress = ((InetSocketAddress) node.getEndPoint().resolve()); + return node; + } + public static DefaultNode newContactPoint(int lastIpByte, InternalDriverContext context) { DefaultEndPoint endPoint = newEndPoint(lastIpByte); return new DefaultNode(endPoint, context); From abcbdde52a887c62048b209f89e1a2e6c61f062b Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 3 Mar 2021 22:10:42 +0100 Subject: [PATCH 066/395] Make field PoolManager.repreparePayloads final --- .../datastax/oss/driver/internal/core/session/PoolManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java index 6127c00226d..68f3519cf52 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java @@ -82,7 +82,7 @@ public class PoolManager implements AsyncAutoCloseable { // (e.g. DefaultPreparedStatement) which are handled at the protocol level (e.g. // CqlPrepareAsyncProcessor). We keep the two separate to avoid introducing a dependency from the // session to a particular processor implementation. - private ConcurrentMap repreparePayloads = + private final ConcurrentMap repreparePayloads = new MapMaker().weakValues().makeMap(); private final String logPrefix; From c72d5b9cb90867d3860629c2be95fa849645d7c6 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sun, 14 Mar 2021 18:41:08 +0100 Subject: [PATCH 067/395] Rename test in OsgiShadedIT --- .../com/datastax/oss/driver/internal/osgi/OsgiShadedIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiShadedIT.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiShadedIT.java index 21d029faa27..a03b7fa796b 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiShadedIT.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiShadedIT.java @@ -47,7 +47,7 @@ public Option[] config() { } @Test - public void test_shaded_reactive() throws Exception { + public void test_shaded() throws Exception { DefaultServiceChecks.checkService(service); } } From f3ee4847464aef151fbc2cc5cf5455de48a5d72a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sun, 14 Mar 2021 20:34:04 +0100 Subject: [PATCH 068/395] Replace deprecated AssertJ method --- .../graph/ContinuousGraphRequestHandlerTest.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java index a5d0c5934d8..de92761e45e 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/graph/ContinuousGraphRequestHandlerTest.java @@ -20,6 +20,7 @@ import static com.datastax.dse.driver.internal.core.graph.GraphTestUtils.tenGraphRows; import static com.datastax.oss.driver.Assertions.assertThat; import static com.datastax.oss.driver.Assertions.assertThatStage; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; @@ -182,9 +183,10 @@ public void should_honor_default_timeout() throws Exception { // will trigger the global timeout and complete it exceptionally globalTimeout.task().run(globalTimeout); - assertThat(page1Future.toCompletableFuture()) - .hasFailedWithThrowableThat() - .isInstanceOf(DriverTimeoutException.class) + assertThat(page1Future.toCompletableFuture()).isCompletedExceptionally(); + + assertThatThrownBy(() -> page1Future.toCompletableFuture().get()) + .hasRootCauseExactlyInstanceOf(DriverTimeoutException.class) .hasMessageContaining("Query timed out after " + defaultTimeout); } } @@ -233,9 +235,10 @@ public void should_honor_statement_timeout() throws Exception { // will trigger the global timeout and complete it exceptionally globalTimeout.task().run(globalTimeout); - assertThat(page1Future.toCompletableFuture()) - .hasFailedWithThrowableThat() - .isInstanceOf(DriverTimeoutException.class) + assertThat(page1Future.toCompletableFuture()).isCompletedExceptionally(); + + assertThatThrownBy(() -> page1Future.toCompletableFuture().get()) + .hasRootCauseExactlyInstanceOf(DriverTimeoutException.class) .hasMessageContaining("Query timed out after " + statementTimeout); } } From 890a8c8c3daff480922017d3d998f2c54eceba95 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sun, 14 Mar 2021 21:06:56 +0100 Subject: [PATCH 069/395] Use DependencyCheck in CompressorSubstitutions --- .../core/protocol/CompressorSubstitutions.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java index fe43bea0863..c760344940c 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; import com.datastax.oss.protocol.internal.Compressor; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; @@ -33,6 +34,7 @@ * BuiltInCompressors#newInstance(String, DriverContext)} to throw an error if the user attempts to * configure it. */ +@SuppressWarnings("unused") public class CompressorSubstitutions { @TargetClass(value = BuiltInCompressors.class, onlyWith = Lz4Present.class) @@ -87,17 +89,9 @@ public static final class DeleteLz4Compressor {} public static final class DeleteSnappyCompressor {} public static class Lz4Present implements BooleanSupplier { - - private static final String LZ4_CLZ_NAME = "net.jpountz.lz4.LZ4Compressor"; - @Override public boolean getAsBoolean() { - try { - Class.forName(LZ4_CLZ_NAME); - return true; - } catch (ClassNotFoundException e) { - return false; - } + return DependencyCheck.LZ4.isPresent(); } } From d75ddadf5bf326c9530ff90c949f4c5ff3a6055e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sun, 14 Mar 2021 19:04:53 +0100 Subject: [PATCH 070/395] JAVA-2917: Include GraalVM substitutions for request processors and geo codecs --- changelog/README.md | 1 + .../type/codec/DseTypeCodecsRegistrar.java | 36 ++++++ .../DseTypeCodecsRegistrarSubstitutions.java | 43 +++++++ .../core/context/DefaultDriverContext.java | 88 ++------------ .../session/BuiltInRequestProcessors.java | 111 ++++++++++++++++++ ...BuiltInRequestProcessorsSubstitutions.java | 88 ++++++++++++++ 6 files changed, 286 insertions(+), 81 deletions(-) create mode 100644 core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java create mode 100644 core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java diff --git a/changelog/README.md b/changelog/README.md index 3c1554bdb12..9255ba3df72 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [improvement] JAVA-2917: Include GraalVM substitutions for request processors and geo codecs - [bug] JAVA-2918: Exclude invalid peers from schema agreement checks ### 4.10.0 diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java new file mode 100644 index 00000000000..5075caa68b2 --- /dev/null +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java @@ -0,0 +1,36 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.dse.driver.internal.core.type.codec; + +import com.datastax.dse.driver.api.core.type.codec.DseTypeCodecs; +import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DseTypeCodecsRegistrar { + + private static final Logger LOG = LoggerFactory.getLogger(DseTypeCodecsRegistrar.class); + + public static void registerDseCodecs(MutableCodecRegistry registry) { + registry.register(DseTypeCodecs.DATE_RANGE); + if (DependencyCheck.ESRI.isPresent()) { + registry.register(DseTypeCodecs.LINE_STRING, DseTypeCodecs.POINT, DseTypeCodecs.POLYGON); + } else { + LOG.debug("ESRI was not found on the classpath: geo codecs will not be available"); + } + } +} diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java new file mode 100644 index 00000000000..51c4958824d --- /dev/null +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java @@ -0,0 +1,43 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.dse.driver.internal.core.type.codec; + +import com.datastax.dse.driver.api.core.type.codec.DseTypeCodecs; +import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import java.util.function.BooleanSupplier; + +@SuppressWarnings("unused") +public class DseTypeCodecsRegistrarSubstitutions { + + @TargetClass(value = DseTypeCodecsRegistrar.class, onlyWith = EsriMissing.class) + public static final class DseTypeCodecsRegistrarEsriMissing { + + @Substitute + public static void registerDseCodecs(MutableCodecRegistry registry) { + registry.register(DseTypeCodecs.DATE_RANGE); + } + } + + public static class EsriMissing implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return !DependencyCheck.ESRI.isPresent(); + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index 5857b0b9be7..f37c2eae3dc 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -16,17 +16,9 @@ package com.datastax.oss.driver.internal.core.context; import com.datastax.dse.driver.api.core.config.DseDriverOption; -import com.datastax.dse.driver.api.core.type.codec.DseTypeCodecs; import com.datastax.dse.driver.internal.core.InsightsClientLifecycleListener; -import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousCqlRequestAsyncProcessor; -import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousCqlRequestSyncProcessor; -import com.datastax.dse.driver.internal.core.cql.continuous.reactive.ContinuousCqlRequestReactiveProcessor; -import com.datastax.dse.driver.internal.core.cql.reactive.CqlRequestReactiveProcessor; -import com.datastax.dse.driver.internal.core.graph.GraphRequestAsyncProcessor; -import com.datastax.dse.driver.internal.core.graph.GraphRequestSyncProcessor; -import com.datastax.dse.driver.internal.core.graph.GraphSupportChecker; -import com.datastax.dse.driver.internal.core.graph.reactive.ReactiveGraphRequestProcessor; import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; +import com.datastax.dse.driver.internal.core.type.codec.DseTypeCodecsRegistrar; import com.datastax.dse.protocol.internal.DseProtocolV1ClientCodecs; import com.datastax.dse.protocol.internal.DseProtocolV2ClientCodecs; import com.datastax.dse.protocol.internal.ProtocolV4ClientCodecsForDse; @@ -60,10 +52,6 @@ import com.datastax.oss.driver.internal.core.channel.DefaultWriteCoalescer; import com.datastax.oss.driver.internal.core.channel.WriteCoalescer; import com.datastax.oss.driver.internal.core.control.ControlConnection; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; -import com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor; -import com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor; import com.datastax.oss.driver.internal.core.metadata.CloudTopologyMonitor; import com.datastax.oss.driver.internal.core.metadata.DefaultTopologyMonitor; import com.datastax.oss.driver.internal.core.metadata.LoadBalancingPolicyWrapper; @@ -83,6 +71,7 @@ import com.datastax.oss.driver.internal.core.protocol.ByteBufPrimitiveCodec; import com.datastax.oss.driver.internal.core.servererrors.DefaultWriteTypeRegistry; import com.datastax.oss.driver.internal.core.servererrors.WriteTypeRegistry; +import com.datastax.oss.driver.internal.core.session.BuiltInRequestProcessors; import com.datastax.oss.driver.internal.core.session.PoolManager; import com.datastax.oss.driver.internal.core.session.RequestProcessor; import com.datastax.oss.driver.internal.core.session.RequestProcessorRegistry; @@ -105,7 +94,6 @@ import edu.umd.cs.findbugs.annotations.Nullable; import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -503,65 +491,10 @@ protected ControlConnection buildControlConnection() { } protected RequestProcessorRegistry buildRequestProcessorRegistry() { - String logPrefix = getSessionName(); - - List> processors = new ArrayList<>(); - - // regular requests (sync and async) - CqlRequestAsyncProcessor cqlRequestAsyncProcessor = new CqlRequestAsyncProcessor(); - CqlRequestSyncProcessor cqlRequestSyncProcessor = - new CqlRequestSyncProcessor(cqlRequestAsyncProcessor); - processors.add(cqlRequestAsyncProcessor); - processors.add(cqlRequestSyncProcessor); - - // prepare requests (sync and async) - CqlPrepareAsyncProcessor cqlPrepareAsyncProcessor = new CqlPrepareAsyncProcessor(); - CqlPrepareSyncProcessor cqlPrepareSyncProcessor = - new CqlPrepareSyncProcessor(cqlPrepareAsyncProcessor); - processors.add(cqlPrepareAsyncProcessor); - processors.add(cqlPrepareSyncProcessor); - - // continuous requests (sync and async) - ContinuousCqlRequestAsyncProcessor continuousCqlRequestAsyncProcessor = - new ContinuousCqlRequestAsyncProcessor(); - ContinuousCqlRequestSyncProcessor continuousCqlRequestSyncProcessor = - new ContinuousCqlRequestSyncProcessor(continuousCqlRequestAsyncProcessor); - processors.add(continuousCqlRequestAsyncProcessor); - processors.add(continuousCqlRequestSyncProcessor); - - // graph requests (sync and async) - GraphRequestAsyncProcessor graphRequestAsyncProcessor = null; - if (DependencyCheck.TINKERPOP.isPresent()) { - graphRequestAsyncProcessor = new GraphRequestAsyncProcessor(this, new GraphSupportChecker()); - GraphRequestSyncProcessor graphRequestSyncProcessor = - new GraphRequestSyncProcessor(graphRequestAsyncProcessor); - processors.add(graphRequestAsyncProcessor); - processors.add(graphRequestSyncProcessor); - } else { - LOG.info( - "Could not register Graph extensions; " - + "this is normal if Tinkerpop was explicitly excluded from classpath"); - } - - // reactive requests (regular, continuous and graph) - if (DependencyCheck.REACTIVE_STREAMS.isPresent()) { - CqlRequestReactiveProcessor cqlRequestReactiveProcessor = - new CqlRequestReactiveProcessor(cqlRequestAsyncProcessor); - ContinuousCqlRequestReactiveProcessor continuousCqlRequestReactiveProcessor = - new ContinuousCqlRequestReactiveProcessor(continuousCqlRequestAsyncProcessor); - processors.add(cqlRequestReactiveProcessor); - processors.add(continuousCqlRequestReactiveProcessor); - if (graphRequestAsyncProcessor != null) { - ReactiveGraphRequestProcessor reactiveGraphRequestProcessor = - new ReactiveGraphRequestProcessor(graphRequestAsyncProcessor); - processors.add(reactiveGraphRequestProcessor); - } - } else { - LOG.info( - "Could not register Reactive extensions; " - + "this is normal if Reactive Streams was explicitly excluded from classpath"); - } - return new RequestProcessorRegistry(logPrefix, processors.toArray(new RequestProcessor[0])); + List> processors = + BuiltInRequestProcessors.createDefaultProcessors(this); + return new RequestProcessorRegistry( + getSessionName(), processors.toArray(new RequestProcessor[0])); } protected CodecRegistry buildCodecRegistry(ProgrammaticArguments arguments) { @@ -570,14 +503,7 @@ protected CodecRegistry buildCodecRegistry(ProgrammaticArguments arguments) { registry = new DefaultCodecRegistry(this.sessionName); } registry.register(arguments.getTypeCodecs()); - registry.register(DseTypeCodecs.DATE_RANGE); - if (DependencyCheck.ESRI.isPresent()) { - registry.register(DseTypeCodecs.LINE_STRING, DseTypeCodecs.POINT, DseTypeCodecs.POLYGON); - } else { - LOG.info( - "Could not register Geo codecs; " - + "this is normal if ESRI was explicitly excluded from classpath"); - } + DseTypeCodecsRegistrar.registerDseCodecs(registry); return registry; } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java new file mode 100644 index 00000000000..a4690847838 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java @@ -0,0 +1,111 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.session; + +import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousCqlRequestAsyncProcessor; +import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousCqlRequestSyncProcessor; +import com.datastax.dse.driver.internal.core.cql.continuous.reactive.ContinuousCqlRequestReactiveProcessor; +import com.datastax.dse.driver.internal.core.cql.reactive.CqlRequestReactiveProcessor; +import com.datastax.dse.driver.internal.core.graph.GraphRequestAsyncProcessor; +import com.datastax.dse.driver.internal.core.graph.GraphRequestSyncProcessor; +import com.datastax.dse.driver.internal.core.graph.GraphSupportChecker; +import com.datastax.dse.driver.internal.core.graph.reactive.ReactiveGraphRequestProcessor; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; +import com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor; +import com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BuiltInRequestProcessors { + + private static final Logger LOG = LoggerFactory.getLogger(BuiltInRequestProcessors.class); + + public static List> createDefaultProcessors(DefaultDriverContext context) { + List> processors = new ArrayList<>(); + addBasicProcessors(processors); + if (DependencyCheck.TINKERPOP.isPresent()) { + addGraphProcessors(context, processors); + } else { + LOG.debug("Tinkerpop was not found on the classpath: graph extensions will not be available"); + } + if (DependencyCheck.REACTIVE_STREAMS.isPresent()) { + addReactiveProcessors(processors); + } else { + LOG.debug( + "Reactive Streams was not found on the classpath: reactive extensions will not be available"); + } + if (DependencyCheck.REACTIVE_STREAMS.isPresent() && DependencyCheck.TINKERPOP.isPresent()) { + addGraphReactiveProcessors(context, processors); + } + return processors; + } + + public static void addBasicProcessors(List> processors) { + // regular requests (sync and async) + CqlRequestAsyncProcessor cqlRequestAsyncProcessor = new CqlRequestAsyncProcessor(); + CqlRequestSyncProcessor cqlRequestSyncProcessor = + new CqlRequestSyncProcessor(cqlRequestAsyncProcessor); + processors.add(cqlRequestAsyncProcessor); + processors.add(cqlRequestSyncProcessor); + + // prepare requests (sync and async) + CqlPrepareAsyncProcessor cqlPrepareAsyncProcessor = new CqlPrepareAsyncProcessor(); + CqlPrepareSyncProcessor cqlPrepareSyncProcessor = + new CqlPrepareSyncProcessor(cqlPrepareAsyncProcessor); + processors.add(cqlPrepareAsyncProcessor); + processors.add(cqlPrepareSyncProcessor); + + // continuous requests (sync and async) + ContinuousCqlRequestAsyncProcessor continuousCqlRequestAsyncProcessor = + new ContinuousCqlRequestAsyncProcessor(); + ContinuousCqlRequestSyncProcessor continuousCqlRequestSyncProcessor = + new ContinuousCqlRequestSyncProcessor(continuousCqlRequestAsyncProcessor); + processors.add(continuousCqlRequestAsyncProcessor); + processors.add(continuousCqlRequestSyncProcessor); + } + + public static void addGraphProcessors( + DefaultDriverContext context, List> processors) { + GraphRequestAsyncProcessor graphRequestAsyncProcessor = + new GraphRequestAsyncProcessor(context, new GraphSupportChecker()); + GraphRequestSyncProcessor graphRequestSyncProcessor = + new GraphRequestSyncProcessor(graphRequestAsyncProcessor); + processors.add(graphRequestAsyncProcessor); + processors.add(graphRequestSyncProcessor); + } + + public static void addReactiveProcessors(List> processors) { + CqlRequestReactiveProcessor cqlRequestReactiveProcessor = + new CqlRequestReactiveProcessor(new CqlRequestAsyncProcessor()); + ContinuousCqlRequestReactiveProcessor continuousCqlRequestReactiveProcessor = + new ContinuousCqlRequestReactiveProcessor(new ContinuousCqlRequestAsyncProcessor()); + processors.add(cqlRequestReactiveProcessor); + processors.add(continuousCqlRequestReactiveProcessor); + } + + public static void addGraphReactiveProcessors( + DefaultDriverContext context, List> processors) { + ReactiveGraphRequestProcessor reactiveGraphRequestProcessor = + new ReactiveGraphRequestProcessor( + new GraphRequestAsyncProcessor(context, new GraphSupportChecker())); + processors.add(reactiveGraphRequestProcessor); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java new file mode 100644 index 00000000000..e0afbb06892 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java @@ -0,0 +1,88 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.session; + +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BooleanSupplier; + +@SuppressWarnings("unused") +public class BuiltInRequestProcessorsSubstitutions { + + @TargetClass(value = BuiltInRequestProcessors.class, onlyWith = GraphMissingReactiveMissing.class) + public static final class BuiltInRequestProcessorsGraphMissingReactiveMissing { + + @Substitute + public static List> createDefaultProcessors( + DefaultDriverContext context) { + List> processors = new ArrayList<>(); + BuiltInRequestProcessors.addBasicProcessors(processors); + return processors; + } + } + + @TargetClass(value = BuiltInRequestProcessors.class, onlyWith = GraphMissingReactivePresent.class) + public static final class BuiltInRequestProcessorsGraphMissingReactivePresent { + + @Substitute + public static List> createDefaultProcessors( + DefaultDriverContext context) { + List> processors = new ArrayList<>(); + BuiltInRequestProcessors.addBasicProcessors(processors); + BuiltInRequestProcessors.addReactiveProcessors(processors); + return processors; + } + } + + @TargetClass(value = BuiltInRequestProcessors.class, onlyWith = GraphPresentReactiveMissing.class) + public static final class BuiltInRequestProcessorsGraphPresentReactiveMissing { + + @Substitute + public static List> createDefaultProcessors( + DefaultDriverContext context) { + List> processors = new ArrayList<>(); + BuiltInRequestProcessors.addBasicProcessors(processors); + BuiltInRequestProcessors.addGraphProcessors(context, processors); + return processors; + } + } + + public static class GraphMissingReactiveMissing implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return !DependencyCheck.TINKERPOP.isPresent() + && !DependencyCheck.REACTIVE_STREAMS.isPresent(); + } + } + + public static class GraphMissingReactivePresent implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return !DependencyCheck.TINKERPOP.isPresent() && DependencyCheck.REACTIVE_STREAMS.isPresent(); + } + } + + public static class GraphPresentReactiveMissing implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return DependencyCheck.TINKERPOP.isPresent() && !DependencyCheck.REACTIVE_STREAMS.isPresent(); + } + } +} From 0df1d2ea5ce398b73405ff4482070ed1e9ddf180 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sun, 14 Mar 2021 16:45:55 +0100 Subject: [PATCH 071/395] JAVA-2927: Make Dropwizard truly optional --- changelog/README.md | 1 + .../driver/api/core/config/OptionsMap.java | 2 +- .../core/metrics/DefaultMetricsFactory.java | 58 +++++ .../DefaultMetricsFactorySubstitutions.java | 55 +++++ .../internal/core/metrics/MetricPaths.java | 2 +- .../core/metrics/NoopMetricsFactory.java | 64 +++++ .../internal/core/util/DependencyCheck.java | 1 + core/src/main/resources/reference.conf | 53 ++-- .../context/MockedDriverContextFactory.java | 2 +- .../core/metrics/NoopMetricsFactoryTest.java | 62 +++++ manual/core/integration/README.md | 33 ++- manual/core/metrics/README.md | 233 ++++++++++++------ metrics/micrometer/pom.xml | 4 + metrics/microprofile/pom.xml | 4 + pom.xml | 2 +- 15 files changed, 469 insertions(+), 107 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactory.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactoryTest.java diff --git a/changelog/README.md b/changelog/README.md index 9255ba3df72..968219ce36d 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [bug] JAVA-2927: Make Dropwizard truly optional - [improvement] JAVA-2917: Include GraalVM substitutions for request processors and geo codecs - [bug] JAVA-2918: Exclude invalid peers from schema agreement checks diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index c5eb7829deb..b0fd39b57c2 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -322,7 +322,7 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put( TypedDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_INTERVAL, Duration.ofMinutes(5)); - map.put(TypedDriverOption.METRICS_FACTORY_CLASS, "DropwizardMetricsFactory"); + map.put(TypedDriverOption.METRICS_FACTORY_CLASS, "DefaultMetricsFactory"); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, Duration.ofSeconds(12)); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS, 3); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_INTERVAL, Duration.ofMinutes(5)); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java new file mode 100644 index 00000000000..e6d78d30dc1 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java @@ -0,0 +1,58 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.Metrics; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import java.util.Optional; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ThreadSafe +public class DefaultMetricsFactory implements MetricsFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultMetricsFactory.class); + + private final MetricsFactory delegate; + + @SuppressWarnings("unused") + public DefaultMetricsFactory(DriverContext context) { + if (DependencyCheck.DROPWIZARD.isPresent()) { + this.delegate = new DropwizardMetricsFactory(context); + } else { + this.delegate = new NoopMetricsFactory(context); + } + LOG.debug("[{}] Using {}", context.getSessionName(), delegate.getClass().getSimpleName()); + } + + @Override + public Optional getMetrics() { + return delegate.getMetrics(); + } + + @Override + public SessionMetricUpdater getSessionUpdater() { + return delegate.getSessionUpdater(); + } + + @Override + public NodeMetricUpdater newNodeUpdater(Node node) { + return delegate.newNodeUpdater(node); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java new file mode 100644 index 00000000000..3965efc8354 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java @@ -0,0 +1,55 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import java.util.function.BooleanSupplier; + +@SuppressWarnings("unused") +public class DefaultMetricsFactorySubstitutions { + + @TargetClass(value = DefaultMetricsFactory.class, onlyWith = DropwizardMissing.class) + public static final class DefaultMetricsFactoryDropwizardMissing { + + @Alias + @TargetElement(name = "delegate") + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) + private MetricsFactory delegate; + + @Substitute + @TargetElement(name = TargetElement.CONSTRUCTOR_NAME) + public DefaultMetricsFactoryDropwizardMissing(DriverContext context) { + this.delegate = new NoopMetricsFactory(context); + } + } + + @TargetClass(value = DropwizardMetricsFactory.class, onlyWith = DropwizardMissing.class) + @Delete + public static final class DeleteDropwizardMetricsFactory {} + + public static class DropwizardMissing implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return !DependencyCheck.DROPWIZARD.isPresent(); + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricPaths.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricPaths.java index b95edc74f73..1b513884bc5 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricPaths.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricPaths.java @@ -30,7 +30,7 @@ public class MetricPaths { - private static final Logger LOG = LoggerFactory.getLogger(DropwizardMetricsFactory.class); + private static final Logger LOG = LoggerFactory.getLogger(MetricPaths.class); public static Set parseSessionMetricPaths(List paths, String logPrefix) { Set result = new HashSet<>(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactory.java new file mode 100644 index 00000000000..501f554dd2f --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.Metrics; +import java.util.List; +import java.util.Optional; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ThreadSafe +public class NoopMetricsFactory implements MetricsFactory { + + private static final Logger LOG = LoggerFactory.getLogger(NoopMetricsFactory.class); + + @SuppressWarnings("unused") + public NoopMetricsFactory(DriverContext context) { + String logPrefix = context.getSessionName(); + DriverExecutionProfile config = context.getConfig().getDefaultProfile(); + List enabledSessionMetrics = + config.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED); + List enabledNodeMetrics = + config.getStringList(DefaultDriverOption.METRICS_NODE_ENABLED); + if (!enabledSessionMetrics.isEmpty() || !enabledNodeMetrics.isEmpty()) { + LOG.warn( + "[{}] Some session-level or node-level metrics were enabled, " + + "but NoopMetricsFactory is being used: all metrics will be empty", + logPrefix); + } + } + + @Override + public Optional getMetrics() { + return Optional.empty(); + } + + @Override + public SessionMetricUpdater getSessionUpdater() { + return NoopSessionMetricUpdater.INSTANCE; + } + + @Override + public NodeMetricUpdater newNodeUpdater(Node node) { + return NoopNodeMetricUpdater.INSTANCE; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java index 1f3b6ae4480..8af213b71ed 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java @@ -36,6 +36,7 @@ public enum DependencyCheck { "com.fasterxml.jackson.core.JsonParser", // jackson-databind "com.fasterxml.jackson.databind.ObjectMapper"), + DROPWIZARD("com.codahale.metrics.MetricRegistry"), ; /** diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 23e3fc2d14e..53b8e8afdf3 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1313,23 +1313,40 @@ datastax-java-driver { factory { # The class for the metrics factory. # - # The driver provides Dropwizard, Micrometer and MicroProfile metrics out of the box. - # To use Dropwizard, this value should be set to "DropwizardMetricsFactory". To use - # Micrometer, set the value to "MicrometerMetricsFactory". To use MicroProfile, set the value - # to "MicroProfileMetricsFactory". + # The driver provides out-of-the-box support for three metrics libraries: Dropwizard, + # Micrometer and MicroProfile Metrics. # - # For Micrometer and MicroProfile, you will also need to add an additional dependency: - # com.datastax.oss:java-driver-metrics-micrometer and - # com.datastax.oss:java-driver-metrics-microprofile respectively. + # Dropwizard is the default metrics library in the driver; to use Dropwizard, this value + # should be left to its default, "DefaultMetricsFactory", or set to + # "DropwizardMetricsFactory". The only difference between the two is that the former will work + # even if Dropwizard is not present on the classpath (in which case it will silently disable + # metrics), while the latter requires its presence. # - # If you would like to use a different metrics framework, change the factory class to the - # fully-qualified name of a class that implements - # com.datastax.oss.driver.internal.core.metrics.MetricsFactory. + # To select Micrometer, set the value to "MicrometerMetricsFactory", and to select + # MicroProfile Metrics, set the value to "MicroProfileMetricsFactory". For these libraries to + # be used, you will also need to add an additional dependency: + # - Micrometer: com.datastax.oss:java-driver-metrics-micrometer + # - MicroProfile: com.datastax.oss:java-driver-metrics-microprofile + # + # If you would like to use another metrics library, set this value to the fully-qualified name + # of a class that implements com.datastax.oss.driver.internal.core.metrics.MetricsFactory. + # + # It is also possible to use "NoopMetricsFactory", which forcibly disables metrics completely. + # In fact, "DefaultMetricsFactory" delegates to "DropwizardMetricsFactory" if Dropwizard is + # present on the classpath, or to "NoopMetricsFactory" if it isn't. + # + # Note: specifying a metrics factory is not enough to enable metrics; for the driver to + # actually start collecting metrics, you also need to specify which metrics to collect. See + # the following options for more information: + # - advanced.metrics.session.enabled + # - advanced.metrics.node.enabled + # + # See also the driver online manual for extensive instructions about how to configure metrics. # # Required: yes # Modifiable at runtime: no # Overridable in a profile: no - class = DropwizardMetricsFactory + class = DefaultMetricsFactory } # The session-level metrics (all disabled by default). # @@ -1417,7 +1434,7 @@ datastax-java-driver { # Extra configuration (for the metrics that need it) - # Required: if the 'cql-requests' metric is enabled + # Required: if the 'cql-requests' metric is enabled, and Dropwizard / HdrHistogram is used. # Modifiable at runtime: no # Overridable in a profile: no cql-requests { @@ -1457,7 +1474,8 @@ datastax-java-driver { refresh-interval = 5 minutes } - # Required: if the 'throttling.delay' metric is enabled + # Required: if the 'throttling.delay' metric is enabled, and Dropwizard / HdrHistogram is + # used. # Modifiable at runtime: no # Overridable in a profile: no throttling.delay { @@ -1466,7 +1484,8 @@ datastax-java-driver { refresh-interval = 5 minutes } - # Required: if the 'continuous-cql-requests' metric is enabled + # Required: if the 'continuous-cql-requests' metric is enabled, and Dropwizard / HdrHistogram + # is used # Modifiable at runtime: no # Overridable in a profile: no continuous-cql-requests { @@ -1504,7 +1523,7 @@ datastax-java-driver { refresh-interval = 5 minutes } - # Required: if the 'graph-requests' metric is enabled + # Required: if the 'graph-requests' metric is enabled, and Dropwizard / HdrHistogram is used # Modifiable at runtime: no # Overridable in a profile: no graph-requests { @@ -1695,7 +1714,7 @@ datastax-java-driver { # See cql-requests in the `session` section # - # Required: if the 'cql-messages' metric is enabled + # Required: if the 'cql-messages' metric is enabled, and Dropwizard / HdrHistogram is used # Modifiable at runtime: no # Overridable in a profile: no cql-messages { @@ -1706,7 +1725,7 @@ datastax-java-driver { # See graph-requests in the `session` section # - # Required: if the 'graph-messages' metric is enabled + # Required: if the 'graph-messages' metric is enabled, and Dropwizard / HdrHistogram is used # Modifiable at runtime: no # Overridable in a profile: no graph-messages { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java index 15d6d296fc4..580f558dc33 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java @@ -51,7 +51,7 @@ public static DefaultDriverContext defaultDriverContext( when(blankProfile.isDefined(DefaultDriverOption.METRICS_FACTORY_CLASS)) .thenReturn(true); when(blankProfile.getString(DefaultDriverOption.METRICS_FACTORY_CLASS)) - .thenReturn("DropwizardMetricsFactory"); + .thenReturn("DefaultMetricsFactory"); return blankProfile; }); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactoryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactoryTest.java new file mode 100644 index 00000000000..bcf40ef301f --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/NoopMetricsFactoryTest.java @@ -0,0 +1,62 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import ch.qos.logback.classic.Level; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.util.LoggerTest; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import java.util.Collections; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class NoopMetricsFactoryTest { + + @Test + public void should_log_warning_when_metrics_enabled() { + // given + InternalDriverContext context = mock(InternalDriverContext.class); + DriverConfig config = mock(DriverConfig.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + when(context.getSessionName()).thenReturn("MockSession"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) + .thenReturn(Collections.singletonList(DefaultSessionMetric.CQL_REQUESTS.getPath())); + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(NoopMetricsFactory.class, Level.WARN); + + // when + new NoopMetricsFactory(context); + + // then + verify(logger.appender, times(1)).doAppend(logger.loggingEventCaptor.capture()); + assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); + assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) + .contains("[MockSession] Some session-level or node-level metrics were enabled"); + } +} diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 37b28810105..4927089f98c 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -56,6 +56,20 @@ right dependencies: See this page. + + + Instrumenting the driver and gathering metrics using the Micrometer metrics library. + + java‑driver‑metrics‑micrometer + See this page. + + + + Instrumenting the driver and gathering metrics using the MicroProfile Metrics library. + + java‑driver‑metrics‑microprofile + See this page. + "Bill Of Materials": can help manage versions if you use multiple driver artifacts. @@ -390,12 +404,11 @@ enable compression. See the [Compression](../compression/) page for more details #### Metrics The driver exposes [metrics](../metrics/) through the -[Dropwizard](http://metrics.dropwizard.io/4.0.0/manual/index.html) library. +[Dropwizard](http://metrics.dropwizard.io/4.1.2/) library. The dependency is declared as required, but metrics are optional. If you've disabled all metrics, or -if you are using a [different metrics framework](../metrics/#changing-the-metrics-frameworks), and -you never call [Session.getMetrics] anywhere in your application, then you can remove the -dependency: +if you are using a different metrics library, and you never call [Session.getMetrics] anywhere in +your application, then you can remove the dependency: ```xml @@ -411,12 +424,14 @@ dependency: ``` -In addition, "timer" metrics use [HdrHistogram](http://hdrhistogram.github.io/HdrHistogram/) to -record latency percentiles. At the time of writing, these metrics are: `cql-requests`, -`throttling.delay` and `cql-messages`; you can also identify them by reading the comments in the -[configuration reference](../configuration/reference/) (look for "exposed as a Timer"). +In addition, when using Dropwizard, "timer" metrics use +[HdrHistogram](http://hdrhistogram.github.io/HdrHistogram/) to record latency percentiles. At the +time of writing, these metrics are: `cql-requests`, `throttling.delay` and `cql-messages`; you can +also identify them by reading the comments in the [configuration +reference](../configuration/reference/) (look for "exposed as a Timer"). -If all of these metrics are disabled, you can remove the dependency: +If all of these metrics are disabled, or if you use a different metrics library, you can remove the +dependency: ```xml diff --git a/manual/core/metrics/README.md b/manual/core/metrics/README.md index 4a15a95f2eb..276245dc524 100644 --- a/manual/core/metrics/README.md +++ b/manual/core/metrics/README.md @@ -2,69 +2,72 @@ ### Quick overview -* `advanced.metrics` in the configuration. All disabled by default, can be selected individually. +* `advanced.metrics` in the configuration. All metrics disabled by default. To enable, select the + metrics library to use, then define which individual metrics to activate. * some metrics are per node, others global to the session, or both. * unlike driver 3, JMX is not provided out of the box. You need to add the dependency manually. ----- -The driver exposes measurements of its internal behavior through a choice of three popular metrics -frameworks: [Dropwizard Metrics], [Micrometer Metrics] or [MicroProfile Metrics]. Application -developers can select a metrics framework, which metrics are enabled, and export them to a -monitoring tool. +The driver is able to report measurements of its internal behavior to a variety of metrics +libraries, and ships with bindings for three popular ones: [Dropwizard Metrics] , [Micrometer +Metrics] and [MicroProfile Metrics]. -### Structure - -There are two categories of metrics: +### Selecting a Metrics Library -* session-level: the measured data is global to a `Session` instance. For example, `connected-nodes` - measures the number of nodes to which we have connections. -* node-level: the data is specific to a node (and therefore there is one metric instance per node). - For example, `pool.open-connections` measures the number of connections open to this particular - node. - -Metric names are path-like, dot-separated strings. The driver prefixes them with the name of the -session (see `session-name` in the configuration), and in the case of node-level metrics, `nodes` -followed by a textual representation of the node's address. For example: +#### Dropwizard Metrics -``` -s0.connected-nodes => 2 -s0.nodes.127_0_0_1:9042.pool.open-connections => 2 -s0.nodes.127_0_0_2:9042.pool.open-connections => 1 -``` +Dropwizard is the driver's default metrics library; there is no additional configuration nor any +extra dependency to add if you wish to use Dropwizard. -### Configuration +#### Micrometer -By default, all metrics are disabled. You can turn them on individually in the configuration, by -adding their name to these lists: +To use Micrometer you must: + +1. Define `MicrometerMetricsFactory` as the metrics factory to use in the driver configuration: ``` datastax-java-driver.advanced.metrics { - session.enabled = [ connected-nodes, cql-requests ] - node.enabled = [ pool.open-connections, pool.in-flight ] + factory.class = MicrometerMetricsFactory } ``` -To find out which metrics are available, see the [reference configuration]. It contains a -commented-out line for each metric, with detailed explanations on its intended usage. +2. Add a dependency to `java-driver-metrics-micrometer` in your application. This separate driver +module contains the actual bindings for Micrometer, and depends itself on the Micrometer library: -If you specify a metric that doesn't exist, it will be ignored and a warning will be logged. +```xml + + com.datastax.oss + java-driver-metrics-micrometer + ${driver.version} + +``` -The `metrics` section may also contain additional configuration for some specific metrics; again, -see the [reference configuration] for more details. +3. You should also exclude Dropwizard and HdrHistogram, which are two transitive dependencies of the +driver, because they are not relevant when using Micrometer: -#### Changing the Metrics Frameworks +```xml + + com.datastax.oss + java-driver-core + + + io.dropwizard.metrics + metrics-core + + + org.hdrhistogram + HdrHistogram + + + +``` -The default metrics framework is Dropwizard. You can change this to either Micrometer or -MicroProfile in the configuration: +#### MicroProfile Metrics -``` -datastax-java-driver.advanced.metrics { - factory.class = MicrometerMetricsFactory -} -``` +To use MicroProfile Metrics you must: -or +1. Define `MicroProfileMetricsFactory` as the metrics factory to use in the driver configuration: ``` datastax-java-driver.advanced.metrics { @@ -72,32 +75,100 @@ datastax-java-driver.advanced.metrics { } ``` -In addition to the configuration change above, you will also need to include the appropriate module -in your project. For Micrometer: +2. Add a dependency to `java-driver-metrics-microprofile` in your application. This separate driver +module contains the actual bindings for MicroProfile, and depends itself on the MicroProfile Metrics +library: ```xml com.datastax.oss - java-driver-metrics-micrometer + java-driver-metrics-microprofile ${driver.version} ``` -For MicroProfile: +3. You should also exclude Dropwizard and HdrHistogram, which are two transitive dependencies of the +driver, because they are not relevant when using MicroProfile Metrics: ```xml com.datastax.oss - java-driver-metrics-microprofile - ${driver.version} + java-driver-core + + + io.dropwizard.metrics + metrics-core + + + org.hdrhistogram + HdrHistogram + + ``` -#### Metric Registry +#### Other Metrics libraries + +Other metrics libraries can also be used. However, you will need to provide a custom +metrics factory. Simply implement the +`com.datastax.oss.driver.internal.core.metrics.MetricsFactory` interface for your library of choice, +then pass the fully-qualified name of that implementation class to the driver using the +`advanced.metrics.factory.class` option. See the [reference configuration]. + +You will certainly need to add the metrics library as a dependency to your application as well. +It is also recommended excluding Dropwizard and HdrHistogram, as shown above. + +### Enabling specific driver metrics + +Now that the metrics library is configured, you need to activate the driver metrics you are +interested in. + +There are two categories of driver metrics: + +* session-level: the measured data is global to a `Session` instance. For example, `connected-nodes` + measures the number of nodes to which we have connections. +* node-level: the data is specific to a node (and therefore there is one metric instance per node). + For example, `pool.open-connections` measures the number of connections open to this particular + node. + +Metric names are path-like, dot-separated strings. The driver prefixes them with the name of the +session (see `session-name` in the configuration), and in the case of node-level metrics, `nodes` +followed by a textual representation of the node's address. For example: + +``` +s0.connected-nodes => 2 +s0.nodes.127_0_0_1:9042.pool.open-connections => 2 +s0.nodes.127_0_0_2:9042.pool.open-connections => 1 +``` + +To find out which metrics are available, see the [reference configuration]. It contains a +commented-out line for each metric, with detailed explanations on its intended usage. + +By default, all metrics are disabled. You can turn them on individually in the configuration, by +adding their name to these lists: + +``` +datastax-java-driver.advanced.metrics { + session.enabled = [ connected-nodes, cql-requests ] + node.enabled = [ pool.open-connections, pool.in-flight ] +} +``` + +If you specify a metric that doesn't exist, it will be ignored, and a warning will be logged. -For any of the three metrics frameworks, you can provide an external Metric Registry object when -building a Session. This will easily allow your application to export the driver's operational -metrics to whatever reporting system you want to use. +Finally, if you are using Dropwizard and enabled any metric of timer type, such as `cql-requests`, +it is also possible to provide additional configuration to fine-tune the underlying histogram's +characteristics and precision, such as its highest expected latency, its number of significant +digits to use, and its refresh interval. Again, see the [reference configuration] for more details. + +### Using an external metric registry + +Regardless of which metrics library is used, you can provide an external metric registry object when +building a session. This allows the driver to transparently export its operational metrics to +whatever reporting system you want to use. + +To pass a metric registry object to the session, use the `CqlSessionBuilder.withMetricRegistry()` +method: ```java CqlSessionBuilder builder = CqlSession.builder(); @@ -105,43 +176,51 @@ builder.withMetricRegistry(myRegistryObject); CqlSession session = builder.build(); ``` -In the above example, `myRegistryObject` should be an instance of the base registry type for the -metrics framework you are using: +Beware that the driver does not inspect the provided object, it simply passes it to the metrics +factory in use; it is the user's responsibility to provide registry objects compatible with the +metrics library in use. For reference, here are the expected base types for the three built-in +metrics libraries: -``` -Dropwizard: com.codahale.metrics.MetricRegistry -Micrometer: io.micrometer.core.instrument.MeterRegistry -MicroProfile: org.eclipse.microprofile.metrics.MetricRegistry -``` +* Dropwizard: `com.codahale.metrics.MetricRegistry` +* Micrometer: `io.micrometer.core.instrument.MeterRegistry` +* MicroProfile: `org.eclipse.microprofile.metrics.MetricRegistry` + +**NOTE:** MicroProfile **requires** an external instance of its registry to be provided. For +Micrometer, if no registry object is provided, Micrometer's `globalRegistry` will be used. For +Dropwizard, if no registry object is provided, an instance of `MetricRegistry` will be created and +used (in which case, it can be retrieved programmatically if needed, see below). -**NOTE:** Only MicroProfile **requires** an external instance of its Registry to be provided. For -Micrometer, if no Registry object is provided, Micrometer's `globalRegistry` will be used. For -Dropwizard, if no Registry object is provided, an instance of `MetricRegistry` will be created and -used. +### Programmatic access to driver metrics -### Export +Programmatic access to driver metrics is only available when using Dropwizard Metrics. Users of +other libraries are encouraged to provide an external registry when creating the driver session (see +above), then use it to gain programmatic access to the driver metrics. -The Dropwizard `MetricRegistry` is exposed via `session.getMetrics().getRegistry()`. You can -retrieve it and configure a `Reporter` to send the metrics to a monitoring tool. +The Dropwizard `MetricRegistry` object is exposed in the driver API via +`session.getMetrics().getRegistry()`. You can retrieve it and, for example, configure a `Reporter` +to send the metrics to a monitoring tool. -**NOTE:** At this time, `session.getMetrics()` is not available when using Micrometer or -MicroProfile metrics. If you wish to use either of those metrics frameworks, it is recommended to -provide a Registry implementation to the driver as described in the [Metric Registry -section](#metric-registry), and follow best practices for exporting that registry to your desired -reporting framework. +**NOTE:** Beware that `session.getMetrics()` is not available when using other metrics libraries, +and will throw a `NoClassDefFoundError` at runtime if accessed in such circumstances. -#### JMX +### Exposing driver metrics with JMX Unlike previous driver versions, JMX support is not included out of the box. +The way to add JMX support to your application depends largely on the metrics library being used. We +show below instructions for Dropwizard only. Micrometer also has support for JMX: please refer to +its [official documentation][Micrometer JMX]. + +#### Dropwizard Metrics + Add the following dependency to your application (make sure the version matches the `metrics-core` dependency of the driver): -``` +```xml io.dropwizard.metrics metrics-jmx - 4.0.2 + 4.1.2 ``` @@ -201,14 +280,14 @@ JmxReporter reporter = reporter.start(); ``` -#### Other protocols +### Exporting metrics with other protocols Dropwizard Metrics has built-in reporters for other output formats: JSON (via a servlet), stdout, CSV files, SLF4J logs and Graphite. Refer to their [manual][Dropwizard manual] for more details. - -[Dropwizard Metrics]: http://metrics.dropwizard.io/4.0.0/manual/index.html -[Dropwizard Manual]: http://metrics.dropwizard.io/4.0.0/getting-started.html#reporting-via-http +[Dropwizard Metrics]: https://metrics.dropwizard.io/4.1.2 +[Dropwizard Manual]: https://metrics.dropwizard.io/4.1.2/getting-started.html [Micrometer Metrics]: https://micrometer.io/docs +[Micrometer JMX]: https://micrometer.io/docs/registry/jmx [MicroProfile Metrics]: https://github.com/eclipse/microprofile-metrics [reference configuration]: ../configuration/reference/ \ No newline at end of file diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 8b0134f3307..5593610f010 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -51,6 +51,10 @@ io.dropwizard.metrics metrics-core + + org.hdrhistogram + HdrHistogram + diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 138deb6f11a..f6549e4d73c 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -51,6 +51,10 @@ io.dropwizard.metrics metrics-core + + org.hdrhistogram + HdrHistogram + diff --git a/pom.xml b/pom.xml index 0152ac1a420..b834259994b 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ 4.0.3 2.0.0-M19 2.22.2 - 20.3.0 + 21.0.0.2 false ${skipTests} From 367284fd0aa2bc3583f3afc87e11825129c2c8b9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 15 Mar 2021 16:21:54 +0100 Subject: [PATCH 072/395] Memoize DependencyCheck.isPresent --- .../internal/core/util/DependencyCheck.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java index 8af213b71ed..0accb5388a0 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java @@ -15,7 +15,8 @@ */ package com.datastax.oss.driver.internal.core.util; -import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import com.datastax.oss.driver.shaded.guava.common.base.Supplier; +import com.datastax.oss.driver.shaded.guava.common.base.Suppliers; /** * A set of driver optional dependencies and a common mechanism to test the presence of such @@ -39,21 +40,32 @@ public enum DependencyCheck { DROPWIZARD("com.codahale.metrics.MetricRegistry"), ; + @SuppressWarnings("ImmutableEnumChecker") + private final Supplier present; + /** - * The fully-qualified name of classes that must exist for the dependency to work properly; we use - * them to test the presence of the whole dependency on the classpath, including its transitive - * dependencies if applicable. This assumes that if these classes are present, then the entire - * library is present and functional, and vice versa. + * We use the given fully-qualified names of classes to test the presence of the whole dependency + * on the classpath, including its transitive dependencies if applicable. This assumes that if + * these classes are present, then the entire library is present and functional, and vice versa. * *

    Note: some of the libraries declared here may be shaded; in these cases the shade plugin * will replace the package names listed above with names starting with {@code * com.datastax.oss.driver.shaded.*}, but the presence check would still work as expected. */ - @SuppressWarnings("ImmutableEnumChecker") - private final ImmutableSet fqcns; - - DependencyCheck(String... fqcns) { - this.fqcns = ImmutableSet.copyOf(fqcns); + DependencyCheck(String... classNamesToTest) { + this.present = + Suppliers.memoize( + () -> { + for (String classNameToTest : classNamesToTest) { + // Always use the driver class loader, assuming that the driver classes and + // the dependency classes are either being loaded by the same class loader, + // or – as in OSGi deployments – by two distinct, but compatible class loaders. + if (Reflection.loadClass(null, classNameToTest) == null) { + return false; + } + } + return true; + }); } /** @@ -62,14 +74,6 @@ public enum DependencyCheck { * @return true if the dependency is present and loadable, false otherwise. */ public boolean isPresent() { - for (String fqcn : fqcns) { - // Always use the driver class loader, assuming that the driver classes and - // the dependency classes are either being loaded by the same class loader, - // or – as in OSGi deployments – by two distinct, but compatible class loaders. - if (Reflection.loadClass(null, fqcn) == null) { - return false; - } - } - return true; + return present.get(); } } From 8b88f280b419d28e0b09e8a38deb41d76f91c445 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 15 Mar 2021 17:01:10 +0100 Subject: [PATCH 073/395] JAVA-2916: Annotate generated classes with `@SuppressWarnings` (#1530) --- changelog/README.md | 1 + .../mapper/processor/dao/DaoImplementationGenerator.java | 5 +++++ .../mapper/processor/entity/EntityHelperGenerator.java | 5 +++++ .../mapper/processor/mapper/MapperBuilderGenerator.java | 5 +++++ .../processor/mapper/MapperImplementationGenerator.java | 5 +++++ 5 files changed, 21 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 968219ce36d..7fe757e4343 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [improvement] JAVA-2916: Annotate generated classes with `@SuppressWarnings` - [bug] JAVA-2927: Make Dropwizard truly optional - [improvement] JAVA-2917: Include GraalVM substitutions for request processors and geo codecs - [bug] JAVA-2918: Exclude invalid peers from schema agreement checks diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoImplementationGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoImplementationGenerator.java index 479da635e20..ef4d516a275 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoImplementationGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoImplementationGenerator.java @@ -37,6 +37,7 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import com.datastax.oss.driver.shaded.guava.common.collect.Maps; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; @@ -301,6 +302,10 @@ protected JavaFile.Builder getContents() { TypeSpec.Builder classBuilder = TypeSpec.classBuilder(implementationName) .addJavadoc(JAVADOC_GENERATED_WARNING) + .addAnnotation( + AnnotationSpec.builder(SuppressWarnings.class) + .addMember("value", "\"all\"") + .build()) .addModifiers(Modifier.PUBLIC) .addSuperinterface(ClassName.get(interfaceElement)); diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGenerator.java index 2ac1e9adade..dc33d7deb12 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGenerator.java @@ -26,6 +26,7 @@ import com.datastax.oss.driver.internal.mapper.processor.util.generation.BindableHandlingSharedCode; import com.datastax.oss.driver.internal.mapper.processor.util.generation.GenericTypeConstantGenerator; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; @@ -87,6 +88,10 @@ protected JavaFile.Builder getContents() { TypeSpec.Builder classContents = TypeSpec.classBuilder(helperName) .addJavadoc(JAVADOC_GENERATED_WARNING) + .addAnnotation( + AnnotationSpec.builder(SuppressWarnings.class) + .addMember("value", "\"all\"") + .build()) .addModifiers(Modifier.PUBLIC) .superclass( ParameterizedTypeName.get( diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperBuilderGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperBuilderGenerator.java index 93ec4f5acfc..c1a4bb078b4 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperBuilderGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperBuilderGenerator.java @@ -21,6 +21,7 @@ import com.datastax.oss.driver.internal.mapper.processor.GeneratedNames; import com.datastax.oss.driver.internal.mapper.processor.ProcessorContext; import com.datastax.oss.driver.internal.mapper.processor.SingleFileCodeGenerator; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; @@ -62,6 +63,10 @@ protected JavaFile.Builder getContents() { getSessionClass()) .addJavadoc(JAVADOC_PARAGRAPH_SEPARATOR) .addJavadoc(JAVADOC_GENERATED_WARNING) + .addAnnotation( + AnnotationSpec.builder(SuppressWarnings.class) + .addMember("value", "\"all\"") + .build()) .addModifiers(Modifier.PUBLIC) .addMethod( MethodSpec.constructorBuilder() diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperImplementationGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperImplementationGenerator.java index bd2bf69428f..ca050f291e1 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperImplementationGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/mapper/MapperImplementationGenerator.java @@ -24,6 +24,7 @@ import com.datastax.oss.driver.internal.mapper.processor.SingleFileCodeGenerator; import com.datastax.oss.driver.internal.mapper.processor.util.NameIndex; import com.datastax.oss.driver.internal.mapper.processor.util.generation.GeneratedCodePatterns; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.JavaFile; @@ -91,6 +92,10 @@ protected JavaFile.Builder getContents() { GeneratedNames.mapperBuilder(interfaceElement)) .addJavadoc(JAVADOC_PARAGRAPH_SEPARATOR) .addJavadoc(JAVADOC_GENERATED_WARNING) + .addAnnotation( + AnnotationSpec.builder(SuppressWarnings.class) + .addMember("value", "\"all\"") + .build()) .addModifiers(Modifier.PUBLIC) .addSuperinterface(ClassName.get(interfaceElement)); From a70705d1fc1231c7b57388aa89ab6a9976918bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Tudenh=C3=B6fner?= Date: Mon, 15 Mar 2021 18:52:29 +0100 Subject: [PATCH 074/395] JAVA-2704: Remove protocol v5 beta status (#1437) Co-authored-by: Alexandre Dutra --- bom/pom.xml | 2 +- changelog/README.md | 1 + .../api/core/DefaultProtocolVersion.java | 7 +++++-- .../oss/driver/api/core/ProtocolVersion.java | 3 ++- .../core/DefaultProtocolVersionRegistry.java | 13 ++++++++++-- .../DefaultProtocolVersionRegistryTest.java | 15 +++++++++++-- .../oss/driver/core/cql/NowInSecondsIT.java | 21 ++----------------- 7 files changed, 35 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 1527d39f924..6aaae045061 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -71,7 +71,7 @@ com.datastax.oss native-protocol - 1.4.12 + 1.4.13-SNAPSHOT com.datastax.oss diff --git a/changelog/README.md b/changelog/README.md index 7fe757e4343..420fd72b325 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [improvement] JAVA-2704: Remove protocol v5 beta status, add v6-beta - [improvement] JAVA-2916: Annotate generated classes with `@SuppressWarnings` - [bug] JAVA-2927: Make Dropwizard truly optional - [improvement] JAVA-2917: Include GraalVM substitutions for request processors and geo codecs diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/DefaultProtocolVersion.java b/core/src/main/java/com/datastax/oss/driver/api/core/DefaultProtocolVersion.java index 1a207a9ede9..9d0135dec8f 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/DefaultProtocolVersion.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/DefaultProtocolVersion.java @@ -30,14 +30,17 @@ public enum DefaultProtocolVersion implements ProtocolVersion { /** Version 4, supported by Cassandra 2.2 and above. */ V4(ProtocolConstants.Version.V4, false), + /** Version 5, supported by Cassandra 4.0 and above. */ + V5(ProtocolConstants.Version.V5, false), + /** - * Version 5, currently supported as a beta preview in Cassandra 3.10 and above. + * Version 6, currently supported as a beta preview in Cassandra 4.0 and above. * *

    Do not use this in production. * * @see ProtocolVersion#isBeta() */ - V5(ProtocolConstants.Version.V5, true), + V6(ProtocolConstants.Version.V6, true), ; // Note that, for the sake of convenience, we also expose shortcuts to these constants on the // ProtocolVersion interface. If you add a new enum constant, remember to update the interface as diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/ProtocolVersion.java b/core/src/main/java/com/datastax/oss/driver/api/core/ProtocolVersion.java index a633bcf892f..9aacf85c0a2 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/ProtocolVersion.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/ProtocolVersion.java @@ -31,13 +31,14 @@ public interface ProtocolVersion { ProtocolVersion V3 = DefaultProtocolVersion.V3; ProtocolVersion V4 = DefaultProtocolVersion.V4; ProtocolVersion V5 = DefaultProtocolVersion.V5; + ProtocolVersion V6 = DefaultProtocolVersion.V6; ProtocolVersion DSE_V1 = DseProtocolVersion.DSE_V1; ProtocolVersion DSE_V2 = DseProtocolVersion.DSE_V2; /** The default version used for {@link Detachable detached} objects. */ // Implementation note: we can't use the ProtocolVersionRegistry here, this has to be a // compile-time constant. - ProtocolVersion DEFAULT = DefaultProtocolVersion.V4; + ProtocolVersion DEFAULT = DefaultProtocolVersion.V5; /** * A numeric code that uniquely identifies the version (this is the code used in network frames). diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistry.java index 2dff6ff22f8..08826758e98 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistry.java @@ -61,6 +61,9 @@ public class DefaultProtocolVersionRegistry implements ProtocolVersionRegistry { @VisibleForTesting static final Version DSE_6_0_0 = Objects.requireNonNull(Version.parse("6.0.0")); + @VisibleForTesting + static final Version DSE_7_0_0 = Objects.requireNonNull(Version.parse("7.0.0")); + private final String logPrefix; public DefaultProtocolVersionRegistry(String logPrefix) { @@ -150,9 +153,12 @@ public ProtocolVersion highestCommon(Collection nodes) { } else if (dseVersion.compareTo(DSE_6_0_0) < 0) { // DSE 5.1 removeHigherThan(DefaultProtocolVersion.V4, DseProtocolVersion.DSE_V1, candidates); - } else { + } else if (dseVersion.compareTo(DSE_7_0_0) < 0) { // DSE 6 removeHigherThan(DefaultProtocolVersion.V4, DseProtocolVersion.DSE_V2, candidates); + } else { + // DSE 7.0 + removeHigherThan(DefaultProtocolVersion.V5, DseProtocolVersion.DSE_V2, candidates); } } else { // not DSE Version cassandraVersion = node.getCassandraVersion(); @@ -181,9 +187,12 @@ public ProtocolVersion highestCommon(Collection nodes) { } else if (cassandraVersion.compareTo(Version.V2_2_0) < 0) { // 2.1.0 removeHigherThan(DefaultProtocolVersion.V3, null, candidates); - } else { + } else if (cassandraVersion.compareTo(Version.V4_0_0) < 0) { // 2.2, 3.x removeHigherThan(DefaultProtocolVersion.V4, null, candidates); + } else { + // 4.0 + removeHigherThan(DefaultProtocolVersion.V5, null, candidates); } } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java index c86d7c824c5..9d81a3bdd3d 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java @@ -20,6 +20,7 @@ import static com.datastax.oss.driver.api.core.ProtocolVersion.V3; import static com.datastax.oss.driver.api.core.ProtocolVersion.V4; import static com.datastax.oss.driver.api.core.ProtocolVersion.V5; +import static com.datastax.oss.driver.api.core.ProtocolVersion.V6; import static com.datastax.oss.driver.internal.core.DefaultProtocolFeature.DATE_TYPE; import static com.datastax.oss.driver.internal.core.DefaultProtocolFeature.SMALLINT_AND_TINYINT_TYPES; import static org.assertj.core.api.Assertions.assertThat; @@ -64,7 +65,13 @@ public void should_not_downgrade_if_no_lower_version() { @Test public void should_downgrade_from_dse_to_oss() { - assertThat(registry.downgrade(DseProtocolVersion.DSE_V1).get()).isEqualTo(ProtocolVersion.V4); + assertThat(registry.downgrade(DseProtocolVersion.DSE_V1).get()).isEqualTo(ProtocolVersion.V5); + } + + @Test + public void should_pick_dse_v2_as_highest_common_when_all_nodes_are_dse_7() { + assertThat(registry.highestCommon(ImmutableList.of(mockDseNode("7.0"), mockDseNode("7.1")))) + .isEqualTo(DseProtocolVersion.DSE_V2); } @Test @@ -124,6 +131,7 @@ public void should_support_date_type_on_oss_v4_and_later() { assertThat(registry.supports(V3, DATE_TYPE)).isFalse(); assertThat(registry.supports(V4, DATE_TYPE)).isTrue(); assertThat(registry.supports(V5, DATE_TYPE)).isTrue(); + assertThat(registry.supports(V6, DATE_TYPE)).isTrue(); assertThat(registry.supports(DSE_V1, DATE_TYPE)).isTrue(); assertThat(registry.supports(DSE_V2, DATE_TYPE)).isTrue(); } @@ -133,6 +141,7 @@ public void should_support_smallint_and_tinyint_types_on_oss_v4_and_later() { assertThat(registry.supports(V3, SMALLINT_AND_TINYINT_TYPES)).isFalse(); assertThat(registry.supports(V4, SMALLINT_AND_TINYINT_TYPES)).isTrue(); assertThat(registry.supports(V5, SMALLINT_AND_TINYINT_TYPES)).isTrue(); + assertThat(registry.supports(V6, SMALLINT_AND_TINYINT_TYPES)).isTrue(); assertThat(registry.supports(DSE_V1, SMALLINT_AND_TINYINT_TYPES)).isTrue(); assertThat(registry.supports(DSE_V2, SMALLINT_AND_TINYINT_TYPES)).isTrue(); } @@ -152,7 +161,9 @@ private Node mockDseNode(String rawDseVersion) { .thenReturn(ImmutableMap.of(DseNodeProperties.DSE_VERSION, dseVersion)); Version cassandraVersion; - if (dseVersion.compareTo(DefaultProtocolVersionRegistry.DSE_6_0_0) >= 0) { + if (dseVersion.compareTo(DefaultProtocolVersionRegistry.DSE_7_0_0) >= 0) { + cassandraVersion = Version.parse("5.0"); + } else if (dseVersion.compareTo(DefaultProtocolVersionRegistry.DSE_6_0_0) >= 0) { cassandraVersion = Version.parse("4.0"); } else if (dseVersion.compareTo(DefaultProtocolVersionRegistry.DSE_5_1_0) >= 0) { cassandraVersion = Version.parse("3.11"); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java index 255875f4d54..2b570329d51 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java @@ -18,9 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.DefaultProtocolVersion; -import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.cql.BatchStatement; import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; @@ -45,27 +42,13 @@ @CassandraRequirement(min = "4.0") @DseRequirement( // Use next version -- not sure if it will be in by then, but as a reminder to check - min = "6.9", + min = "7.0", description = "Feature not available in DSE yet") public class NowInSecondsIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); - private static final SessionRule SESSION_RULE = buildSessionRule(); - - private static SessionRule buildSessionRule() { - // Reminder to revisit the test when V5 comes out of beta: remove the custom config loader and - // inline this method. - assertThat(DefaultProtocolVersion.V5.isBeta()) - .as("This test can be simplified now that protocol v5 is stable") - .isTrue(); - return SessionRule.builder(CCM_RULE) - .withConfigLoader( - DriverConfigLoader.programmaticBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") - .build()) - .build(); - } + private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); From 0f522118e68e632d0d9fab9ce057e81c4e3993c9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 15 Mar 2021 22:17:23 +0100 Subject: [PATCH 075/395] Add loggers for CCM and Simulacron --- integration-tests/src/test/resources/logback-test.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/resources/logback-test.xml b/integration-tests/src/test/resources/logback-test.xml index 77fa051841e..078ca8a1911 100644 --- a/integration-tests/src/test/resources/logback-test.xml +++ b/integration-tests/src/test/resources/logback-test.xml @@ -28,6 +28,8 @@ + + - + From 632424655af70a3edbfacf21a0c493f923e9d215 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 15 Mar 2021 22:17:46 +0100 Subject: [PATCH 076/395] Upgrade to Simulacron 0.11.0 --- .../ProtocolVersionInitialNegotiationIT.java | 233 ++++++++++++++++-- .../core/cql/BoundStatementSimulacronIT.java | 10 +- .../datastax/oss/driver/mapper/ProfileIT.java | 34 ++- .../driver/mapper/StatementAttributesIT.java | 32 ++- pom.xml | 2 +- 5 files changed, 261 insertions(+), 50 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java index 1bc10fa6e83..64e38e7268e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java @@ -18,7 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import com.datastax.dse.driver.api.core.metadata.DseNodeProperties; +import com.datastax.dse.driver.api.core.DseProtocolVersion; import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.DefaultProtocolVersion; @@ -26,8 +26,6 @@ import com.datastax.oss.driver.api.core.UnsupportedProtocolVersionException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; -import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; @@ -46,7 +44,7 @@ public class ProtocolVersionInitialNegotiationIT { @CassandraRequirement( min = "2.1", max = "2.2", - description = "required to downgrade to an older version") + description = "Only C* in [2.1,2.2[ has V3 as its highest version") @Test public void should_downgrade_to_v3() { try (CqlSession session = SessionUtils.newSession(ccm)) { @@ -56,18 +54,36 @@ public void should_downgrade_to_v3() { } @CassandraRequirement( - min = "2.1", - max = "2.2", - description = "required to downgrade to an older version") + min = "2.2", + max = "4.0", + description = "Only C* in [2.2,4.0[ has V4 as its highest version") + @Test + public void should_downgrade_to_v4() { + try (CqlSession session = SessionUtils.newSession(ccm)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); + session.execute("select * from system.local"); + } + } + + @DseRequirement( + max = "6.0", + description = "Only DSE in [*,6.0[ has DSE_V1 as its highest version") @Test - public void should_fail_if_provided_version_isnt_supported() { + public void should_downgrade_to_dse_v1() { + try (CqlSession session = SessionUtils.newSession(ccm)) { + assertThat(session.getContext().getProtocolVersion()).isEqualTo(DseProtocolVersion.DSE_V1); + session.execute("select * from system.local"); + } + } + + @CassandraRequirement(max = "2.2", description = "Only C* in [*,2.2[ has V4 unsupported") + @Test + public void should_fail_if_provided_v4_is_not_supported() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") .build(); - try (CqlSession session = SessionUtils.newSession(ccm, loader)) { - assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); - session.execute("select * from system.local"); + try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { fail("Expected an AllNodesFailedException"); } catch (AllNodesFailedException anfe) { Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); @@ -79,24 +95,110 @@ public void should_fail_if_provided_version_isnt_supported() { } } + @CassandraRequirement( + min = "2.1", + max = "4.0", + description = "Only C* in [2.1,4.0[ has V5 unsupported or supported as beta") + @Test + public void should_fail_if_provided_v5_is_not_supported() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") + .build(); + try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { + fail("Expected an AllNodesFailedException"); + } catch (AllNodesFailedException anfe) { + Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); + assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); + UnsupportedProtocolVersionException unsupportedException = + (UnsupportedProtocolVersionException) cause; + assertThat(unsupportedException.getAttemptedVersions()) + .containsOnly(DefaultProtocolVersion.V5); + } + } + + @DseRequirement( + max = "7.0", + description = "Only DSE in [*,7.0[ has V5 unsupported or supported as beta") + @Test + public void should_fail_if_provided_v5_is_not_supported_dse() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") + .build(); + try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { + fail("Expected an AllNodesFailedException"); + } catch (AllNodesFailedException anfe) { + Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); + assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); + UnsupportedProtocolVersionException unsupportedException = + (UnsupportedProtocolVersionException) cause; + assertThat(unsupportedException.getAttemptedVersions()) + .containsOnly(DefaultProtocolVersion.V5); + } + } + + @DseRequirement(max = "5.1", description = "Only DSE in [*,5.1[ has DSE_V1 unsupported") + @Test + public void should_fail_if_provided_dse_v1_is_not_supported() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "DSE_V1") + .build(); + try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { + fail("Expected an AllNodesFailedException"); + } catch (AllNodesFailedException anfe) { + Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); + assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); + UnsupportedProtocolVersionException unsupportedException = + (UnsupportedProtocolVersionException) cause; + assertThat(unsupportedException.getAttemptedVersions()) + .containsOnly(DseProtocolVersion.DSE_V1); + } + } + + @DseRequirement(max = "6.0", description = "Only DSE in [*,6.0[ has DSE_V2 unsupported") + @Test + public void should_fail_if_provided_dse_v2_is_not_supported() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "DSE_V2") + .build(); + try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { + fail("Expected an AllNodesFailedException"); + } catch (AllNodesFailedException anfe) { + Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); + assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); + UnsupportedProtocolVersionException unsupportedException = + (UnsupportedProtocolVersionException) cause; + assertThat(unsupportedException.getAttemptedVersions()) + .containsOnly(DseProtocolVersion.DSE_V2); + } + } + /** Note that this test will need to be updated as new protocol versions are introduced. */ - @CassandraRequirement(min = "2.2", description = "required to meet default protocol version") - @DseRequirement(min = "6.0", description = "required to meet default protocol version") + @CassandraRequirement(min = "4.0", description = "Only C* in [4.0,*[ has V5 supported") @Test public void should_not_downgrade_if_server_supports_latest_version() { try (CqlSession session = SessionUtils.newSession(ccm)) { - Metadata metadata = session.getMetadata(); - Node node = metadata.getNodes().values().iterator().next(); - boolean isDse = node.getExtras().containsKey(DseNodeProperties.DSE_VERSION); - assertThat(session.getContext().getProtocolVersion()) - .isEqualTo(isDse ? ProtocolVersion.DSE_V2 : ProtocolVersion.V4); + assertThat(session.getContext().getProtocolVersion()).isEqualTo(ProtocolVersion.V5); session.execute("select * from system.local"); } } - @CassandraRequirement(min = "2.2", description = "required to use an older protocol version") + /** Note that this test will need to be updated as new protocol versions are introduced. */ + @DseRequirement(min = "6.0", description = "Only DSE in [6.0,*[ has DSE_V2 supported") + @Test + public void should_not_downgrade_if_server_supports_latest_version_dse() { + try (CqlSession session = SessionUtils.newSession(ccm)) { + assertThat(session.getContext().getProtocolVersion()).isEqualTo(ProtocolVersion.DSE_V2); + session.execute("select * from system.local"); + } + } + + @CassandraRequirement(min = "2.1", description = "Only C* in [2.1,*[ has V3 supported") @Test - public void should_use_explicitly_provided_protocol_version() { + public void should_use_explicitly_provided_v3() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") @@ -106,4 +208,95 @@ public void should_use_explicitly_provided_protocol_version() { session.execute("select * from system.local"); } } + + @DseRequirement(min = "4.8", description = "Only DSE in [4.8,*[ has V3 supported") + @Test + public void should_use_explicitly_provided_v3_dse() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); + session.execute("select * from system.local"); + } + } + + @CassandraRequirement(min = "2.2", description = "Only C* in [2.2,*[ has V4 supported") + @Test + public void should_use_explicitly_provided_v4() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); + session.execute("select * from system.local"); + } + } + + @DseRequirement(min = "5.0", description = "Only DSE in [5.0,*[ has V4 supported") + @Test + public void should_use_explicitly_provided_v4_dse() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); + session.execute("select * from system.local"); + } + } + + @CassandraRequirement(min = "4.0", description = "Only C* in [4.0,*[ has V5 supported") + @Test + public void should_use_explicitly_provided_v5() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(5); + session.execute("select * from system.local"); + } + } + + @DseRequirement(min = "7.0", description = "Only DSE in [7.0,*[ has V5 supported") + @Test + public void should_use_explicitly_provided_v5_dse() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(5); + session.execute("select * from system.local"); + } + } + + @DseRequirement(min = "5.1", description = "Only DSE in [5.1,*[ has DSE_V1 supported") + @Test + public void should_use_explicitly_provided_dse_v1() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "DSE_V1") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion()).isEqualTo(DseProtocolVersion.DSE_V1); + session.execute("select * from system.local"); + } + } + + @DseRequirement(min = "6.0", description = "Only DSE in [6.0,*[ has DSE_V2 supported") + @Test + public void should_use_explicitly_provided_dse_v2() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "DSE_V2") + .build(); + try (CqlSession session = SessionUtils.newSession(ccm, loader)) { + assertThat(session.getContext().getProtocolVersion()).isEqualTo(DseProtocolVersion.DSE_V2); + session.execute("select * from system.local"); + } + } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java index 4f31dff1717..71fc5eb429e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementSimulacronIT.java @@ -36,8 +36,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import java.time.Duration; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.ClassRule; @@ -125,8 +125,8 @@ public void should_use_consistencies() { @Test public void should_use_timeout_from_simple_statement() { try (CqlSession session = SessionUtils.newSession(SIMULACRON_RULE)) { - Map params = ImmutableMap.of("k", 0); - Map paramTypes = ImmutableMap.of("k", "int"); + LinkedHashMap params = new LinkedHashMap<>(ImmutableMap.of("k", 0)); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("k", "int")); SIMULACRON_RULE .cluster() .prime( @@ -156,8 +156,8 @@ public void should_use_timeout_from_simple_statement() { @Test public void should_use_timeout() { try (CqlSession session = SessionUtils.newSession(SIMULACRON_RULE)) { - Map params = ImmutableMap.of("k", 0); - Map paramTypes = ImmutableMap.of("k", "int"); + LinkedHashMap params = new LinkedHashMap<>(ImmutableMap.of("k", 0)); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("k", "int")); // set timeout on simple statement, but will be unused since overridden by bound statement. SIMULACRON_RULE .cluster() diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ProfileIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ProfileIT.java index d03f280704d..eac0410759e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ProfileIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ProfileIT.java @@ -49,8 +49,8 @@ import com.datastax.oss.simulacron.common.stubbing.PrimeDsl; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -216,9 +216,11 @@ private void assertServerSideCl(ConsistencyLevel expectedCl) { } private static void primeInsertQuery() { - Map params = - ImmutableMap.of("pk", SAMPLE_ENTITY.getPk(), "data", SAMPLE_ENTITY.getData()); - Map paramTypes = ImmutableMap.of("pk", "uuid", "data", "ascii"); + LinkedHashMap params = + new LinkedHashMap<>( + ImmutableMap.of("pk", SAMPLE_ENTITY.getPk(), "data", SAMPLE_ENTITY.getData())); + LinkedHashMap paramTypes = + new LinkedHashMap<>(ImmutableMap.of("pk", "uuid", "data", "ascii")); SIMULACRON_RULE .cluster() .prime( @@ -234,8 +236,9 @@ private static void primeInsertQuery() { } private static void primeDeleteQuery() { - Map params = ImmutableMap.of("pk", SAMPLE_ENTITY.getPk()); - Map paramTypes = ImmutableMap.of("pk", "uuid"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", SAMPLE_ENTITY.getPk())); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("pk", "uuid")); SIMULACRON_RULE .cluster() .prime( @@ -252,8 +255,9 @@ private static void primeDeleteQuery() { } private static void primeSelectQuery() { - Map params = ImmutableMap.of("pk", SAMPLE_ENTITY.getPk()); - Map paramTypes = ImmutableMap.of("pk", "uuid"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", SAMPLE_ENTITY.getPk())); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("pk", "uuid")); SIMULACRON_RULE .cluster() .prime( @@ -270,8 +274,9 @@ private static void primeSelectQuery() { } private static void primeCountQuery() { - Map params = ImmutableMap.of("pk", SAMPLE_ENTITY.getPk()); - Map paramTypes = ImmutableMap.of("pk", "uuid"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", SAMPLE_ENTITY.getPk())); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("pk", "uuid")); SIMULACRON_RULE .cluster() .prime( @@ -288,9 +293,11 @@ private static void primeCountQuery() { } private static void primeUpdateQuery() { - Map params = - ImmutableMap.of("pk", SAMPLE_ENTITY.getPk(), "data", SAMPLE_ENTITY.getData()); - Map paramTypes = ImmutableMap.of("pk", "uuid", "data", "ascii"); + LinkedHashMap params = + new LinkedHashMap<>( + ImmutableMap.of("pk", SAMPLE_ENTITY.getPk(), "data", SAMPLE_ENTITY.getData())); + LinkedHashMap paramTypes = + new LinkedHashMap<>(ImmutableMap.of("pk", "uuid", "data", "ascii")); SIMULACRON_RULE .cluster() .prime( @@ -329,6 +336,7 @@ public interface SimpleDao { void delete(Simple simple); @Select + @SuppressWarnings("UnusedReturnValue") Simple findByPk(UUID pk); @Query("SELECT count(*) FROM ks.simple WHERE pk=:pk") diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java index d32fd1f9517..46a10d465ad 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java @@ -47,7 +47,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import java.nio.ByteBuffer; -import java.util.Map; +import java.util.LinkedHashMap; import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -194,8 +194,10 @@ public void should_fail_runtime_attributes_bad() { } private static void primeInsertQuery() { - Map params = ImmutableMap.of("pk", simple.getPk(), "data", simple.getData()); - Map paramTypes = ImmutableMap.of("pk", "uuid", "data", "ascii"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", simple.getPk(), "data", simple.getData())); + LinkedHashMap paramTypes = + new LinkedHashMap<>(ImmutableMap.of("pk", "uuid", "data", "ascii")); SIMULACRON_RULE .cluster() .prime( @@ -210,8 +212,9 @@ private static void primeInsertQuery() { } private static void primeDeleteQuery() { - Map params = ImmutableMap.of("pk", simple.getPk()); - Map paramTypes = ImmutableMap.of("pk", "uuid"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", simple.getPk())); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("pk", "uuid")); SIMULACRON_RULE .cluster() .prime( @@ -227,8 +230,9 @@ private static void primeDeleteQuery() { } private static void primeSelectQuery() { - Map params = ImmutableMap.of("pk", simple.getPk()); - Map paramTypes = ImmutableMap.of("pk", "uuid"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", simple.getPk())); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("pk", "uuid")); SIMULACRON_RULE .cluster() .prime( @@ -244,8 +248,9 @@ private static void primeSelectQuery() { } private static void primeCountQuery() { - Map params = ImmutableMap.of("pk", simple.getPk()); - Map paramTypes = ImmutableMap.of("pk", "uuid"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", simple.getPk())); + LinkedHashMap paramTypes = new LinkedHashMap<>(ImmutableMap.of("pk", "uuid")); SIMULACRON_RULE .cluster() .prime( @@ -261,8 +266,10 @@ private static void primeCountQuery() { } private static void primeUpdateQuery() { - Map params = ImmutableMap.of("pk", simple.getPk(), "data", simple.getData()); - Map paramTypes = ImmutableMap.of("pk", "uuid", "data", "ascii"); + LinkedHashMap params = + new LinkedHashMap<>(ImmutableMap.of("pk", simple.getPk(), "data", simple.getData())); + LinkedHashMap paramTypes = + new LinkedHashMap<>(ImmutableMap.of("pk", "uuid", "data", "ascii")); SIMULACRON_RULE .cluster() .prime( @@ -319,10 +326,12 @@ public interface SimpleDao { void delete2(Simple simple); @Select + @SuppressWarnings("UnusedReturnValue") Simple findByPk(UUID pk, Function function); @Select @StatementAttributes(consistencyLevel = "ANY", serialConsistencyLevel = "QUORUM", pageSize = 13) + @SuppressWarnings("UnusedReturnValue") Simple findByPk2(UUID pk); @Query("SELECT count(*) FROM ks.simple WHERE pk=:pk") @@ -330,6 +339,7 @@ public interface SimpleDao { @Query("SELECT count(*) FROM ks.simple WHERE pk=:pk") @StatementAttributes(consistencyLevel = "ANY", serialConsistencyLevel = "QUORUM", pageSize = 13) + @SuppressWarnings("UnusedReturnValue") long count2(UUID pk); @Update diff --git a/pom.xml b/pom.xml index b834259994b..eb6ab69f887 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ 6.0.0 6.0.3 4.13.4 - 0.10.0 + 0.11.0 1.1.4 2.28 2.5.0 From c3cb29664057e5fb470465ac36fd58649d14b630 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 16 Mar 2021 10:18:37 +0100 Subject: [PATCH 077/395] JAVA-2925: Consider protocol version unsupported when server requires USE_BETA flag for it (#1537) --- changelog/README.md | 1 + .../core/channel/ProtocolInitHandler.java | 8 ++-- ...ChannelFactoryProtocolNegotiationTest.java | 38 +++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 420fd72b325..984dd9259c5 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [bug] JAVA-2925: Consider protocol version unsupported when server requires USE_BETA flag for it - [improvement] JAVA-2704: Remove protocol v5 beta status, add v6-beta - [improvement] JAVA-2916: Annotate generated classes with `@SuppressWarnings` - [bug] JAVA-2927: Make Dropwizard truly optional diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java index 1f9c0e2c689..99462ce3462 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ProtocolInitHandler.java @@ -326,9 +326,11 @@ void onResponse(Message response) { (step == Step.OPTIONS && querySupportedOptions) || step == Step.STARTUP; boolean serverOrProtocolError = error.code == ErrorCode.PROTOCOL_ERROR || error.code == ErrorCode.SERVER_ERROR; - if (firstRequest - && serverOrProtocolError - && error.message.contains("Invalid or unsupported protocol version")) { + boolean badProtocolVersionMessage = + error.message.contains("Invalid or unsupported protocol version") + // JAVA-2925: server is behind driver and considers the proposed version as beta + || error.message.contains("Beta version of the protocol used"); + if (firstRequest && serverOrProtocolError && badProtocolVersionMessage) { fail( UnsupportedProtocolVersionException.forSingleAttempt( endPoint, initialProtocolVersion)); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/channel/ChannelFactoryProtocolNegotiationTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/channel/ChannelFactoryProtocolNegotiationTest.java index 189561c161b..2d7aeec2b62 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/channel/ChannelFactoryProtocolNegotiationTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/channel/ChannelFactoryProtocolNegotiationTest.java @@ -94,6 +94,44 @@ public void should_fail_if_version_specified_and_not_supported_by_server(int err }); } + @Test + public void should_fail_if_version_specified_and_considered_beta_by_server() { + // Given + when(defaultProfile.isDefined(DefaultDriverOption.PROTOCOL_VERSION)).thenReturn(true); + when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_VERSION)).thenReturn("V5"); + when(protocolVersionRegistry.fromName("V5")).thenReturn(DefaultProtocolVersion.V5); + ChannelFactory factory = newChannelFactory(); + + // When + CompletionStage channelFuture = + factory.connect( + SERVER_ADDRESS, DriverChannelOptions.DEFAULT, NoopNodeMetricUpdater.INSTANCE); + + Frame requestFrame = readOutboundFrame(); + assertThat(requestFrame.message).isInstanceOf(Options.class); + writeInboundFrame(requestFrame, TestResponses.supportedResponse("mock_key", "mock_value")); + + requestFrame = readOutboundFrame(); + assertThat(requestFrame.protocolVersion).isEqualTo(DefaultProtocolVersion.V5.getCode()); + // Server considers v5 beta, e.g. C* 3.10 or 3.11 + writeInboundFrame( + requestFrame, + new Error( + ProtocolConstants.ErrorCode.PROTOCOL_ERROR, + "Beta version of the protocol used (5/v5-beta), but USE_BETA flag is unset")); + + // Then + assertThatStage(channelFuture) + .isFailed( + e -> { + assertThat(e) + .isInstanceOf(UnsupportedProtocolVersionException.class) + .hasMessageContaining("Host does not support protocol version V5"); + assertThat(((UnsupportedProtocolVersionException) e).getAttemptedVersions()) + .containsExactly(DefaultProtocolVersion.V5); + }); + } + @Test public void should_succeed_if_version_not_specified_and_server_supports_latest_supported() { // Given From 39be4f71aa974d783a11b94ff1fa70beaa7e6848 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 16 Mar 2021 10:21:45 +0100 Subject: [PATCH 078/395] Fix failing tests in ProtocolVersionInitialNegotiationIT --- .../ProtocolVersionInitialNegotiationIT.java | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java index 64e38e7268e..366e9fe5669 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java @@ -31,6 +31,7 @@ import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; +import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -46,7 +47,17 @@ public class ProtocolVersionInitialNegotiationIT { max = "2.2", description = "Only C* in [2.1,2.2[ has V3 as its highest version") @Test - public void should_downgrade_to_v3() { + public void should_downgrade_to_v3_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + try (CqlSession session = SessionUtils.newSession(ccm)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); + session.execute("select * from system.local"); + } + } + + @DseRequirement(max = "5.0", description = "Only DSE in [*,5.0[ has V3 as its highest version") + @Test + public void should_downgrade_to_v3_dse() { try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); session.execute("select * from system.local"); @@ -58,7 +69,20 @@ public void should_downgrade_to_v3() { max = "4.0", description = "Only C* in [2.2,4.0[ has V4 as its highest version") @Test - public void should_downgrade_to_v4() { + public void should_downgrade_to_v4_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + try (CqlSession session = SessionUtils.newSession(ccm)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); + session.execute("select * from system.local"); + } + } + + @DseRequirement( + min = "5.0", + max = "5.1", + description = "Only DSE in [5.0,5.1[ has V4 as its highest version") + @Test + public void should_downgrade_to_v4_dse() { try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); session.execute("select * from system.local"); @@ -66,8 +90,9 @@ public void should_downgrade_to_v4() { } @DseRequirement( + min = "5.1", max = "6.0", - description = "Only DSE in [*,6.0[ has DSE_V1 as its highest version") + description = "Only DSE in [5.1,6.0[ has DSE_V1 as its highest version") @Test public void should_downgrade_to_dse_v1() { try (CqlSession session = SessionUtils.newSession(ccm)) { @@ -78,7 +103,27 @@ public void should_downgrade_to_dse_v1() { @CassandraRequirement(max = "2.2", description = "Only C* in [*,2.2[ has V4 unsupported") @Test - public void should_fail_if_provided_v4_is_not_supported() { + public void should_fail_if_provided_v4_is_not_supported_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") + .build(); + try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { + fail("Expected an AllNodesFailedException"); + } catch (AllNodesFailedException anfe) { + Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); + assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); + UnsupportedProtocolVersionException unsupportedException = + (UnsupportedProtocolVersionException) cause; + assertThat(unsupportedException.getAttemptedVersions()) + .containsOnly(DefaultProtocolVersion.V4); + } + } + + @DseRequirement(max = "5.0", description = "Only DSE in [*,5.0[ has V4 unsupported") + @Test + public void should_fail_if_provided_v4_is_not_supported_dse() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") @@ -100,7 +145,8 @@ public void should_fail_if_provided_v4_is_not_supported() { max = "4.0", description = "Only C* in [2.1,4.0[ has V5 unsupported or supported as beta") @Test - public void should_fail_if_provided_v5_is_not_supported() { + public void should_fail_if_provided_v5_is_not_supported_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") @@ -179,7 +225,8 @@ public void should_fail_if_provided_dse_v2_is_not_supported() { /** Note that this test will need to be updated as new protocol versions are introduced. */ @CassandraRequirement(min = "4.0", description = "Only C* in [4.0,*[ has V5 supported") @Test - public void should_not_downgrade_if_server_supports_latest_version() { + public void should_not_downgrade_if_server_supports_latest_version_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion()).isEqualTo(ProtocolVersion.V5); session.execute("select * from system.local"); @@ -198,7 +245,8 @@ public void should_not_downgrade_if_server_supports_latest_version_dse() { @CassandraRequirement(min = "2.1", description = "Only C* in [2.1,*[ has V3 supported") @Test - public void should_use_explicitly_provided_v3() { + public void should_use_explicitly_provided_v3_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") @@ -224,7 +272,8 @@ public void should_use_explicitly_provided_v3_dse() { @CassandraRequirement(min = "2.2", description = "Only C* in [2.2,*[ has V4 supported") @Test - public void should_use_explicitly_provided_v4() { + public void should_use_explicitly_provided_v4_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") @@ -250,7 +299,8 @@ public void should_use_explicitly_provided_v4_dse() { @CassandraRequirement(min = "4.0", description = "Only C* in [4.0,*[ has V5 supported") @Test - public void should_use_explicitly_provided_v5() { + public void should_use_explicitly_provided_v5_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") From 85b784bab7a2f775e1d7433dbcf50df8aad8125b Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 17 Mar 2021 00:09:44 +0100 Subject: [PATCH 079/395] Set CCM logger level to ERROR --- integration-tests/src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/resources/logback-test.xml b/integration-tests/src/test/resources/logback-test.xml index 078ca8a1911..36dd79c1040 100644 --- a/integration-tests/src/test/resources/logback-test.xml +++ b/integration-tests/src/test/resources/logback-test.xml @@ -29,7 +29,7 @@ - + From faa7f7c379ca5ffaeaffc31f2cd9ace0a5f5bc42 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 17 Mar 2021 00:12:47 +0100 Subject: [PATCH 080/395] Add note in the upgrade guide about protocol v5 (JAVA-2704) --- upgrade_guide/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 80909ad15da..54d1e86c6a7 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,16 @@ ## Upgrade guide +### 4.11.0 + +#### Native protocol V5 is now production-ready + +Thanks to [JAVA-2704](https://datastax-oss.atlassian.net/browse/JAVA-2704), 4.11.0 is the first +version in the driver 4.x series to fully support Cassandra's native protocol version 5, which has +been promoted from beta to production-ready in the upcoming Cassandra 4.0 release. + +Users should not experience any disruption. When connecting to Cassandra 4.0, V5 will be +transparently selected as the protocol version to use. + ### 4.10.0 #### Cross-datacenter failover From 17f61165c3b2580979da10a98b12899417fe0a8a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 17 Mar 2021 22:15:44 +0100 Subject: [PATCH 081/395] JAVA-2872: Ability to customize metric names and tags (#1540) --- changelog/README.md | 1 + .../api/core/config/DefaultDriverOption.java | 14 + .../driver/api/core/config/OptionsMap.java | 1 + .../api/core/config/TypedDriverOption.java | 8 + .../driver/api/core/metrics/NodeMetric.java | 5 +- .../api/core/metrics/SessionMetric.java | 3 +- .../core/context/DefaultDriverContext.java | 23 ++ .../core/context/InternalDriverContext.java | 4 + .../internal/core/metadata/SniEndPoint.java | 3 + .../core/metrics/AbstractMetricUpdater.java | 120 +++++++ .../core/metrics/DefaultMetricId.java | 68 ++++ .../metrics/DefaultMetricIdGenerator.java | 64 ++++ .../core/metrics/DropwizardMetricUpdater.java | 164 +++++++--- .../metrics/DropwizardMetricsFactory.java | 4 +- .../metrics/DropwizardNodeMetricUpdater.java | 115 +++---- .../DropwizardSessionMetricUpdater.java | 116 ++----- .../internal/core/metrics/MetricId.java | 47 +++ .../core/metrics/MetricIdGenerator.java | 47 +++ .../internal/core/metrics/MetricUpdater.java | 16 +- .../metrics/TaggingMetricIdGenerator.java | 71 +++++ core/src/main/resources/reference.conf | 72 ++++- .../metrics/DefaultMetricIdGeneratorTest.java | 108 +++++++ .../core/metrics/DefaultMetricIdTest.java | 61 ++++ .../metrics/DropwizardMetricsFactoryTest.java | 10 +- .../metrics/TaggingMetricIdGeneratorTest.java | 114 +++++++ .../common/AbstractMetricsTestBase.java | 217 ++++++++++--- .../micrometer/MicrometerMetricsIT.java | 280 ++++++++++------- .../microprofile/MicroProfileMetricsIT.java | 295 ++++++++++-------- manual/core/metrics/README.md | 55 ++++ .../micrometer/MicrometerMetricUpdater.java | 109 +++++-- .../micrometer/MicrometerMetricsFactory.java | 4 +- .../MicrometerNodeMetricUpdater.java | 108 +++---- .../MicrometerSessionMetricUpdater.java | 126 ++------ .../metrics/micrometer/MicrometerTags.java | 33 ++ .../MicrometerMetricsFactoryTest.java | 10 +- .../MicroProfileMetricUpdater.java | 123 ++++++-- .../MicroProfileMetricsFactory.java | 4 +- .../MicroProfileNodeMetricUpdater.java | 112 +++---- .../MicroProfileSessionMetricUpdater.java | 122 ++------ .../microprofile/MicroProfileTags.java | 33 ++ .../MicroProfileMetricsFactoryTest.java | 10 +- upgrade_guide/README.md | 13 + 42 files changed, 1995 insertions(+), 918 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricId.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGenerator.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricId.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGenerator.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGeneratorTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGeneratorTest.java create mode 100644 metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerTags.java create mode 100644 metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileTags.java diff --git a/changelog/README.md b/changelog/README.md index 984dd9259c5..2d3d1d0c280 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [new feature] JAVA-2872: Ability to customize metric names and tags - [bug] JAVA-2925: Consider protocol version unsupported when server requires USE_BETA flag for it - [improvement] JAVA-2704: Remove protocol v5 beta status, add v6-beta - [improvement] JAVA-2916: Annotate generated classes with `@SuppressWarnings` diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index d9bc504bea4..150305dfea4 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -838,6 +838,20 @@ public enum DefaultDriverOption implements DriverOption { */ LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS( "advanced.load-balancing-policy.dc-failover.allow-for-local-consistency-levels"), + + /** + * The classname of the desired {@code MetricIdGenerator} implementation. + * + *

    Value-type: {@link String} + */ + METRICS_ID_GENERATOR_CLASS("advanced.metrics.id-generator.class"), + + /** + * The value of the prefix to prepend to all metric names. + * + *

    Value-type: {@link String} + */ + METRICS_ID_GENERATOR_PREFIX("advanced.metrics.id-generator.prefix"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index b0fd39b57c2..9c4758f531f 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -323,6 +323,7 @@ protected static void fillWithDriverDefaults(OptionsMap map) { TypedDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_INTERVAL, Duration.ofMinutes(5)); map.put(TypedDriverOption.METRICS_FACTORY_CLASS, "DefaultMetricsFactory"); + map.put(TypedDriverOption.METRICS_ID_GENERATOR_CLASS, "DefaultMetricIdGenerator"); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, Duration.ofSeconds(12)); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS, 3); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_INTERVAL, Duration.ofMinutes(5)); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index bf4223bf45c..d2687da68d7 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -709,6 +709,14 @@ public String toString() { public static final TypedDriverOption METRICS_FACTORY_CLASS = new TypedDriverOption<>(DefaultDriverOption.METRICS_FACTORY_CLASS, GenericType.STRING); + /** The classname of the desired {@code MetricIdGenerator} implementation. */ + public static final TypedDriverOption METRICS_ID_GENERATOR_CLASS = + new TypedDriverOption<>(DefaultDriverOption.METRICS_ID_GENERATOR_CLASS, GenericType.STRING); + + /** The value of the prefix to prepend to all metric names. */ + public static final TypedDriverOption METRICS_ID_GENERATOR_PREFIX = + new TypedDriverOption<>(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, GenericType.STRING); + /** The maximum number of nodes from remote DCs to include in query plans. */ public static final TypedDriverOption LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC = diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/metrics/NodeMetric.java b/core/src/main/java/com/datastax/oss/driver/api/core/metrics/NodeMetric.java index 6f7c3c8e7f6..5fac2ef30da 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/metrics/NodeMetric.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/metrics/NodeMetric.java @@ -21,8 +21,9 @@ /** * A node-level metric exposed through {@link Session#getMetrics()}. * - *

    All metrics exposed out of the box by the driver are instances of {@link DefaultNodeMetric} - * (this interface only exists to allow custom metrics in driver extensions). + *

    All metrics exposed out of the box by the driver are instances of {@link DefaultNodeMetric} or + * {@link com.datastax.dse.driver.api.core.metrics.DseNodeMetric DseNodeMetric} (this interface only + * exists to allow custom metrics in driver extensions). * * @see SessionMetric */ diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/metrics/SessionMetric.java b/core/src/main/java/com/datastax/oss/driver/api/core/metrics/SessionMetric.java index 4b591e14085..c0da00df070 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/metrics/SessionMetric.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/metrics/SessionMetric.java @@ -22,7 +22,8 @@ * A session-level metric exposed through {@link Session#getMetrics()}. * *

    All metrics exposed out of the box by the driver are instances of {@link DefaultSessionMetric} - * (this interface only exists to allow custom metrics in driver extensions). + * or {@link com.datastax.dse.driver.api.core.metrics.DseSessionMetric DseSessionMetric} (this + * interface only exists to allow custom metrics in driver extensions). * * @see NodeMetric */ diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index f37c2eae3dc..8cbe488253b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -65,6 +65,7 @@ import com.datastax.oss.driver.internal.core.metadata.token.DefaultTokenFactoryRegistry; import com.datastax.oss.driver.internal.core.metadata.token.ReplicationStrategyFactory; import com.datastax.oss.driver.internal.core.metadata.token.TokenFactoryRegistry; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; import com.datastax.oss.driver.internal.core.pool.ChannelPoolFactory; import com.datastax.oss.driver.internal.core.protocol.BuiltInCompressors; @@ -200,6 +201,8 @@ public class DefaultDriverContext implements InternalDriverContext { new LazyReference<>("poolManager", this::buildPoolManager, cycleDetector); private final LazyReference metricsFactoryRef = new LazyReference<>("metricsFactory", this::buildMetricsFactory, cycleDetector); + private final LazyReference metricIdGeneratorRef = + new LazyReference<>("metricIdGenerator", this::buildMetricIdGenerator, cycleDetector); private final LazyReference requestThrottlerRef = new LazyReference<>("requestThrottler", this::buildRequestThrottler, cycleDetector); private final LazyReference> startupOptionsRef = @@ -543,6 +546,20 @@ protected MetricsFactory buildMetricsFactory() { DefaultDriverOption.METRICS_FACTORY_CLASS))); } + protected MetricIdGenerator buildMetricIdGenerator() { + return Reflection.buildFromConfig( + this, + DefaultDriverOption.METRICS_ID_GENERATOR_CLASS, + MetricIdGenerator.class, + "com.datastax.oss.driver.internal.core.metrics") + .orElseThrow( + () -> + new IllegalArgumentException( + String.format( + "Missing metric descriptor, check your config (%s)", + DefaultDriverOption.METRICS_ID_GENERATOR_CLASS))); + } + protected RequestThrottler buildRequestThrottler() { return Reflection.buildFromConfig( this, @@ -853,6 +870,12 @@ public MetricsFactory getMetricsFactory() { return metricsFactoryRef.get(); } + @NonNull + @Override + public MetricIdGenerator getMetricIdGenerator() { + return metricIdGeneratorRef.get(); + } + @NonNull @Override public RequestThrottler getRequestThrottler() { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java index 3b17b98deef..0bfc07d73a2 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java @@ -30,6 +30,7 @@ import com.datastax.oss.driver.internal.core.metadata.schema.queries.SchemaQueriesFactory; import com.datastax.oss.driver.internal.core.metadata.token.ReplicationStrategyFactory; import com.datastax.oss.driver.internal.core.metadata.token.TokenFactoryRegistry; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; import com.datastax.oss.driver.internal.core.pool.ChannelPoolFactory; import com.datastax.oss.driver.internal.core.servererrors.WriteTypeRegistry; @@ -125,6 +126,9 @@ public interface InternalDriverContext extends DriverContext { @NonNull MetricsFactory getMetricsFactory(); + @NonNull + MetricIdGenerator getMetricIdGenerator(); + /** * The value that was passed to {@link SessionBuilder#withLocalDatacenter(String,String)} for this * particular profile. If it was specified through the configuration instead, this method will diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java index 5c2918e1f34..475e1b56b95 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.shaded.guava.common.primitives.UnsignedBytes; +import edu.umd.cs.findbugs.annotations.NonNull; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -48,6 +49,7 @@ public String getServerName() { return serverName; } + @NonNull @Override public InetSocketAddress resolve() { try { @@ -93,6 +95,7 @@ public String toString() { return proxyAddress.toString() + ":" + serverName; } + @NonNull @Override public String asMetricPrefix() { String hostString = proxyAddress.getHostString(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java new file mode 100644 index 00000000000..04fdc2c58bc --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java @@ -0,0 +1,120 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; +import com.datastax.oss.driver.internal.core.pool.ChannelPool; +import com.datastax.oss.driver.internal.core.session.RequestProcessor; +import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; +import com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler; +import com.datastax.oss.driver.shaded.guava.common.cache.Cache; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractMetricUpdater implements MetricUpdater { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractMetricUpdater.class); + + protected final InternalDriverContext context; + protected final Set enabledMetrics; + + protected AbstractMetricUpdater(InternalDriverContext context, Set enabledMetrics) { + this.context = context; + this.enabledMetrics = enabledMetrics; + } + + @Override + public boolean isEnabled(MetricT metric, String profileName) { + return enabledMetrics.contains(metric); + } + + protected int connectedNodes() { + int count = 0; + for (Node node : context.getMetadataManager().getMetadata().getNodes().values()) { + if (node.getOpenConnections() > 0) { + count++; + } + } + return count; + } + + protected int throttlingQueueSize() { + RequestThrottler requestThrottler = context.getRequestThrottler(); + String logPrefix = context.getSessionName(); + if (requestThrottler instanceof ConcurrencyLimitingRequestThrottler) { + return ((ConcurrencyLimitingRequestThrottler) requestThrottler).getQueueSize(); + } + if (requestThrottler instanceof RateLimitingRequestThrottler) { + return ((RateLimitingRequestThrottler) requestThrottler).getQueueSize(); + } + LOG.warn( + "[{}] Metric {} does not support {}, it will always return 0", + logPrefix, + DefaultSessionMetric.THROTTLING_QUEUE_SIZE.getPath(), + requestThrottler.getClass().getName()); + return 0; + } + + protected long preparedStatementCacheSize() { + Cache cache = getPreparedStatementCache(); + if (cache == null) { + LOG.warn( + "[{}] Metric {} is enabled in the config, " + + "but it looks like no CQL prepare processor is registered. " + + "The gauge will always return 0", + context.getSessionName(), + DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE.getPath()); + return 0L; + } + return cache.size(); + } + + @Nullable + protected Cache getPreparedStatementCache() { + // By default, both the sync processor and the async ones are registered and they share the same + // cache. But with a custom processor registry, there could be only one of the two present. + for (RequestProcessor processor : context.getRequestProcessorRegistry().getProcessors()) { + if (processor instanceof CqlPrepareAsyncProcessor) { + return ((CqlPrepareAsyncProcessor) processor).getCache(); + } else if (processor instanceof CqlPrepareSyncProcessor) { + return ((CqlPrepareSyncProcessor) processor).getCache(); + } + } + return null; + } + + protected int availableStreamIds(Node node) { + ChannelPool pool = context.getPoolManager().getPools().get(node); + return (pool == null) ? 0 : pool.getAvailableIds(); + } + + protected int inFlightRequests(Node node) { + ChannelPool pool = context.getPoolManager().getPools().get(node); + return (pool == null) ? 0 : pool.getInFlight(); + } + + protected int orphanedStreamIds(Node node) { + ChannelPool pool = context.getPoolManager().getPools().get(node); + return (pool == null) ? 0 : pool.getOrphanedIds(); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricId.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricId.java new file mode 100644 index 00000000000..bd200854b24 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricId.java @@ -0,0 +1,68 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Map; +import java.util.Objects; +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public final class DefaultMetricId implements MetricId { + + private final String name; + private final ImmutableMap tags; + + public DefaultMetricId(String name, Map tags) { + this.name = Objects.requireNonNull(name, "name cannot be null"); + this.tags = ImmutableMap.copyOf(Objects.requireNonNull(tags, "tags cannot be null")); + } + + @NonNull + @Override + public String getName() { + return name; + } + + @NonNull + @Override + public Map getTags() { + return tags; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DefaultMetricId that = (DefaultMetricId) o; + return name.equals(that.name) && tags.equals(that.tags); + } + + @Override + public int hashCode() { + return Objects.hash(name, tags); + } + + @Override + public String toString() { + return name + tags; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGenerator.java new file mode 100644 index 00000000000..614c7d6eb9a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGenerator.java @@ -0,0 +1,64 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.NodeMetric; +import com.datastax.oss.driver.api.core.metrics.SessionMetric; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Objects; + +/** + * The default {@link MetricIdGenerator}. + * + *

    This generator generates unique names, containing the session name, the node endpoint (for + * node metrics), and the metric prefix. It does not generate tags. + */ +public class DefaultMetricIdGenerator implements MetricIdGenerator { + + private final String sessionPrefix; + private final String nodePrefix; + + @SuppressWarnings("unused") + public DefaultMetricIdGenerator(DriverContext context) { + String sessionName = context.getSessionName(); + String prefix = + Objects.requireNonNull( + context + .getConfig() + .getDefaultProfile() + .getString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, "")); + sessionPrefix = prefix.isEmpty() ? sessionName + '.' : prefix + '.' + sessionName + '.'; + nodePrefix = sessionPrefix + "nodes."; + } + + @NonNull + @Override + public MetricId sessionMetricId(@NonNull SessionMetric metric) { + return new DefaultMetricId(sessionPrefix + metric.getPath(), ImmutableMap.of()); + } + + @NonNull + @Override + public MetricId nodeMetricId(@NonNull Node node, @NonNull NodeMetric metric) { + return new DefaultMetricId( + nodePrefix + node.getEndPoint().asMetricPrefix() + '.' + metric.getPath(), + ImmutableMap.of()); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java index 0c47637d780..7605d770069 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java @@ -15,110 +15,172 @@ */ package com.datastax.oss.driver.internal.core.metrics; +import com.codahale.metrics.Counter; +import com.codahale.metrics.Histogram; +import com.codahale.metrics.Meter; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Reservoir; import com.codahale.metrics.Timer; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.config.DriverOption; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Duration; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ThreadSafe -public abstract class DropwizardMetricUpdater implements MetricUpdater { +public abstract class DropwizardMetricUpdater extends AbstractMetricUpdater { private static final Logger LOG = LoggerFactory.getLogger(DropwizardMetricUpdater.class); - protected final Set enabledMetrics; protected final MetricRegistry registry; - protected DropwizardMetricUpdater(Set enabledMetrics, MetricRegistry registry) { - this.enabledMetrics = enabledMetrics; + protected final ConcurrentMap metrics = new ConcurrentHashMap<>(); + + protected final ConcurrentMap reservoirs = new ConcurrentHashMap<>(); + + protected DropwizardMetricUpdater( + InternalDriverContext context, Set enabledMetrics, MetricRegistry registry) { + super(context, enabledMetrics); this.registry = registry; } - protected abstract String buildFullName(MetricT metric, String profileName); + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) + public T getMetric(MetricT metric, String profileName) { + return (T) metrics.get(metric); + } @Override - public void incrementCounter(MetricT metric, String profileName, long amount) { + public void incrementCounter(MetricT metric, @Nullable String profileName, long amount) { if (isEnabled(metric, profileName)) { - registry.counter(buildFullName(metric, profileName)).inc(amount); + getOrCreateCounterFor(metric).inc(amount); } } @Override - public void updateHistogram(MetricT metric, String profileName, long value) { + public void updateHistogram(MetricT metric, @Nullable String profileName, long value) { if (isEnabled(metric, profileName)) { - registry.histogram(buildFullName(metric, profileName)).update(value); + getOrCreateHistogramFor(metric).update(value); } } @Override - public void markMeter(MetricT metric, String profileName, long amount) { + public void markMeter(MetricT metric, @Nullable String profileName, long amount) { if (isEnabled(metric, profileName)) { - registry.meter(buildFullName(metric, profileName)).mark(amount); + getOrCreateMeterFor(metric).mark(amount); } } @Override - public void updateTimer(MetricT metric, String profileName, long duration, TimeUnit unit) { + public void updateTimer( + MetricT metric, @Nullable String profileName, long duration, TimeUnit unit) { if (isEnabled(metric, profileName)) { - registry.timer(buildFullName(metric, profileName)).update(duration, unit); + getOrCreateTimerFor(metric).update(duration, unit); } } - @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) - public T getMetric(MetricT metric, String profileName) { - return (T) registry.getMetrics().get(buildFullName(metric, profileName)); + protected abstract MetricId getMetricId(MetricT metric); + + protected void initializeGauge( + MetricT metric, DriverExecutionProfile profile, Supplier supplier) { + if (isEnabled(metric, profile.getName())) { + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + return registry.gauge(id.getName(), () -> supplier::get); + }); + } } - @Override - public boolean isEnabled(MetricT metric, String profileName) { - return enabledMetrics.contains(metric); + protected void initializeCounter(MetricT metric, DriverExecutionProfile profile) { + if (isEnabled(metric, profile.getName())) { + getOrCreateCounterFor(metric); + } } - protected void initializeDefaultCounter(MetricT metric, String profileName) { - if (isEnabled(metric, profileName)) { - // Just initialize eagerly so that the metric appears even when it has no data yet - registry.counter(buildFullName(metric, profileName)); + protected void initializeHdrTimer( + MetricT metric, + DriverExecutionProfile profile, + DriverOption highestLatency, + DriverOption significantDigits, + DriverOption interval) { + if (isEnabled(metric, profile.getName())) { + reservoirs.computeIfAbsent( + metric, m -> createHdrReservoir(m, profile, highestLatency, significantDigits, interval)); + getOrCreateTimerFor(metric); } } - protected void initializeHdrTimer( + protected Counter getOrCreateCounterFor(MetricT metric) { + return (Counter) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + return registry.counter(id.getName()); + }); + } + + protected Meter getOrCreateMeterFor(MetricT metric) { + return (Meter) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + return registry.meter(id.getName()); + }); + } + + protected Histogram getOrCreateHistogramFor(MetricT metric) { + return (Histogram) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + return registry.histogram(id.getName()); + }); + } + + protected Timer getOrCreateTimerFor(MetricT metric) { + return (Timer) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Reservoir reservoir = reservoirs.get(metric); + Timer timer = reservoir == null ? new Timer() : new Timer(reservoir); + return registry.timer(id.getName(), () -> timer); + }); + } + + protected HdrReservoir createHdrReservoir( MetricT metric, - DriverExecutionProfile config, + DriverExecutionProfile profile, DriverOption highestLatencyOption, DriverOption significantDigitsOption, DriverOption intervalOption) { - String profileName = config.getName(); - if (isEnabled(metric, profileName)) { - String fullName = buildFullName(metric, profileName); - - Duration highestLatency = config.getDuration(highestLatencyOption); - final int significantDigits; - int d = config.getInt(significantDigitsOption); - if (d >= 0 && d <= 5) { - significantDigits = d; - } else { - LOG.warn( - "[{}] Configuration option {} is out of range (expected between 0 and 5, found {}); " - + "using 3 instead.", - fullName, - significantDigitsOption, - d); - significantDigits = 3; - } - Duration refreshInterval = config.getDuration(intervalOption); - - // Initialize eagerly to use the custom implementation - registry.timer( - fullName, - () -> - new Timer( - new HdrReservoir(highestLatency, significantDigits, refreshInterval, fullName))); + MetricId id = getMetricId(metric); + Duration highestLatency = profile.getDuration(highestLatencyOption); + int significantDigits = profile.getInt(significantDigitsOption); + if (significantDigits < 0 || significantDigits > 5) { + LOG.warn( + "[{}] Configuration option {} is out of range (expected between 0 and 5, " + + "found {}); using 3 instead.", + id.getName(), + significantDigitsOption, + significantDigits); + significantDigits = 3; } + Duration refreshInterval = profile.getDuration(intervalOption); + return new HdrReservoir(highestLatency, significantDigits, refreshInterval, id.getName()); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java index 5b81166668d..8cfac64fbe4 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java @@ -96,7 +96,7 @@ public DropwizardMetricsFactory(InternalDriverContext context, Ticker ticker) { if (possibleMetricRegistry instanceof MetricRegistry) { this.registry = (MetricRegistry) possibleMetricRegistry; DropwizardSessionMetricUpdater dropwizardSessionUpdater = - new DropwizardSessionMetricUpdater(enabledSessionMetrics, registry, context); + new DropwizardSessionMetricUpdater(context, enabledSessionMetrics, registry); this.sessionUpdater = dropwizardSessionUpdater; this.metrics = new DefaultMetrics(registry, dropwizardSessionUpdater); } else { @@ -144,7 +144,7 @@ public NodeMetricUpdater newNodeUpdater(Node node) { } else { DropwizardNodeMetricUpdater dropwizardNodeMetricUpdater = new DropwizardNodeMetricUpdater( - node, enabledNodeMetrics, registry, context, () -> metricsCache.getIfPresent(node)); + node, context, enabledNodeMetrics, registry, () -> metricsCache.getIfPresent(node)); metricsCache.put(node, dropwizardNodeMetricUpdater); return dropwizardNodeMetricUpdater; } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java index 7961d102659..ca50f57d1c1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java @@ -15,97 +15,80 @@ */ package com.datastax.oss.driver.internal.core.metrics; -import com.codahale.metrics.Gauge; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.api.core.metrics.DseNodeMetric; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.pool.ChannelPool; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import net.jcip.annotations.ThreadSafe; @ThreadSafe public class DropwizardNodeMetricUpdater extends DropwizardMetricUpdater implements NodeMetricUpdater { - private final String metricNamePrefix; + private final Node node; private final Runnable signalMetricUpdated; public DropwizardNodeMetricUpdater( Node node, + InternalDriverContext context, Set enabledMetrics, MetricRegistry registry, - InternalDriverContext context, Runnable signalMetricUpdated) { - super(enabledMetrics, registry); + super(context, enabledMetrics, registry); + this.node = node; this.signalMetricUpdated = signalMetricUpdated; - this.metricNamePrefix = buildPrefix(context.getSessionName(), node.getEndPoint()); - DriverExecutionProfile config = context.getConfig().getDefaultProfile(); + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + + initializeGauge(DefaultNodeMetric.OPEN_CONNECTIONS, profile, node::getOpenConnections); + initializeGauge(DefaultNodeMetric.AVAILABLE_STREAMS, profile, () -> availableStreamIds(node)); + initializeGauge(DefaultNodeMetric.IN_FLIGHT, profile, () -> inFlightRequests(node)); + initializeGauge(DefaultNodeMetric.ORPHANED_STREAMS, profile, () -> orphanedStreamIds(node)); + + initializeCounter(DefaultNodeMetric.UNSENT_REQUESTS, profile); + initializeCounter(DefaultNodeMetric.ABORTED_REQUESTS, profile); + initializeCounter(DefaultNodeMetric.WRITE_TIMEOUTS, profile); + initializeCounter(DefaultNodeMetric.READ_TIMEOUTS, profile); + initializeCounter(DefaultNodeMetric.UNAVAILABLES, profile); + initializeCounter(DefaultNodeMetric.OTHER_ERRORS, profile); + initializeCounter(DefaultNodeMetric.RETRIES, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_ABORTED, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, profile); + initializeCounter(DefaultNodeMetric.IGNORES, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_ABORTED, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_UNAVAILABLE, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_OTHER_ERROR, profile); + initializeCounter(DefaultNodeMetric.SPECULATIVE_EXECUTIONS, profile); + initializeCounter(DefaultNodeMetric.CONNECTION_INIT_ERRORS, profile); + initializeCounter(DefaultNodeMetric.AUTHENTICATION_ERRORS, profile); - if (enabledMetrics.contains(DefaultNodeMetric.OPEN_CONNECTIONS)) { - this.registry.register( - buildFullName(DefaultNodeMetric.OPEN_CONNECTIONS, null), - (Gauge) node::getOpenConnections); - } - initializePoolGauge( - DefaultNodeMetric.AVAILABLE_STREAMS, node, ChannelPool::getAvailableIds, context); - initializePoolGauge(DefaultNodeMetric.IN_FLIGHT, node, ChannelPool::getInFlight, context); - initializePoolGauge( - DefaultNodeMetric.ORPHANED_STREAMS, node, ChannelPool::getOrphanedIds, context); initializeHdrTimer( DefaultNodeMetric.CQL_MESSAGES, - config, + profile, DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST, DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS, DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_INTERVAL); - initializeDefaultCounter(DefaultNodeMetric.UNSENT_REQUESTS, null); - initializeDefaultCounter(DefaultNodeMetric.ABORTED_REQUESTS, null); - initializeDefaultCounter(DefaultNodeMetric.WRITE_TIMEOUTS, null); - initializeDefaultCounter(DefaultNodeMetric.READ_TIMEOUTS, null); - initializeDefaultCounter(DefaultNodeMetric.UNAVAILABLES, null); - initializeDefaultCounter(DefaultNodeMetric.OTHER_ERRORS, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_ABORTED, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_ABORTED, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_UNAVAILABLE, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_OTHER_ERROR, null); - initializeDefaultCounter(DefaultNodeMetric.SPECULATIVE_EXECUTIONS, null); - initializeDefaultCounter(DefaultNodeMetric.CONNECTION_INIT_ERRORS, null); - initializeDefaultCounter(DefaultNodeMetric.AUTHENTICATION_ERRORS, null); initializeHdrTimer( DseNodeMetric.GRAPH_MESSAGES, - context.getConfig().getDefaultProfile(), + profile, DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_HIGHEST, DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_DIGITS, DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_INTERVAL); } - @Override - public String buildFullName(NodeMetric metric, String profileName) { - return metricNamePrefix + metric.getPath(); - } - - private String buildPrefix(String sessionName, EndPoint endPoint) { - return sessionName + ".nodes." + endPoint.asMetricPrefix() + "."; - } - @Override public void incrementCounter(NodeMetric metric, String profileName, long amount) { signalMetricUpdated.run(); @@ -131,29 +114,27 @@ public void updateTimer(NodeMetric metric, String profileName, long duration, Ti } @Override - @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) + @SuppressWarnings("TypeParameterUnusedInFormals") public T getMetric(NodeMetric metric, String profileName) { signalMetricUpdated.run(); return super.getMetric(metric, profileName); } - private void initializePoolGauge( - NodeMetric metric, - Node node, - Function reading, - InternalDriverContext context) { - if (enabledMetrics.contains(metric)) { - registry.register( - buildFullName(metric, null), - (Gauge) - () -> { - ChannelPool pool = context.getPoolManager().getPools().get(node); - return (pool == null) ? 0 : reading.apply(pool); - }); + public void cleanupNodeMetrics() { + for (NodeMetric metric : metrics.keySet()) { + MetricId id = getMetricId(metric); + registry.remove(id.getName()); } + metrics.clear(); + reservoirs.clear(); } - public void cleanupNodeMetrics() { - registry.removeMatching((name, metric) -> name.startsWith(metricNamePrefix)); + @Override + protected MetricId getMetricId(NodeMetric metric) { + MetricId id = context.getMetricIdGenerator().nodeMetricId(node, metric); + if (!id.getTags().isEmpty()) { + throw new IllegalStateException("Cannot use metric tags with Dropwizard"); + } + return id; } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardSessionMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardSessionMetricUpdater.java index 95d1a4fbaab..9013c2d2749 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardSessionMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardSessionMetricUpdater.java @@ -15,140 +15,68 @@ */ package com.datastax.oss.driver.internal.core.metrics; -import com.codahale.metrics.Gauge; import com.codahale.metrics.MetricRegistry; import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.api.core.metrics.DseSessionMetric; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; -import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; -import com.datastax.oss.driver.internal.core.session.RequestProcessor; -import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; -import com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; -import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Set; import net.jcip.annotations.ThreadSafe; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @ThreadSafe public class DropwizardSessionMetricUpdater extends DropwizardMetricUpdater implements SessionMetricUpdater { - private static final Logger LOG = LoggerFactory.getLogger(DropwizardSessionMetricUpdater.class); + public DropwizardSessionMetricUpdater( + InternalDriverContext context, Set enabledMetrics, MetricRegistry registry) { + super(context, enabledMetrics, registry); - private final String metricNamePrefix; + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); - public DropwizardSessionMetricUpdater( - Set enabledMetrics, MetricRegistry registry, InternalDriverContext context) { - super(enabledMetrics, registry); - this.metricNamePrefix = context.getSessionName() + "."; + initializeGauge(DefaultSessionMetric.CONNECTED_NODES, profile, this::connectedNodes); + initializeGauge(DefaultSessionMetric.THROTTLING_QUEUE_SIZE, profile, this::throttlingQueueSize); + initializeGauge( + DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, profile, this::preparedStatementCacheSize); + + initializeCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, profile); + initializeCounter(DefaultSessionMetric.THROTTLING_ERRORS, profile); + initializeCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, profile); - if (enabledMetrics.contains(DefaultSessionMetric.CONNECTED_NODES)) { - this.registry.gauge( - buildFullName(DefaultSessionMetric.CONNECTED_NODES, null), - () -> - () -> { - int count = 0; - for (Node node : context.getMetadataManager().getMetadata().getNodes().values()) { - if (node.getOpenConnections() > 0) { - count += 1; - } - } - return count; - }); - } - if (enabledMetrics.contains(DefaultSessionMetric.THROTTLING_QUEUE_SIZE)) { - this.registry.gauge( - buildFullName(DefaultSessionMetric.THROTTLING_QUEUE_SIZE, null), - () -> buildQueueGauge(context.getRequestThrottler(), context.getSessionName())); - } - if (enabledMetrics.contains(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE)) { - this.registry.gauge( - buildFullName(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, null), - () -> { - Cache cache = getPreparedStatementCache(context); - Gauge gauge; - if (cache == null) { - LOG.warn( - "[{}] Metric {} is enabled in the config, " - + "but it looks like no CQL prepare processor is registered. " - + "The gauge will always return 0", - context.getSessionName(), - DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE.getPath()); - gauge = () -> 0L; - } else { - gauge = cache::size; - } - return gauge; - }); - } initializeHdrTimer( DefaultSessionMetric.CQL_REQUESTS, - context.getConfig().getDefaultProfile(), + profile, DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_HIGHEST, DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS, DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_INTERVAL); - initializeDefaultCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, null); initializeHdrTimer( DefaultSessionMetric.THROTTLING_DELAY, - context.getConfig().getDefaultProfile(), + profile, DefaultDriverOption.METRICS_SESSION_THROTTLING_HIGHEST, DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS, DefaultDriverOption.METRICS_SESSION_THROTTLING_INTERVAL); - initializeDefaultCounter(DefaultSessionMetric.THROTTLING_ERRORS, null); initializeHdrTimer( DseSessionMetric.CONTINUOUS_CQL_REQUESTS, - context.getConfig().getDefaultProfile(), + profile, DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_HIGHEST, DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS, DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_INTERVAL); - initializeDefaultCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, null); initializeHdrTimer( DseSessionMetric.GRAPH_REQUESTS, - context.getConfig().getDefaultProfile(), + profile, DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS, DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_INTERVAL); } @Override - public String buildFullName(SessionMetric metric, String profileName) { - return metricNamePrefix + metric.getPath(); - } - - private Gauge buildQueueGauge(RequestThrottler requestThrottler, String logPrefix) { - if (requestThrottler instanceof ConcurrencyLimitingRequestThrottler) { - return ((ConcurrencyLimitingRequestThrottler) requestThrottler)::getQueueSize; - } else if (requestThrottler instanceof RateLimitingRequestThrottler) { - return ((RateLimitingRequestThrottler) requestThrottler)::getQueueSize; - } else { - LOG.warn( - "[{}] Metric {} does not support {}, it will always return 0", - logPrefix, - DefaultSessionMetric.THROTTLING_QUEUE_SIZE.getPath(), - requestThrottler.getClass().getName()); - return () -> 0; - } - } - - @Nullable - private static Cache getPreparedStatementCache(InternalDriverContext context) { - // By default, both the sync processor and the async one are registered and they share the same - // cache. But with a custom processor registry, there could be only one of the two present. - for (RequestProcessor processor : context.getRequestProcessorRegistry().getProcessors()) { - if (processor instanceof CqlPrepareAsyncProcessor) { - return ((CqlPrepareAsyncProcessor) processor).getCache(); - } else if (processor instanceof CqlPrepareSyncProcessor) { - return ((CqlPrepareSyncProcessor) processor).getCache(); - } + protected MetricId getMetricId(SessionMetric metric) { + MetricId id = context.getMetricIdGenerator().sessionMetricId(metric); + if (!id.getTags().isEmpty()) { + throw new IllegalStateException("Cannot use metric tags with Dropwizard"); } - return null; + return id; } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricId.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricId.java new file mode 100644 index 00000000000..6f8c308472c --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricId.java @@ -0,0 +1,47 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Map; + +/** + * The identifier of a metric. + * + *

    The driver will use the reported name and tags to register the described metric against the + * current metric registry. + * + *

    A metric identifier is unique, that is, the combination of its name and its tags is expected + * to be unique for a given metric registry. + */ +public interface MetricId { + + /** + * Returns this metric name. + * + *

    Metric names can be any non-empty string, but it is recommended to create metric names that + * have path-like structures separated by a dot, e.g. {@code path.to.my.custom.metric}. Driver + * built-in implementations of this interface abide by this rule. + * + * @return The metric name; cannot be empty nor null. + */ + @NonNull + String getName(); + + /** @return The metric tags, or empty if no tag is defined; cannot be null. */ + @NonNull + Map getTags(); +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java new file mode 100644 index 00000000000..7cfd39bf37b --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java @@ -0,0 +1,47 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.NodeMetric; +import com.datastax.oss.driver.api.core.metrics.SessionMetric; +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * A {@link MetricIdGenerator} is used to generate the unique identifiers by which a metric should + * be registered against the current metrics registry. + * + *

    The driver ships with two implementations of this interface; {@code DefaultMetricIdGenerator} + * and {@code TaggingMetricIdGenerator}. + * + *

    {@code DefaultMetricIdGenerator} is the default implementation; it generates metric + * identifiers with unique names and no tags. + * + *

    {@code TaggingMetricIdGenerator} generates metric identifiers whose uniqueness stems from the + * combination of their names and tags. + * + *

    See the driver's {@code reference.conf} file. + */ +public interface MetricIdGenerator { + + /** Generates a {@link MetricId} for the given {@link SessionMetric}. */ + @NonNull + MetricId sessionMetricId(@NonNull SessionMetric metric); + + /** Generates a {@link MetricId} for the given {@link Node and }{@link NodeMetric}. */ + @NonNull + MetricId nodeMetricId(@NonNull Node node, @NonNull NodeMetric metric); +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java index f8dc93460b5..e545e4baf79 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java @@ -15,6 +15,7 @@ */ package com.datastax.oss.driver.internal.core.metrics; +import edu.umd.cs.findbugs.annotations.Nullable; import java.util.concurrent.TimeUnit; /** @@ -25,21 +26,22 @@ */ public interface MetricUpdater { - void incrementCounter(MetricT metric, String profileName, long amount); + void incrementCounter(MetricT metric, @Nullable String profileName, long amount); - default void incrementCounter(MetricT metric, String profileName) { + default void incrementCounter(MetricT metric, @Nullable String profileName) { incrementCounter(metric, profileName, 1); } - void updateHistogram(MetricT metric, String profileName, long value); + // note: currently unused + void updateHistogram(MetricT metric, @Nullable String profileName, long value); - void markMeter(MetricT metric, String profileName, long amount); + void markMeter(MetricT metric, @Nullable String profileName, long amount); - default void markMeter(MetricT metric, String profileName) { + default void markMeter(MetricT metric, @Nullable String profileName) { markMeter(metric, profileName, 1); } - void updateTimer(MetricT metric, String profileName, long duration, TimeUnit unit); + void updateTimer(MetricT metric, @Nullable String profileName, long duration, TimeUnit unit); - boolean isEnabled(MetricT metric, String profileName); + boolean isEnabled(MetricT metric, @Nullable String profileName); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGenerator.java new file mode 100644 index 00000000000..d49d1abb357 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGenerator.java @@ -0,0 +1,71 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.NodeMetric; +import com.datastax.oss.driver.api.core.metrics.SessionMetric; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Objects; + +/** + * A {@link MetricIdGenerator} that generates metric identifiers using a combination of names and + * tags. + * + *

    Session metric identifiers contain a name starting with "session." and ending with the metric + * path, and a tag with the key "session" and the value of the current session name. + * + *

    Node metric identifiers contain a name starting with "nodes." and ending with the metric path, + * and two tags: one with the key "session" and the value of the current session name, the other + * with the key "node" and the value of the current node endpoint. + */ +public class TaggingMetricIdGenerator implements MetricIdGenerator { + + private final String sessionName; + private final String sessionPrefix; + private final String nodePrefix; + + @SuppressWarnings("unused") + public TaggingMetricIdGenerator(DriverContext context) { + sessionName = context.getSessionName(); + String prefix = + Objects.requireNonNull( + context + .getConfig() + .getDefaultProfile() + .getString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, "")); + sessionPrefix = prefix.isEmpty() ? "session." : prefix + ".session."; + nodePrefix = prefix.isEmpty() ? "nodes." : prefix + ".nodes."; + } + + @NonNull + @Override + public MetricId sessionMetricId(@NonNull SessionMetric metric) { + return new DefaultMetricId( + sessionPrefix + metric.getPath(), ImmutableMap.of("session", sessionName)); + } + + @NonNull + @Override + public MetricId nodeMetricId(@NonNull Node node, @NonNull NodeMetric metric) { + return new DefaultMetricId( + nodePrefix + metric.getPath(), + ImmutableMap.of("session", sessionName, "node", node.getEndPoint().toString())); + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 53b8e8afdf3..49ae947d556 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1348,6 +1348,64 @@ datastax-java-driver { # Overridable in a profile: no class = DefaultMetricsFactory } + + # This section configures how metric ids are generated. A metric id is a unique combination of + # a metric name and metric tags. + id-generator { + + # The class name of a component implementing + # com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator. If it is not qualified, the + # driver assumes that it resides in the package com.datastax.oss.driver.internal.core.metrics. + # + # The driver ships with two built-in implementations: + # + # - DefaultMetricIdGenerator: generates identifiers composed solely of (unique) metric names; + # it does not generate tags. It is mostly suitable for use with metrics libraries that do + # not support tags, like Dropwizard. + # - TaggingMetricIdGenerator: generates identifiers composed of name and tags. It is mostly + # suitable for use with metrics libraries that support tags, like Micrometer or MicroProfile + # Metrics. + # + # For example, here is how each one of them generates identifiers for the session metric + # "bytes-sent", assuming that the session is named "s0": + # - DefaultMetricIdGenerator: name "s0.bytes-sent", tags: {}. + # - TaggingMetricIdGenerator: name "session.bytes-sent", tags: {"session":"s0"} + # + # Here is how each one of them generates identifiers for the node metric "bytes-sent", + # assuming that the session is named "s0", and the node's broadcast address is 10.1.2.3:9042: + # - DefaultMetricIdGenerator: name "s0.nodes.10_1_2_3:9042.bytes-sent", tags: {}. + # - TaggingMetricIdGenerator: name "nodes.bytes-sent", tags: { "session" : "s0", + # "node" : "\10.1.2.3:9042" } + # + # As shown above, both built-in implementations generate names that are path-like structures + # separated by dots. This is indeed the most common expected format by reporting tools. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + class = DefaultMetricIdGenerator + + # An optional prefix to prepend to each generated metric name. + # + # The prefix should not start nor end with a dot or any other path separator; the following + # are two valid examples: "cassandra" or "myapp.prod.cassandra". + # + # For example, if this prefix is set to "cassandra", here is how the session metric + # "bytes-sent" would be named, assuming that the session is named "s0": + # - with DefaultMetricIdGenerator: "cassandra.s0.bytes-sent" + # - with TaggingMetricIdGenerator: "cassandra.session.bytes-sent" + # + # Here is how the node metric "bytes-sent" would be named, assuming that the session is named + # "s0", and the node's broadcast address is 10.1.2.3:9042: + # - with DefaultMetricIdGenerator: "cassandra.s0.nodes.10_1_2_3:9042.bytes-sent" + # - with TaggingMetricIdGenerator: "cassandra.nodes.bytes-sent" + # + # Required: no + # Modifiable at runtime: no + # Overridable in a profile: no + // prefix = "cassandra" + } + # The session-level metrics (all disabled by default). # # Required: yes @@ -1355,10 +1413,12 @@ datastax-java-driver { # Overridable in a profile: no session { enabled = [ - # The number and rate of bytes sent for the entire session (exposed as a Meter). + # The number and rate of bytes sent for the entire session (exposed as a Meter if available, + # otherwise as a Counter). // bytes-sent, - # The number and rate of bytes received for the entire session (exposed as a Meter). + # The number and rate of bytes received for the entire session (exposed as a Meter if + # available, otherwise as a Counter). // bytes-received # The number of nodes to which the driver has at least one active connection (exposed as a @@ -1375,7 +1435,7 @@ datastax-java-driver { # with a DriverTimeoutException (exposed as a Counter). // cql-client-timeouts, - # The size of the driver-side cache of CQL prepared statements. + # The size of the driver-side cache of CQL prepared statements (exposed as a Gauge). # # The cache uses weak values eviction, so this represents the number of PreparedStatement # instances that your application has created, and is still holding a reference to. Note @@ -1596,10 +1656,12 @@ datastax-java-driver { # See the description of the connection.max-orphan-requests option for more details. // pool.orphaned-streams, - # The number and rate of bytes sent to this node (exposed as a Meter). + # The number and rate of bytes sent to this node (exposed as a Meter if available, otherwise + # as a Counter). // bytes-sent, - # The number and rate of bytes received from this node (exposed as a Meter). + # The number and rate of bytes received from this node (exposed as a Meter if available, + # otherwise as a Counter). // bytes-received, # The throughput and latency percentiles of individual CQL messages sent to this node as diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGeneratorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGeneratorTest.java new file mode 100644 index 00000000000..851f7b843c2 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdGeneratorTest.java @@ -0,0 +1,108 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.EndPoint; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(DataProviderRunner.class) +public class DefaultMetricIdGeneratorTest { + + @Mock private InternalDriverContext context; + + @Mock private DriverConfig config; + + @Mock private DriverExecutionProfile profile; + + @Mock private Node node; + + @Mock private EndPoint endpoint; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + given(context.getConfig()).willReturn(config); + given(context.getSessionName()).willReturn("s0"); + given(config.getDefaultProfile()).willReturn(profile); + given(node.getEndPoint()).willReturn(endpoint); + given(endpoint.asMetricPrefix()).willReturn("10_1_2_3:9042"); + } + + @Test + @UseDataProvider("sessionMetrics") + public void should_generate_session_metric(String prefix, String expectedName) { + // given + given(profile.getString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, "")) + .willReturn(prefix); + DefaultMetricIdGenerator generator = new DefaultMetricIdGenerator(context); + // when + MetricId id = generator.sessionMetricId(DefaultSessionMetric.CONNECTED_NODES); + // then + assertThat(id.getName()).isEqualTo(expectedName); + assertThat(id.getTags()).isEmpty(); + } + + @Test + @UseDataProvider("nodeMetrics") + public void should_generate_node_metric(String prefix, String expectedName) { + // given + given(profile.getString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, "")) + .willReturn(prefix); + DefaultMetricIdGenerator generator = new DefaultMetricIdGenerator(context); + // when + MetricId id = generator.nodeMetricId(node, DefaultNodeMetric.CQL_MESSAGES); + // then + assertThat(id.getName()).isEqualTo(expectedName); + assertThat(id.getTags()).isEmpty(); + } + + @DataProvider + public static Object[][] sessionMetrics() { + String suffix = DefaultSessionMetric.CONNECTED_NODES.getPath(); + return new Object[][] { + new Object[] {"", "s0." + suffix}, + new Object[] {"cassandra", "cassandra.s0." + suffix}, + new Object[] {"app.cassandra", "app.cassandra.s0." + suffix} + }; + } + + @DataProvider + public static Object[][] nodeMetrics() { + String suffix = DefaultNodeMetric.CQL_MESSAGES.getPath(); + return new Object[][] { + new Object[] {"", "s0.nodes.10_1_2_3:9042." + suffix}, + new Object[] {"cassandra", "cassandra.s0.nodes.10_1_2_3:9042." + suffix}, + new Object[] {"app.cassandra", "app.cassandra.s0.nodes.10_1_2_3:9042." + suffix} + }; + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdTest.java new file mode 100644 index 00000000000..91b7e9490af --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricIdTest.java @@ -0,0 +1,61 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.collect.ImmutableMap; +import org.junit.Test; + +public class DefaultMetricIdTest { + + @Test + public void testGetName() { + DefaultMetricId id = new DefaultMetricId("metric1", ImmutableMap.of()); + assertThat(id.getName()).isEqualTo("metric1"); + } + + @Test + public void testGetTags() { + DefaultMetricId id = + new DefaultMetricId("metric1", ImmutableMap.of("tag1", "value1", "tag2", "value2")); + assertThat(id.getTags()) + .hasSize(2) + .containsEntry("tag1", "value1") + .containsEntry("tag2", "value2"); + } + + @Test + public void testEquals() { + DefaultMetricId id1 = + new DefaultMetricId("metric1", ImmutableMap.of("tag1", "value1", "tag2", "value2")); + DefaultMetricId id2 = + new DefaultMetricId("metric1", ImmutableMap.of("tag1", "value1", "tag2", "value2")); + DefaultMetricId id3 = + new DefaultMetricId("metric2", ImmutableMap.of("tag1", "value1", "tag2", "value2")); + DefaultMetricId id4 = new DefaultMetricId("metric1", ImmutableMap.of("tag2", "value2")); + assertThat(id1).isEqualTo(id2).isNotEqualTo(id3).isNotEqualTo(id4); + } + + @Test + public void testHashCode() { + DefaultMetricId id1 = + new DefaultMetricId("metric1", ImmutableMap.of("tag1", "value1", "tag2", "value2")); + DefaultMetricId id2 = + new DefaultMetricId("metric1", ImmutableMap.of("tag1", "value1", "tag2", "value2")); + assertThat(id1).hasSameHashCodeAs(id2); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java index 44d0131283f..51886d712a6 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java @@ -35,7 +35,7 @@ import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.time.Duration; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -102,8 +102,8 @@ public void should_throw_if_registry_of_wrong_type() { InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); DriverConfig config = mock(DriverConfig.class); - Duration expireAfter = LOWEST_ACCEPTABLE_EXPIRE_AFTER.minusMinutes(1); - List enabledMetrics = Arrays.asList(DefaultSessionMetric.CQL_REQUESTS.getPath()); + List enabledMetrics = + Collections.singletonList(DefaultSessionMetric.CQL_REQUESTS.getPath()); // when when(config.getDefaultProfile()).thenReturn(profile); when(context.getConfig()).thenReturn(config); @@ -111,14 +111,14 @@ public void should_throw_if_registry_of_wrong_type() { // registry object is not a registry type when(context.getMetricRegistry()).thenReturn(Integer.MAX_VALUE); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); + .thenReturn(LOWEST_ACCEPTABLE_EXPIRE_AFTER); when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) .thenReturn(enabledMetrics); // then try { new DropwizardMetricsFactory(context); fail( - "MetricsFactory should require correct registy object type: " + "MetricsFactory should require correct registry object type: " + MetricRegistry.class.getName()); } catch (IllegalArgumentException iae) { assertThat(iae.getMessage()) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGeneratorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGeneratorTest.java new file mode 100644 index 00000000000..02fdc9fb0ab --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/TaggingMetricIdGeneratorTest.java @@ -0,0 +1,114 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.EndPoint; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.google.common.collect.ImmutableMap; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(DataProviderRunner.class) +public class TaggingMetricIdGeneratorTest { + + @Mock private InternalDriverContext context; + + @Mock private DriverConfig config; + + @Mock private DriverExecutionProfile profile; + + @Mock private Node node; + + @Mock private EndPoint endpoint; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + given(context.getConfig()).willReturn(config); + given(context.getSessionName()).willReturn("s0"); + given(config.getDefaultProfile()).willReturn(profile); + given(node.getEndPoint()).willReturn(endpoint); + given(endpoint.toString()).willReturn("/10.1.2.3:9042"); + } + + @Test + @UseDataProvider("sessionMetrics") + public void should_generate_session_metric( + String prefix, String expectedName, Map expectedTags) { + // given + given(profile.getString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, "")) + .willReturn(prefix); + TaggingMetricIdGenerator generator = new TaggingMetricIdGenerator(context); + // when + MetricId id = generator.sessionMetricId(DefaultSessionMetric.CONNECTED_NODES); + // then + assertThat(id.getName()).isEqualTo(expectedName); + assertThat(id.getTags()).isEqualTo(expectedTags); + } + + @Test + @UseDataProvider("nodeMetrics") + public void should_generate_node_metric( + String prefix, String expectedName, Map expectedTags) { + // given + given(profile.getString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, "")) + .willReturn(prefix); + TaggingMetricIdGenerator generator = new TaggingMetricIdGenerator(context); + // when + MetricId id = generator.nodeMetricId(node, DefaultNodeMetric.CQL_MESSAGES); + // then + assertThat(id.getName()).isEqualTo(expectedName); + assertThat(id.getTags()).isEqualTo(expectedTags); + } + + @DataProvider + public static Object[][] sessionMetrics() { + String suffix = DefaultSessionMetric.CONNECTED_NODES.getPath(); + ImmutableMap tags = ImmutableMap.of("session", "s0"); + return new Object[][] { + new Object[] {"", "session." + suffix, tags}, + new Object[] {"cassandra", "cassandra.session." + suffix, tags}, + new Object[] {"app.cassandra", "app.cassandra.session." + suffix, tags} + }; + } + + @DataProvider + public static Object[][] nodeMetrics() { + String suffix = DefaultNodeMetric.CQL_MESSAGES.getPath(); + ImmutableMap tags = ImmutableMap.of("session", "s0", "node", "/10.1.2.3:9042"); + return new Object[][] { + new Object[] {"", "nodes." + suffix, tags}, + new Object[] {"cassandra", "cassandra.nodes." + suffix, tags}, + new Object[] {"app.cassandra", "app.cassandra.nodes." + suffix, tags} + }; + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java index 1748e91028d..f6bd9c23c5e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java @@ -15,80 +15,215 @@ */ package com.datastax.oss.driver.metrics.common; -import static org.assertj.core.api.Assertions.assertThat; - import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.CqlSessionBuilder; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; -import com.datastax.oss.driver.api.core.metrics.NodeMetric; -import com.datastax.oss.driver.api.core.metrics.SessionMetric; -import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; +import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; -import java.util.Collection; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.core.metrics.FakeTicker; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.DefaultMetricIdGenerator; +import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; +import com.datastax.oss.driver.internal.core.metrics.TaggingMetricIdGenerator; +import com.datastax.oss.driver.shaded.guava.common.base.Ticker; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.net.InetSocketAddress; +import java.time.Duration; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.ClassRule; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(DataProviderRunner.class) public abstract class AbstractMetricsTestBase { - @ClassRule public static final CcmRule CCM_RULE = CcmRule.getInstance(); + protected static final List ENABLED_SESSION_METRICS = + Arrays.asList(DefaultSessionMetric.values()); - private static final List ENABLED_SESSION_METRICS = - Stream.of(DefaultSessionMetric.values()) - .map(DefaultSessionMetric::getPath) - .collect(Collectors.toList()); - private static final List ENABLED_NODE_METRICS = - Stream.of(DefaultNodeMetric.values()) - .map(DefaultNodeMetric::getPath) - .collect(Collectors.toList()); + protected static final List ENABLED_NODE_METRICS = + Arrays.asList(DefaultNodeMetric.values()); - protected Object getMetricRegistry() { - return null; - } + protected abstract SimulacronRule simulacron(); + + protected abstract Object newMetricRegistry(); - protected abstract String getMetricFactoryClass(); + protected abstract String getMetricsFactoryClass(); + + protected abstract MetricsFactory newTickingMetricsFactory( + InternalDriverContext context, Ticker ticker); protected abstract void assertMetrics(CqlSession session); - protected abstract Collection getRegistryMetrics(); + protected abstract void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception; + + protected abstract void assertNodeMetricsNotEvicted(CqlSession session, Node node) + throws Exception; + + @Before + public void clearPrimes() { + simulacron().cluster().clearLogs(); + simulacron().cluster().clearPrimes(true); + } @Test - public void should_expose_metrics() { + @UseDataProvider("descriptorsAndPrefixes") + public void should_expose_metrics(Class descriptorClass, String prefix) { + DriverConfigLoader loader = SessionUtils.configLoaderBuilder() - .withStringList(DefaultDriverOption.METRICS_SESSION_ENABLED, ENABLED_SESSION_METRICS) - .withStringList(DefaultDriverOption.METRICS_NODE_ENABLED, ENABLED_NODE_METRICS) - .withString(DefaultDriverOption.METRICS_FACTORY_CLASS, getMetricFactoryClass()) + .withStringList( + DefaultDriverOption.METRICS_SESSION_ENABLED, + ENABLED_SESSION_METRICS.stream() + .map(DefaultSessionMetric::getPath) + .collect(Collectors.toList())) + .withStringList( + DefaultDriverOption.METRICS_NODE_ENABLED, + ENABLED_NODE_METRICS.stream() + .map(DefaultNodeMetric::getPath) + .collect(Collectors.toList())) + .withString(DefaultDriverOption.METRICS_FACTORY_CLASS, getMetricsFactoryClass()) + .withString( + DefaultDriverOption.METRICS_ID_GENERATOR_CLASS, descriptorClass.getSimpleName()) + .withString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, prefix) .build(); - CqlSessionBuilder builder = - CqlSession.builder().addContactEndPoints(CCM_RULE.getContactPoints()); + try (CqlSession session = - (CqlSession) - builder.withConfigLoader(loader).withMetricRegistry(getMetricRegistry()).build()) { - for (int i = 0; i < 10; i++) { - session.execute("SELECT release_version FROM system.local"); + CqlSession.builder() + .addContactEndPoints(simulacron().getContactPoints()) + .withConfigLoader(loader) + .withMetricRegistry(newMetricRegistry()) + .build()) { + + for (Node node : session.getMetadata().getNodes().values()) { + for (int i = 0; i < 10; i++) { + session.execute( + SimpleStatement.newInstance("SELECT release_version FROM system.local") + .setNode(node)); + } } - // Should have 10 requests. Assert all applicable metrics. - assertMetricsSize(getRegistryMetrics()); assertMetrics(session); } } - protected String buildSessionMetricPattern(SessionMetric metric, CqlSession s) { - return s.getContext().getSessionName() + "\\." + metric.getPath(); + @DataProvider + public static Object[][] descriptorsAndPrefixes() { + return new Object[][] { + new Object[] {DefaultMetricIdGenerator.class, ""}, + new Object[] {DefaultMetricIdGenerator.class, "cassandra"}, + new Object[] {TaggingMetricIdGenerator.class, ""}, + new Object[] {TaggingMetricIdGenerator.class, "cassandra"}, + }; } - protected String buildNodeMetricPattern(NodeMetric metric, CqlSession s) { - return s.getContext().getSessionName() + "\\.nodes\\.\\S*\\." + metric.getPath(); + @Test + public void should_evict_node_level_metrics() throws Exception { + // given + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withStringList( + DefaultDriverOption.METRICS_SESSION_ENABLED, + ENABLED_SESSION_METRICS.stream() + .map(DefaultSessionMetric::getPath) + .collect(Collectors.toList())) + .withStringList( + DefaultDriverOption.METRICS_NODE_ENABLED, + ENABLED_NODE_METRICS.stream() + .map(DefaultNodeMetric::getPath) + .collect(Collectors.toList())) + .withDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER, Duration.ofHours(1)) + .build(); + FakeTicker fakeTicker = new FakeTicker(); + try (CqlSession session = + new TestSessionBuilder() + .addContactEndPoints(simulacron().getContactPoints()) + .withConfigLoader(loader) + .withMetricRegistry(newMetricRegistry()) + .withTicker(fakeTicker) + .build()) { + + for (Node node : session.getMetadata().getNodes().values()) { + for (int i = 0; i < 10; i++) { + session.execute( + SimpleStatement.newInstance("SELECT release_version FROM system.local") + .setNode(node)); + } + } + + Node node1 = findNode(session, 0); + Node node2 = findNode(session, 1); + Node node3 = findNode(session, 2); + + // when advance time to before eviction + fakeTicker.advance(Duration.ofMinutes(59)); + // execute query that updates only node1 + session.execute( + SimpleStatement.newInstance("SELECT release_version FROM system.local").setNode(node1)); + // advance time to after eviction + fakeTicker.advance(Duration.ofMinutes(2)); + + // then no node-level metrics should be evicted from node1 + assertNodeMetricsNotEvicted(session, node1); + // node2 and node3 metrics should have been evicted + assertNodeMetricsEvicted(session, node2); + assertNodeMetricsEvicted(session, node3); + } + } + + private Node findNode(CqlSession session, int id) { + InetSocketAddress address1 = simulacron().cluster().node(id).inetSocketAddress(); + return session.getMetadata().findNode(address1).orElseThrow(IllegalStateException::new); + } + + private class TestSessionBuilder extends SessionBuilder { + + private Ticker ticker; + + @Override + protected CqlSession wrap(@NonNull CqlSession defaultSession) { + return defaultSession; + } + + public TestSessionBuilder withTicker(Ticker ticker) { + this.ticker = ticker; + return this; + } + + @Override + protected DriverContext buildContext( + DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { + return new TestDriverContext(configLoader, programmaticArguments, ticker); + } } - private void assertMetricsSize(Collection metrics) { - assertThat(metrics).hasSize(ENABLED_SESSION_METRICS.size() + ENABLED_NODE_METRICS.size()); + private class TestDriverContext extends DefaultDriverContext { + + private final Ticker ticker; + + public TestDriverContext( + @NonNull DriverConfigLoader configLoader, + @NonNull ProgrammaticArguments programmaticArguments, + @NonNull Ticker ticker) { + super(configLoader, programmaticArguments); + this.ticker = ticker; + } + + @Override + protected MetricsFactory buildMetricsFactory() { + return newTickingMetricsFactory(this, ticker); + } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java index c9717475cc2..d4261c2d967 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java @@ -16,153 +16,211 @@ package com.datastax.oss.driver.metrics.micrometer; import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; +import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; +import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerMetricsFactory; +import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerNodeMetricUpdater; +import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerTags; import com.datastax.oss.driver.metrics.common.AbstractMetricsTestBase; +import com.datastax.oss.driver.shaded.guava.common.base.Ticker; +import com.datastax.oss.driver.shaded.guava.common.cache.Cache; +import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import java.util.Collection; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.regex.Pattern; -import org.assertj.core.api.Condition; +import java.lang.reflect.Field; +import org.junit.ClassRule; import org.junit.experimental.categories.Category; @Category(ParallelizableTests.class) public class MicrometerMetricsIT extends AbstractMetricsTestBase { - private static final MeterRegistry METER_REGISTRY = new SimpleMeterRegistry(); + @ClassRule + public static final SimulacronRule SIMULACRON_RULE = + new SimulacronRule(ClusterSpec.builder().withNodes(3)); @Override - protected void assertMetrics(CqlSession session) { - await() - .pollInterval(500, TimeUnit.MILLISECONDS) - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> - assertThat(METER_REGISTRY.getMeters()) - .haveExactly( - 1, - buildTimerCondition( - "CQL_REQUESTS should be a SESSION Timer with count 10", - buildSessionMetricPattern(DefaultSessionMetric.CQL_REQUESTS, session), - a -> a == 10)) - .haveExactly( - 1, - buildTimerCondition( - "CQL_MESSAGESS should be a NODE Timer with count 10", - buildNodeMetricPattern(DefaultNodeMetric.CQL_MESSAGES, session), - a -> a == 10)) - .haveExactly( - 1, - buildGaugeCondition( - "CONNECTED_NODES should be a SESSION Gauge with count 1", - buildSessionMetricPattern( - DefaultSessionMetric.CONNECTED_NODES, session), - a -> a == 1)) - .haveExactly( - 1, - buildCounterCondition( - "RETRIES should be a NODE Counter with count 0", - buildNodeMetricPattern(DefaultNodeMetric.RETRIES, session), - a -> a == 0)) - .haveExactly( - 1, - buildCounterCondition( - "BYTES_SENT should be a SESSION Counter with count > 0", - buildSessionMetricPattern(DefaultSessionMetric.BYTES_SENT, session), - a -> a > 0)) - .haveExactly( - 1, - buildCounterCondition( - "BYTES_SENT should be a SESSION Counter with count > 0", - buildNodeMetricPattern(DefaultNodeMetric.BYTES_SENT, session), - a -> a > 0)) - .haveExactly( - 1, - buildCounterCondition( - "BYTES_RECEIVED should be a SESSION Counter with count > 0", - buildSessionMetricPattern(DefaultSessionMetric.BYTES_RECEIVED, session), - a -> a > 0)) - .haveExactly( - 1, - buildGaugeCondition( - "AVAILABLE_STREAMS should be a NODE Gauge with count 1024", - buildNodeMetricPattern(DefaultNodeMetric.AVAILABLE_STREAMS, session), - a -> a == 1024)) - .haveExactly( - 1, - buildCounterCondition( - "BYTES_RECEIVED should be a NODE Counter with count > 0", - buildNodeMetricPattern(DefaultNodeMetric.BYTES_RECEIVED, session), - a -> a > 0))); + protected SimulacronRule simulacron() { + return SIMULACRON_RULE; } @Override - protected Object getMetricRegistry() { - return METER_REGISTRY; + protected MeterRegistry newMetricRegistry() { + return new SimpleMeterRegistry(); } @Override - protected String getMetricFactoryClass() { + protected String getMetricsFactoryClass() { return "MicrometerMetricsFactory"; } @Override - protected Collection getRegistryMetrics() { - return METER_REGISTRY.getMeters(); + protected MetricsFactory newTickingMetricsFactory(InternalDriverContext context, Ticker ticker) { + return new MicrometerMetricsFactory(context, ticker); } - private Condition buildTimerCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition(description) { - @Override - public boolean matches(Meter obj) { - if (!(obj instanceof Timer)) { - return false; - } - Timer timer = (Timer) obj; - return Pattern.matches(metricPattern, timer.getId().getName()) - && verifyFunction.apply(timer.count()); + @Override + protected void assertMetrics(CqlSession session) { + + MeterRegistry registry = + (MeterRegistry) ((InternalDriverContext) session.getContext()).getMetricRegistry(); + assertThat(registry).isNotNull(); + + assertThat(registry.getMeters()) + .hasSize(ENABLED_SESSION_METRICS.size() + ENABLED_NODE_METRICS.size() * 3); + + MetricIdGenerator metricIdGenerator = + ((InternalDriverContext) session.getContext()).getMetricIdGenerator(); + + for (DefaultSessionMetric metric : ENABLED_SESSION_METRICS) { + MetricId id = metricIdGenerator.sessionMetricId(metric); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + Meter m = registry.find(id.getName()).tags(tags).meter(); + assertThat(m).isNotNull(); + switch (metric) { + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).count()).isGreaterThan(0.0); + break; + case CONNECTED_NODES: + assertThat(m).isInstanceOf(Gauge.class); + assertThat(((Gauge) m).value()).isEqualTo(3.0); + break; + case CQL_REQUESTS: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).count()).isEqualTo(30); + break; + case CQL_CLIENT_TIMEOUTS: + case THROTTLING_ERRORS: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).count()).isZero(); + break; + case THROTTLING_DELAY: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).count()).isZero(); + break; + case THROTTLING_QUEUE_SIZE: + case CQL_PREPARED_CACHE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat(((Gauge) m).value()).isZero(); + break; } - }; - } + } - private Condition buildCounterCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition(description) { - @Override - public boolean matches(Meter obj) { - if (!(obj instanceof Counter)) { - return false; + for (Node node : session.getMetadata().getNodes().values()) { + + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = metricIdGenerator.nodeMetricId(node, metric); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + Meter m = registry.find(id.getName()).tags(tags).meter(); + assertThat(m).isNotNull(); + switch (metric) { + case OPEN_CONNECTIONS: + assertThat(m).isInstanceOf(Gauge.class); + // control node has 2 connections + assertThat(((Gauge) m).value()).isBetween(1.0, 2.0); + break; + case CQL_MESSAGES: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).count()).isEqualTo(10); + break; + case AVAILABLE_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + assertThat(((Gauge) m).value()).isGreaterThan(100); + break; + case IN_FLIGHT: + assertThat(m).isInstanceOf(Gauge.class); + break; + case ORPHANED_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + assertThat(((Gauge) m).value()).isZero(); + break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).count()).isGreaterThan(0.0); + break; + case UNSENT_REQUESTS: + case ABORTED_REQUESTS: + case WRITE_TIMEOUTS: + case READ_TIMEOUTS: + case UNAVAILABLES: + case OTHER_ERRORS: + case RETRIES: + case RETRIES_ON_ABORTED: + case RETRIES_ON_READ_TIMEOUT: + case RETRIES_ON_WRITE_TIMEOUT: + case RETRIES_ON_UNAVAILABLE: + case RETRIES_ON_OTHER_ERROR: + case IGNORES: + case IGNORES_ON_ABORTED: + case IGNORES_ON_READ_TIMEOUT: + case IGNORES_ON_WRITE_TIMEOUT: + case IGNORES_ON_UNAVAILABLE: + case IGNORES_ON_OTHER_ERROR: + case SPECULATIVE_EXECUTIONS: + case CONNECTION_INIT_ERRORS: + case AUTHENTICATION_ERRORS: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).count()).isZero(); + break; } - Counter counter = (Counter) obj; - return Pattern.matches(metricPattern, counter.getId().getName()) - && verifyFunction.apply(counter.count()); } - }; + } } - private Condition buildGaugeCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition(description) { - @Override - public boolean matches(Meter obj) { - if (!(obj instanceof Gauge)) { - return false; - } - Gauge gauge = (Gauge) obj; - return Pattern.matches(metricPattern, gauge.getId().getName()) - && verifyFunction.apply(gauge.value()); - } - }; + @Override + protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) throws Exception { + InternalDriverContext context = (InternalDriverContext) session.getContext(); + MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); + MeterRegistry registry = (MeterRegistry) context.getMetricRegistry(); + assertThat(registry).isNotNull(); + // FIXME see JAVA-2929 + triggerCacheCleanup(context.getMetricsFactory()); + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = metricIdGenerator.nodeMetricId(node, metric); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + Meter m = registry.find(id.getName()).tags(tags).meter(); + assertThat(m).isNotNull(); + } + } + + @Override + protected void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception { + InternalDriverContext context = (InternalDriverContext) session.getContext(); + MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); + MeterRegistry registry = (MeterRegistry) context.getMetricRegistry(); + assertThat(registry).isNotNull(); + // FIXME see JAVA-2929 + triggerCacheCleanup(context.getMetricsFactory()); + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = metricIdGenerator.nodeMetricId(node, metric); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + Meter m = registry.find(id.getName()).tags(tags).meter(); + assertThat(m).isNull(); + } + } + + private void triggerCacheCleanup(MetricsFactory metricsFactory) throws Exception { + Field metricsCache = MicrometerMetricsFactory.class.getDeclaredField("metricsCache"); + metricsCache.setAccessible(true); + @SuppressWarnings("unchecked") + Cache cache = + (Cache) metricsCache.get(metricsFactory); + cache.cleanUp(); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java index 446bf9c309b..52a05f7d593 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java @@ -16,171 +16,216 @@ package com.datastax.oss.driver.metrics.microprofile; import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; +import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; +import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerNodeMetricUpdater; +import com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileMetricsFactory; +import com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileTags; import com.datastax.oss.driver.metrics.common.AbstractMetricsTestBase; +import com.datastax.oss.driver.shaded.guava.common.base.Ticker; +import com.datastax.oss.driver.shaded.guava.common.cache.Cache; +import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import io.smallrye.metrics.MetricsRegistryImpl; -import java.util.Collection; -import java.util.Map.Entry; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.regex.Pattern; -import org.assertj.core.api.Condition; +import java.lang.reflect.Field; import org.eclipse.microprofile.metrics.Counter; import org.eclipse.microprofile.metrics.Gauge; import org.eclipse.microprofile.metrics.Meter; import org.eclipse.microprofile.metrics.Metric; import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Tag; import org.eclipse.microprofile.metrics.Timer; +import org.junit.ClassRule; import org.junit.experimental.categories.Category; @Category(ParallelizableTests.class) public class MicroProfileMetricsIT extends AbstractMetricsTestBase { - private static final MetricRegistry METRIC_REGISTRY = new MetricsRegistryImpl(); + @ClassRule + public static final SimulacronRule SIMULACRON_RULE = + new SimulacronRule(ClusterSpec.builder().withNodes(3)); @Override - protected void assertMetrics(CqlSession session) { - await() - .pollInterval(500, TimeUnit.MILLISECONDS) - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> - assertThat(METRIC_REGISTRY.getMetrics()) - .hasEntrySatisfying( - buildTimerCondition( - "CQL_REQUESTS should be a SESSION Timer with count 10", - buildSessionMetricPattern(DefaultSessionMetric.CQL_REQUESTS, session), - a -> a == 10)) - .hasEntrySatisfying( - buildGaugeCondition( - "CONNECTED_NODES should be a SESSION Gauge with count 1", - buildSessionMetricPattern( - DefaultSessionMetric.CONNECTED_NODES, session), - a -> a == 1)) - .hasEntrySatisfying( - buildMeterCondition( - "BYTES_SENT should be a SESSION Meter with count > 0", - buildSessionMetricPattern(DefaultSessionMetric.BYTES_SENT, session), - a -> a > 0)) - .hasEntrySatisfying( - buildMeterCondition( - "BYTES_SENT should be a SESSION Meter with count > 0", - buildNodeMetricPattern(DefaultNodeMetric.BYTES_SENT, session), - a -> a > 0)) - .hasEntrySatisfying( - buildMeterCondition( - "BYTES_RECEIVED should be a SESSION Meter with count > 0", - buildSessionMetricPattern(DefaultSessionMetric.BYTES_RECEIVED, session), - a -> a > 0)) - .hasEntrySatisfying( - buildMeterCondition( - "BYTES_RECEIVED should be a NODE Meter with count > 0", - buildNodeMetricPattern(DefaultNodeMetric.BYTES_RECEIVED, session), - a -> a > 0)) - .hasEntrySatisfying( - buildTimerCondition( - "CQL_MESSAGESS should be a NODE Timer with count 10", - buildNodeMetricPattern(DefaultNodeMetric.CQL_MESSAGES, session), - a -> a == 10)) - .hasEntrySatisfying( - buildGaugeCondition( - "AVAILABLE_STREAMS should be a NODE Gauge with count 1024", - buildNodeMetricPattern(DefaultNodeMetric.AVAILABLE_STREAMS, session), - a -> a == 1024)) - .hasEntrySatisfying( - buildCounterCondition( - "RETRIES should be a NODE Counter with count 0", - buildNodeMetricPattern(DefaultNodeMetric.RETRIES, session), - a -> a == 0))); + protected SimulacronRule simulacron() { + return SIMULACRON_RULE; } @Override - protected Object getMetricRegistry() { - return METRIC_REGISTRY; + protected MetricRegistry newMetricRegistry() { + return new MetricsRegistryImpl(); } @Override - protected String getMetricFactoryClass() { + protected String getMetricsFactoryClass() { return "MicroProfileMetricsFactory"; } @Override - protected Collection getRegistryMetrics() { - return METRIC_REGISTRY.getMetrics().entrySet(); + protected MetricsFactory newTickingMetricsFactory(InternalDriverContext context, Ticker ticker) { + return new MicroProfileMetricsFactory(context, ticker); } - private Condition> buildTimerCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition>(description) { - @Override - public boolean matches(Entry metric) { - if (!(metric.getValue() instanceof Timer)) { - // Metric is not a Timer - return false; - } - final Timer timer = (Timer) metric.getValue(); - final MetricID id = metric.getKey(); - return verifyFunction.apply(timer.getCount()) - && Pattern.matches(metricPattern, id.getName()); + @Override + protected void assertMetrics(CqlSession session) { + + MetricRegistry registry = + (MetricRegistry) ((InternalDriverContext) session.getContext()).getMetricRegistry(); + assertThat(registry).isNotNull(); + + assertThat(registry.getMetrics()) + .hasSize(ENABLED_SESSION_METRICS.size() + ENABLED_NODE_METRICS.size() * 3); + + MetricIdGenerator metricIdGenerator = + ((InternalDriverContext) session.getContext()).getMetricIdGenerator(); + + for (DefaultSessionMetric metric : ENABLED_SESSION_METRICS) { + MetricId metricId = metricIdGenerator.sessionMetricId(metric); + Tag[] tags = MicroProfileTags.toMicroProfileTags(metricId.getTags()); + MetricID id = new MetricID(metricId.getName(), tags); + Metric m = registry.getMetrics().get(id); + assertThat(m).isNotNull(); + switch (metric) { + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Meter.class); + assertThat(((Meter) m).getCount()).isGreaterThan(0L); + break; + case CONNECTED_NODES: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Integer) ((Gauge) m).getValue()).isEqualTo(3); + break; + case CQL_REQUESTS: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).getCount()).isEqualTo(30L); + break; + case CQL_CLIENT_TIMEOUTS: + case THROTTLING_ERRORS: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).getCount()).isZero(); + break; + case THROTTLING_DELAY: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).getCount()).isZero(); + break; + case THROTTLING_QUEUE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Integer) ((Gauge) m).getValue()).isZero(); + break; + case CQL_PREPARED_CACHE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Long) ((Gauge) m).getValue()).isZero(); + break; } - }; - } + } - private Condition> buildCounterCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition>(description) { - @Override - public boolean matches(Entry metric) { - if (!(metric.getValue() instanceof Counter)) { - // Metric is not a Counter - return false; + for (Node node : session.getMetadata().getNodes().values()) { + + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId description = metricIdGenerator.nodeMetricId(node, metric); + Tag[] tags = MicroProfileTags.toMicroProfileTags(description.getTags()); + MetricID id = new MetricID(description.getName(), tags); + Metric m = registry.getMetrics().get(id); + assertThat(m).isNotNull(); + switch (metric) { + case OPEN_CONNECTIONS: + assertThat(m).isInstanceOf(Gauge.class); + // control node has 2 connections + assertThat((Integer) ((Gauge) m).getValue()).isBetween(1, 2); + break; + case CQL_MESSAGES: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).getCount()).isEqualTo(10L); + break; + case AVAILABLE_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Integer) ((Gauge) m).getValue()).isGreaterThan(100); + break; + case IN_FLIGHT: + assertThat(m).isInstanceOf(Gauge.class); + break; + case ORPHANED_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Integer) ((Gauge) m).getValue()).isZero(); + break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Meter.class); + assertThat(((Meter) m).getCount()).isGreaterThan(0L); + break; + case UNSENT_REQUESTS: + case ABORTED_REQUESTS: + case WRITE_TIMEOUTS: + case READ_TIMEOUTS: + case UNAVAILABLES: + case OTHER_ERRORS: + case RETRIES: + case RETRIES_ON_ABORTED: + case RETRIES_ON_READ_TIMEOUT: + case RETRIES_ON_WRITE_TIMEOUT: + case RETRIES_ON_UNAVAILABLE: + case RETRIES_ON_OTHER_ERROR: + case IGNORES: + case IGNORES_ON_ABORTED: + case IGNORES_ON_READ_TIMEOUT: + case IGNORES_ON_WRITE_TIMEOUT: + case IGNORES_ON_UNAVAILABLE: + case IGNORES_ON_OTHER_ERROR: + case SPECULATIVE_EXECUTIONS: + case CONNECTION_INIT_ERRORS: + case AUTHENTICATION_ERRORS: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).getCount()).isZero(); + break; } - final Counter counter = (Counter) metric.getValue(); - final MetricID id = metric.getKey(); - return verifyFunction.apply(counter.getCount()) - && Pattern.matches(metricPattern, id.getName()); } - }; + } } - private Condition> buildMeterCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition>(description) { - @Override - public boolean matches(Entry metric) { - if (!(metric.getValue() instanceof Meter)) { - // Metric is not a Meter - return false; - } - final Meter meter = (Meter) metric.getValue(); - final MetricID id = metric.getKey(); - return verifyFunction.apply(meter.getCount()) - && Pattern.matches(metricPattern, id.getName()); - } - }; + @Override + protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) throws Exception { + InternalDriverContext context = (InternalDriverContext) session.getContext(); + MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); + MetricRegistry registry = (MetricRegistry) context.getMetricRegistry(); + assertThat(registry).isNotNull(); + // FIXME see JAVA-2929 + triggerCacheCleanup(context.getMetricsFactory()); + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = metricIdGenerator.nodeMetricId(node, metric); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + assertThat(registry.getMetrics()).containsKey(new MetricID(id.getName(), tags)); + } } - private Condition> buildGaugeCondition( - String description, String metricPattern, Function verifyFunction) { - return new Condition>(description) { - @Override - public boolean matches(Entry metric) { - if (!(metric.getValue() instanceof Gauge)) { - // Metric is not a Gauge - return false; - } - final Gauge gauge = (Gauge) metric.getValue(); - final Number gaugeValue = (Number) gauge.getValue(); - final MetricID id = metric.getKey(); - return verifyFunction.apply(gaugeValue.doubleValue()) - && Pattern.matches(metricPattern, id.getName()); - } - }; + @Override + protected void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception { + InternalDriverContext context = (InternalDriverContext) session.getContext(); + MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); + MetricRegistry registry = (MetricRegistry) context.getMetricRegistry(); + assertThat(registry).isNotNull(); + // FIXME see JAVA-2929 + triggerCacheCleanup(context.getMetricsFactory()); + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = metricIdGenerator.nodeMetricId(node, metric); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + assertThat(registry.getMetrics()).doesNotContainKey(new MetricID(id.getName(), tags)); + } + } + + private void triggerCacheCleanup(MetricsFactory metricsFactory) throws Exception { + Field metricsCache = MicroProfileMetricsFactory.class.getDeclaredField("metricsCache"); + metricsCache.setAccessible(true); + @SuppressWarnings("unchecked") + Cache cache = + (Cache) metricsCache.get(metricsFactory); + cache.cleanUp(); } } diff --git a/manual/core/metrics/README.md b/manual/core/metrics/README.md index 276245dc524..46bfe7689bd 100644 --- a/manual/core/metrics/README.md +++ b/manual/core/metrics/README.md @@ -161,6 +161,61 @@ it is also possible to provide additional configuration to fine-tune the underly characteristics and precision, such as its highest expected latency, its number of significant digits to use, and its refresh interval. Again, see the [reference configuration] for more details. +### Selecting a metric identifier style + +Most metric libraries uniquely identify a metric by a name and, optionally, by a set of key-value +pairs, usually called tags. + +The `advanced.metrics.id-generator.class` option is used to customize how the driver generates +metric identifiers. The driver ships with two built-in implementations: + +- `DefaultMetricIdGenerator`: generates identifiers composed solely of (unique) metric names; it + does not generate tags. It is mostly suitable for use with metrics libraries that do not support + tags, like Dropwizard. +- `TaggingMetricIdGenerator`: generates identifiers composed of name and tags. It is mostly suitable + for use with metrics libraries that support tags, like Micrometer or MicroProfile Metrics. + +For example, here is how each one of them generates identifiers for the session metric "bytes-sent", +assuming that the session is named "s0": + +- `DefaultMetricIdGenerator`: + - name:`s0.bytes-sent` + - tags: `{}` +- `TaggingMetricIdGenerator`: + - name: `session.bytes-sent` + - tags: `{ "session" : "s0" }` + +Here is how each one of them generates identifiers for the node metric "bytes-sent", assuming that +the session is named "s0", and the node's broadcast address is 10.1.2.3:9042: + +- `DefaultMetricIdGenerator`: + - name : `s0.nodes.10_1_2_3:9042.bytes-sent` + - tags: `{}` +- `TaggingMetricIdGenerator`: + - name `nodes.bytes-sent` + - tags: `{ "session" : "s0", "node" : "\10.1.2.3:9042" }` + +As shown above, both built-in implementations generate names that are path-like structures separated +by dots. This is indeed the most common expected format by reporting tools. + +Finally, it is also possible to define a global prefix for all metric names; this can be done with +the `advanced.metrics.id-generator.prefix` option. + +The prefix should not start nor end with a dot or any other path separator; the following are two +valid examples: `cassandra` or `myapp.prod.cassandra`. + +For example, if this prefix is set to `cassandra`, here is how the session metric "bytes-sent" would +be named, assuming that the session is named "s0": + +- with `DefaultMetricIdGenerator`: `cassandra.s0.bytes-sent` +- with `TaggingMetricIdGenerator`: `cassandra.session.bytes-sent` + +Here is how the node metric "bytes-sent" would be named, assuming that the session is named "s0", +and the node's broadcast address is 10.1.2.3:9042: + +- with `DefaultMetricIdGenerator`: `cassandra.s0.nodes.10_1_2_3:9042.bytes-sent` +- with `TaggingMetricIdGenerator`: `cassandra.nodes.bytes-sent` + ### Using an external metric registry Regardless of which metrics library is used, you can provide an external metric registry object when diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java index b5214c9e4f8..d00539df191 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java @@ -16,70 +16,123 @@ package com.datastax.oss.driver.internal.metrics.micrometer; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.internal.core.metrics.MetricUpdater; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import edu.umd.cs.findbugs.annotations.Nullable; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Timer; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import net.jcip.annotations.ThreadSafe; @ThreadSafe -public abstract class MicrometerMetricUpdater implements MetricUpdater { - protected final Set enabledMetrics; +public abstract class MicrometerMetricUpdater extends AbstractMetricUpdater { + protected final MeterRegistry registry; + protected final ConcurrentMap metrics = new ConcurrentHashMap<>(); - protected MicrometerMetricUpdater(Set enabledMetrics, MeterRegistry registry) { - this.enabledMetrics = enabledMetrics; + protected MicrometerMetricUpdater( + InternalDriverContext context, Set enabledMetrics, MeterRegistry registry) { + super(context, enabledMetrics); this.registry = registry; } - protected abstract String buildFullName(MetricT metric, String profileName); - @Override - public void incrementCounter(MetricT metric, String profileName, long amount) { + public void incrementCounter(MetricT metric, @Nullable String profileName, long amount) { if (isEnabled(metric, profileName)) { - registry.counter(buildFullName(metric, profileName)).increment(amount); + getOrCreateCounterFor(metric).increment(amount); } } @Override - public void updateHistogram(MetricT metric, String profileName, long value) { + public void updateHistogram(MetricT metric, @Nullable String profileName, long value) { if (isEnabled(metric, profileName)) { - registry.summary(buildFullName(metric, profileName)).record(value); + getOrCreateDistributionSummaryFor(metric).record(value); } } @Override - public void markMeter(MetricT metric, String profileName, long amount) { + public void markMeter(MetricT metric, @Nullable String profileName, long amount) { if (isEnabled(metric, profileName)) { - registry.counter(buildFullName(metric, profileName)).increment(amount); + // There is no meter type in Micrometer, so use a counter + getOrCreateCounterFor(metric).increment(amount); } } @Override - public void updateTimer(MetricT metric, String profileName, long duration, TimeUnit unit) { + public void updateTimer( + MetricT metric, @Nullable String profileName, long duration, TimeUnit unit) { if (isEnabled(metric, profileName)) { - registry.timer(buildFullName(metric, profileName)).record(duration, unit); + getOrCreateTimerFor(metric).record(duration, unit); } } - @Override - public boolean isEnabled(MetricT metric, String profileName) { - return enabledMetrics.contains(metric); - } + protected abstract MetricId getMetricId(MetricT metric); - protected void initializeDefaultCounter(MetricT metric, String profileName) { - if (isEnabled(metric, profileName)) { - // Just initialize eagerly so that the metric appears even when it has no data yet - registry.counter(buildFullName(metric, profileName)); + protected void initializeGauge( + MetricT metric, DriverExecutionProfile profile, Supplier supplier) { + if (isEnabled(metric, profile.getName())) { + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + return Gauge.builder(id.getName(), supplier).tags(tags).register(registry); + }); } } - protected void initializeTimer(MetricT metric, DriverExecutionProfile config) { - String profileName = config.getName(); - if (isEnabled(metric, profileName)) { - String fullName = buildFullName(metric, profileName); + protected void initializeCounter(MetricT metric, DriverExecutionProfile profile) { + if (isEnabled(metric, profile.getName())) { + getOrCreateCounterFor(metric); + } + } - registry.timer(fullName); + protected void initializeTimer(MetricT metric, DriverExecutionProfile profile) { + if (isEnabled(metric, profile.getName())) { + getOrCreateTimerFor(metric); } } + + protected Counter getOrCreateCounterFor(MetricT metric) { + return (Counter) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + return Counter.builder(id.getName()).tags(tags).register(registry); + }); + } + + protected DistributionSummary getOrCreateDistributionSummaryFor(MetricT metric) { + return (DistributionSummary) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + return DistributionSummary.builder(id.getName()).tags(tags).register(registry); + }); + } + + protected Timer getOrCreateTimerFor(MetricT metric) { + return (Timer) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); + return Timer.builder(id.getName()).tags(tags).register(registry); + }); + } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java index 90d8badb226..f326b308733 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java @@ -101,7 +101,7 @@ public MicrometerMetricsFactory(InternalDriverContext context, Ticker ticker) { if (possibleMetricRegistry instanceof MeterRegistry) { this.registry = (MeterRegistry) possibleMetricRegistry; this.sessionUpdater = - new MicrometerSessionMetricUpdater(enabledSessionMetrics, this.registry, this.context); + new MicrometerSessionMetricUpdater(this.context, enabledSessionMetrics, this.registry); } else { // Metrics are enabled, but the registry object is not an expected type throw new IllegalArgumentException( @@ -147,7 +147,7 @@ public NodeMetricUpdater newNodeUpdater(Node node) { } MicrometerNodeMetricUpdater updater = new MicrometerNodeMetricUpdater( - node, enabledNodeMetrics, registry, context, () -> metricsCache.getIfPresent(node)); + node, context, enabledNodeMetrics, registry, () -> metricsCache.getIfPresent(node)); metricsCache.put(node, updater); return updater; } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java index f15a5366144..3c77839c4b5 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java @@ -17,79 +17,66 @@ import com.datastax.dse.driver.api.core.metrics.DseNodeMetric; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; -import com.datastax.oss.driver.internal.core.pool.ChannelPool; +import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.function.Function; +import net.jcip.annotations.ThreadSafe; +@ThreadSafe public class MicrometerNodeMetricUpdater extends MicrometerMetricUpdater implements NodeMetricUpdater { - private final String metricNamePrefix; + private final Node node; private final Runnable signalMetricUpdated; public MicrometerNodeMetricUpdater( Node node, + InternalDriverContext context, Set enabledMetrics, MeterRegistry registry, - DriverContext driverContext, Runnable signalMetricUpdated) { - super(enabledMetrics, registry); + super(context, enabledMetrics, registry); + this.node = node; this.signalMetricUpdated = signalMetricUpdated; - InternalDriverContext context = (InternalDriverContext) driverContext; - this.metricNamePrefix = buildPrefix(driverContext.getSessionName(), node.getEndPoint()); - DriverExecutionProfile config = driverContext.getConfig().getDefaultProfile(); + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); - if (enabledMetrics.contains(DefaultNodeMetric.OPEN_CONNECTIONS)) { - this.registry.gauge( - buildFullName(DefaultNodeMetric.OPEN_CONNECTIONS, null), node.getOpenConnections()); - } - initializePoolGauge( - DefaultNodeMetric.AVAILABLE_STREAMS, node, ChannelPool::getAvailableIds, context); - initializePoolGauge(DefaultNodeMetric.IN_FLIGHT, node, ChannelPool::getInFlight, context); - initializePoolGauge( - DefaultNodeMetric.ORPHANED_STREAMS, node, ChannelPool::getOrphanedIds, context); - initializeTimer(DefaultNodeMetric.CQL_MESSAGES, config); - initializeDefaultCounter(DefaultNodeMetric.UNSENT_REQUESTS, null); - initializeDefaultCounter(DefaultNodeMetric.ABORTED_REQUESTS, null); - initializeDefaultCounter(DefaultNodeMetric.WRITE_TIMEOUTS, null); - initializeDefaultCounter(DefaultNodeMetric.READ_TIMEOUTS, null); - initializeDefaultCounter(DefaultNodeMetric.UNAVAILABLES, null); - initializeDefaultCounter(DefaultNodeMetric.OTHER_ERRORS, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_ABORTED, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_ABORTED, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_UNAVAILABLE, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_OTHER_ERROR, null); - initializeDefaultCounter(DefaultNodeMetric.SPECULATIVE_EXECUTIONS, null); - initializeDefaultCounter(DefaultNodeMetric.CONNECTION_INIT_ERRORS, null); - initializeDefaultCounter(DefaultNodeMetric.AUTHENTICATION_ERRORS, null); - initializeTimer(DseNodeMetric.GRAPH_MESSAGES, driverContext.getConfig().getDefaultProfile()); - } + initializeGauge(DefaultNodeMetric.OPEN_CONNECTIONS, profile, node::getOpenConnections); + initializeGauge(DefaultNodeMetric.AVAILABLE_STREAMS, profile, () -> availableStreamIds(node)); + initializeGauge(DefaultNodeMetric.IN_FLIGHT, profile, () -> inFlightRequests(node)); + initializeGauge(DefaultNodeMetric.ORPHANED_STREAMS, profile, () -> orphanedStreamIds(node)); - @Override - public String buildFullName(NodeMetric metric, String profileName) { - return metricNamePrefix + metric.getPath(); - } + initializeCounter(DefaultNodeMetric.UNSENT_REQUESTS, profile); + initializeCounter(DefaultNodeMetric.ABORTED_REQUESTS, profile); + initializeCounter(DefaultNodeMetric.WRITE_TIMEOUTS, profile); + initializeCounter(DefaultNodeMetric.READ_TIMEOUTS, profile); + initializeCounter(DefaultNodeMetric.UNAVAILABLES, profile); + initializeCounter(DefaultNodeMetric.OTHER_ERRORS, profile); + initializeCounter(DefaultNodeMetric.RETRIES, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_ABORTED, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, profile); + initializeCounter(DefaultNodeMetric.IGNORES, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_ABORTED, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_UNAVAILABLE, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_OTHER_ERROR, profile); + initializeCounter(DefaultNodeMetric.SPECULATIVE_EXECUTIONS, profile); + initializeCounter(DefaultNodeMetric.CONNECTION_INIT_ERRORS, profile); + initializeCounter(DefaultNodeMetric.AUTHENTICATION_ERRORS, profile); - private String buildPrefix(String sessionName, EndPoint endPoint) { - return sessionName + ".nodes." + endPoint.asMetricPrefix() + "."; + initializeTimer(DefaultNodeMetric.CQL_MESSAGES, profile); + initializeTimer(DseNodeMetric.GRAPH_MESSAGES, profile); } @Override @@ -116,24 +103,15 @@ public void updateTimer(NodeMetric metric, String profileName, long duration, Ti super.updateTimer(metric, profileName, duration, unit); } - private void initializePoolGauge( - NodeMetric metric, - Node node, - Function reading, - InternalDriverContext context) { - if (enabledMetrics.contains(metric)) { - final String metricName = buildFullName(metric, null); - registry.gauge( - metricName, - context, - c -> { - ChannelPool pool = c.getPoolManager().getPools().get(node); - return (pool == null) ? 0 : reading.apply(pool); - }); + public void cleanupNodeMetrics() { + for (Meter meter : metrics.values()) { + registry.remove(meter); } + metrics.clear(); } - public void cleanupNodeMetrics() { - registry.getMeters().removeIf(metric -> metric.getId().getName().startsWith(metricNamePrefix)); + @Override + protected MetricId getMetricId(NodeMetric metric) { + return context.getMetricIdGenerator().nodeMetricId(node, metric); } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java index e1ff7bb7122..93106ea77a9 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java @@ -16,129 +16,43 @@ package com.datastax.oss.driver.internal.metrics.micrometer; import com.datastax.dse.driver.api.core.metrics.DseSessionMetric; -import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; -import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; +import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; -import com.datastax.oss.driver.internal.core.session.RequestProcessor; -import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; -import com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; -import edu.umd.cs.findbugs.annotations.Nullable; import io.micrometer.core.instrument.MeterRegistry; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import net.jcip.annotations.ThreadSafe; +@ThreadSafe public class MicrometerSessionMetricUpdater extends MicrometerMetricUpdater implements SessionMetricUpdater { - private static final Logger LOG = LoggerFactory.getLogger(MicrometerSessionMetricUpdater.class); - - private final String metricNamePrefix; - public MicrometerSessionMetricUpdater( - Set enabledMetrics, MeterRegistry registry, DriverContext driverContext) { - super(enabledMetrics, registry); - InternalDriverContext context = (InternalDriverContext) driverContext; - this.metricNamePrefix = context.getSessionName() + "."; + InternalDriverContext context, Set enabledMetrics, MeterRegistry registry) { + super(context, enabledMetrics, registry); - if (enabledMetrics.contains(DefaultSessionMetric.CONNECTED_NODES)) { - registerConnectedNodeGauge(context); - } - if (enabledMetrics.contains(DefaultSessionMetric.THROTTLING_QUEUE_SIZE)) { - registerThrottlingQueueGauge(context); - } - if (enabledMetrics.contains(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE)) { - registerPreparedCacheGauge(context); - } - initializeTimer(DefaultSessionMetric.CQL_REQUESTS, context.getConfig().getDefaultProfile()); - initializeDefaultCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, null); - initializeTimer(DefaultSessionMetric.THROTTLING_DELAY, context.getConfig().getDefaultProfile()); - initializeDefaultCounter(DefaultSessionMetric.THROTTLING_ERRORS, null); - initializeTimer( - DseSessionMetric.CONTINUOUS_CQL_REQUESTS, context.getConfig().getDefaultProfile()); - initializeDefaultCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, null); - initializeTimer(DseSessionMetric.GRAPH_REQUESTS, context.getConfig().getDefaultProfile()); - } + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); - private void registerConnectedNodeGauge(InternalDriverContext context) { - this.registry.gauge( - buildFullName(DefaultSessionMetric.CONNECTED_NODES, null), - context, - c -> { - int count = 0; - for (Node node : c.getMetadataManager().getMetadata().getNodes().values()) { - if (node.getOpenConnections() > 0) { - ++count; - } - } - return count; - }); - } + initializeGauge(DefaultSessionMetric.CONNECTED_NODES, profile, this::connectedNodes); + initializeGauge(DefaultSessionMetric.THROTTLING_QUEUE_SIZE, profile, this::throttlingQueueSize); + initializeGauge( + DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, profile, this::preparedStatementCacheSize); - private void registerThrottlingQueueGauge(InternalDriverContext context) { - this.registry.gauge( - buildFullName(DefaultSessionMetric.THROTTLING_QUEUE_SIZE, null), - context, - c -> { - RequestThrottler requestThrottler = c.getRequestThrottler(); - String logPrefix = c.getSessionName(); - if (requestThrottler instanceof ConcurrencyLimitingRequestThrottler) { - return ((ConcurrencyLimitingRequestThrottler) requestThrottler).getQueueSize(); - } - if (requestThrottler instanceof RateLimitingRequestThrottler) { - return ((RateLimitingRequestThrottler) requestThrottler).getQueueSize(); - } - LOG.warn( - "[{}] Metric {} does not support {}, it will always return 0", - logPrefix, - DefaultSessionMetric.THROTTLING_QUEUE_SIZE.getPath(), - requestThrottler.getClass().getName()); - return 0; - }); - } + initializeCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, profile); + initializeCounter(DefaultSessionMetric.THROTTLING_ERRORS, profile); + initializeCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, profile); - private void registerPreparedCacheGauge(InternalDriverContext context) { - this.registry.gauge( - buildFullName(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, null), - context, - c -> { - Cache cache = getPreparedStatementCache(c); - if (cache == null) { - LOG.warn( - "[{}] Metric {} is enabled in the config, " - + "but it looks like no CQL prepare processor is registered. " - + "The gauge will always return 0", - context.getSessionName(), - DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE.getPath()); - return 0L; - } - return cache.size(); - }); + initializeTimer(DefaultSessionMetric.CQL_REQUESTS, profile); + initializeTimer(DefaultSessionMetric.THROTTLING_DELAY, profile); + initializeTimer(DseSessionMetric.CONTINUOUS_CQL_REQUESTS, profile); + initializeTimer(DseSessionMetric.GRAPH_REQUESTS, profile); } @Override - public String buildFullName(SessionMetric metric, String profileName) { - return metricNamePrefix + metric.getPath(); - } - - @Nullable - private static Cache getPreparedStatementCache(InternalDriverContext context) { - // By default, both the sync processor and the async one are registered and they share the same - // cache. But with a custom processor registry, there could be only one of the two present. - for (RequestProcessor processor : context.getRequestProcessorRegistry().getProcessors()) { - if (processor instanceof CqlPrepareAsyncProcessor) { - return ((CqlPrepareAsyncProcessor) processor).getCache(); - } else if (processor instanceof CqlPrepareSyncProcessor) { - return ((CqlPrepareSyncProcessor) processor).getCache(); - } - } - return null; + protected MetricId getMetricId(SessionMetric metric) { + return context.getMetricIdGenerator().sessionMetricId(metric); } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerTags.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerTags.java new file mode 100644 index 00000000000..7c6e54d59bf --- /dev/null +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerTags.java @@ -0,0 +1,33 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.metrics.micrometer; + +import io.micrometer.core.instrument.Tag; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class MicrometerTags { + + public static Iterable toMicrometerTags(Map tags) { + List micrometerTags = new ArrayList<>(tags.size()); + for (Entry entry : tags.entrySet()) { + micrometerTags.add(Tag.of(entry.getKey(), entry.getValue())); + } + return micrometerTags; + } +} diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java index abaf780f5dd..17532ff30bd 100644 --- a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java @@ -35,7 +35,7 @@ import com.tngtech.java.junit.dataprovider.UseDataProvider; import io.micrometer.core.instrument.MeterRegistry; import java.time.Duration; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -104,8 +104,8 @@ public void should_throw_if_wrong_or_missing_registry_type( InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); DriverConfig config = mock(DriverConfig.class); - Duration expireAfter = LOWEST_ACCEPTABLE_EXPIRE_AFTER.minusMinutes(1); - List enabledMetrics = Arrays.asList(DefaultSessionMetric.CQL_REQUESTS.getPath()); + List enabledMetrics = + Collections.singletonList(DefaultSessionMetric.CQL_REQUESTS.getPath()); // when when(config.getDefaultProfile()).thenReturn(profile); when(context.getConfig()).thenReturn(config); @@ -113,14 +113,14 @@ public void should_throw_if_wrong_or_missing_registry_type( // registry object is not a registry type when(context.getMetricRegistry()).thenReturn(registryObj); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); + .thenReturn(LOWEST_ACCEPTABLE_EXPIRE_AFTER); when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) .thenReturn(enabledMetrics); // then try { new MicrometerMetricsFactory(context); fail( - "MetricsFactory should require correct registy object type: " + "MetricsFactory should require correct registry object type: " + MeterRegistry.class.getName()); } catch (IllegalArgumentException iae) { assertThat(iae.getMessage()).isEqualTo(expectedMsg); diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java index b712d1db8bd..2d5ea9013c5 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java @@ -16,71 +16,138 @@ package com.datastax.oss.driver.internal.metrics.microprofile; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.internal.core.metrics.MetricUpdater; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import net.jcip.annotations.ThreadSafe; +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.Gauge; +import org.eclipse.microprofile.metrics.Histogram; +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.Meter; +import org.eclipse.microprofile.metrics.Metric; import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; +import org.eclipse.microprofile.metrics.Tag; +import org.eclipse.microprofile.metrics.Timer; @ThreadSafe -public abstract class MicroProfileMetricUpdater implements MetricUpdater { +public abstract class MicroProfileMetricUpdater extends AbstractMetricUpdater { - protected final Set enabledMetrics; protected final MetricRegistry registry; + protected final ConcurrentMap metrics = new ConcurrentHashMap<>(); - protected MicroProfileMetricUpdater(Set enabledMetrics, MetricRegistry registry) { - this.enabledMetrics = enabledMetrics; + protected MicroProfileMetricUpdater( + InternalDriverContext context, Set enabledMetrics, MetricRegistry registry) { + super(context, enabledMetrics); this.registry = registry; } - protected abstract String buildFullName(MetricT metric, String profileName); - @Override - public void incrementCounter(MetricT metric, String profileName, long amount) { + public void incrementCounter(MetricT metric, @Nullable String profileName, long amount) { if (isEnabled(metric, profileName)) { - registry.counter(buildFullName(metric, profileName)).inc(amount); + getOrCreateCounterFor(metric).inc(amount); } } @Override - public void updateHistogram(MetricT metric, String profileName, long value) { + public void updateHistogram(MetricT metric, @Nullable String profileName, long value) { if (isEnabled(metric, profileName)) { - registry.histogram(buildFullName(metric, profileName)).update(value); + getOrCreateHistogramFor(metric).update(value); } } @Override - public void markMeter(MetricT metric, String profileName, long amount) { + public void markMeter(MetricT metric, @Nullable String profileName, long amount) { if (isEnabled(metric, profileName)) { - registry.meter(buildFullName(metric, profileName)).mark(amount); + getOrCreateMeterFor(metric).mark(amount); } } @Override - public void updateTimer(MetricT metric, String profileName, long duration, TimeUnit unit) { + public void updateTimer( + MetricT metric, @Nullable String profileName, long duration, TimeUnit unit) { if (isEnabled(metric, profileName)) { - registry.timer(buildFullName(metric, profileName)).update(duration, unit); + getOrCreateTimerFor(metric).update(duration, unit); } } - @Override - public boolean isEnabled(MetricT metric, String profileName) { - return enabledMetrics.contains(metric); - } + protected abstract MetricId getMetricId(MetricT metric); - protected void initializeDefaultCounter(MetricT metric, String profileName) { - if (isEnabled(metric, profileName)) { - // Just initialize eagerly so that the metric appears even when it has no data yet - registry.counter(buildFullName(metric, profileName)); + protected void initializeGauge( + MetricT metric, DriverExecutionProfile profile, Gauge supplier) { + if (isEnabled(metric, profile.getName())) { + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + String name = id.getName(); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + Metadata metadata = + Metadata.builder().withName(name).withType(MetricType.GAUGE).build(); + return registry.register(metadata, supplier, tags); + }); } } - protected void initializeTimer(MetricT metric, DriverExecutionProfile config) { - String profileName = config.getName(); - if (isEnabled(metric, profileName)) { - String fullName = buildFullName(metric, profileName); + protected void initializeCounter(MetricT metric, DriverExecutionProfile profile) { + if (isEnabled(metric, profile.getName())) { + getOrCreateCounterFor(metric); + } + } - registry.timer(fullName); + protected void initializeTimer(MetricT metric, DriverExecutionProfile profile) { + if (isEnabled(metric, profile.getName())) { + getOrCreateTimerFor(metric); } } + + protected Counter getOrCreateCounterFor(MetricT metric) { + return (Counter) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + return registry.counter(id.getName(), tags); + }); + } + + protected Meter getOrCreateMeterFor(MetricT metric) { + return (Meter) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + return registry.meter(id.getName(), tags); + }); + } + + protected Histogram getOrCreateHistogramFor(MetricT metric) { + return (Histogram) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + return registry.histogram(id.getName(), tags); + }); + } + + protected Timer getOrCreateTimerFor(MetricT metric) { + return (Timer) + metrics.computeIfAbsent( + metric, + m -> { + MetricId id = getMetricId(m); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + return registry.timer(id.getName(), tags); + }); + } } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java index 6cb9f5de47b..f06974a20d4 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java @@ -102,7 +102,7 @@ public MicroProfileMetricsFactory(InternalDriverContext context, Ticker ticker) this.registry = (MetricRegistry) possibleMetricRegistry; this.sessionUpdater = new MicroProfileSessionMetricUpdater( - enabledSessionMetrics, this.registry, this.context); + this.context, enabledSessionMetrics, this.registry); } else { // Metrics are enabled, but the registry object is not an expected type throw new IllegalArgumentException( @@ -148,7 +148,7 @@ public NodeMetricUpdater newNodeUpdater(Node node) { } MicroProfileNodeMetricUpdater updater = new MicroProfileNodeMetricUpdater( - node, enabledNodeMetrics, registry, context, () -> metricsCache.getIfPresent(node)); + node, context, enabledNodeMetrics, registry, () -> metricsCache.getIfPresent(node)); metricsCache.put(node, updater); return updater; } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java index d622210250e..5693819ac56 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java @@ -17,81 +17,67 @@ import com.datastax.dse.driver.api.core.metrics.DseNodeMetric; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; -import com.datastax.oss.driver.internal.core.pool.ChannelPool; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import org.eclipse.microprofile.metrics.Gauge; +import net.jcip.annotations.ThreadSafe; +import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Tag; +@ThreadSafe public class MicroProfileNodeMetricUpdater extends MicroProfileMetricUpdater implements NodeMetricUpdater { - private final String metricNamePrefix; + private final Node node; private final Runnable signalMetricUpdated; public MicroProfileNodeMetricUpdater( Node node, + InternalDriverContext context, Set enabledMetrics, MetricRegistry registry, - DriverContext driverContext, Runnable signalMetricUpdated) { - super(enabledMetrics, registry); + super(context, enabledMetrics, registry); + this.node = node; this.signalMetricUpdated = signalMetricUpdated; - InternalDriverContext context = (InternalDriverContext) driverContext; - this.metricNamePrefix = buildPrefix(driverContext.getSessionName(), node.getEndPoint()); - DriverExecutionProfile config = driverContext.getConfig().getDefaultProfile(); + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); - if (enabledMetrics.contains(DefaultNodeMetric.OPEN_CONNECTIONS)) { - this.registry.register( - buildFullName(DefaultNodeMetric.OPEN_CONNECTIONS, null), - (Gauge) node::getOpenConnections); - } - initializePoolGauge( - DefaultNodeMetric.AVAILABLE_STREAMS, node, ChannelPool::getAvailableIds, context); - initializePoolGauge(DefaultNodeMetric.IN_FLIGHT, node, ChannelPool::getInFlight, context); - initializePoolGauge( - DefaultNodeMetric.ORPHANED_STREAMS, node, ChannelPool::getOrphanedIds, context); - initializeTimer(DefaultNodeMetric.CQL_MESSAGES, config); - initializeDefaultCounter(DefaultNodeMetric.UNSENT_REQUESTS, null); - initializeDefaultCounter(DefaultNodeMetric.ABORTED_REQUESTS, null); - initializeDefaultCounter(DefaultNodeMetric.WRITE_TIMEOUTS, null); - initializeDefaultCounter(DefaultNodeMetric.READ_TIMEOUTS, null); - initializeDefaultCounter(DefaultNodeMetric.UNAVAILABLES, null); - initializeDefaultCounter(DefaultNodeMetric.OTHER_ERRORS, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_ABORTED, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, null); - initializeDefaultCounter(DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_ABORTED, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_UNAVAILABLE, null); - initializeDefaultCounter(DefaultNodeMetric.IGNORES_ON_OTHER_ERROR, null); - initializeDefaultCounter(DefaultNodeMetric.SPECULATIVE_EXECUTIONS, null); - initializeDefaultCounter(DefaultNodeMetric.CONNECTION_INIT_ERRORS, null); - initializeDefaultCounter(DefaultNodeMetric.AUTHENTICATION_ERRORS, null); - initializeTimer(DseNodeMetric.GRAPH_MESSAGES, driverContext.getConfig().getDefaultProfile()); - } + initializeGauge(DefaultNodeMetric.OPEN_CONNECTIONS, profile, node::getOpenConnections); + initializeGauge(DefaultNodeMetric.AVAILABLE_STREAMS, profile, () -> availableStreamIds(node)); + initializeGauge(DefaultNodeMetric.IN_FLIGHT, profile, () -> inFlightRequests(node)); + initializeGauge(DefaultNodeMetric.ORPHANED_STREAMS, profile, () -> orphanedStreamIds(node)); - @Override - public String buildFullName(NodeMetric metric, String profileName) { - return metricNamePrefix + metric.getPath(); - } + initializeCounter(DefaultNodeMetric.UNSENT_REQUESTS, profile); + initializeCounter(DefaultNodeMetric.ABORTED_REQUESTS, profile); + initializeCounter(DefaultNodeMetric.WRITE_TIMEOUTS, profile); + initializeCounter(DefaultNodeMetric.READ_TIMEOUTS, profile); + initializeCounter(DefaultNodeMetric.UNAVAILABLES, profile); + initializeCounter(DefaultNodeMetric.OTHER_ERRORS, profile); + initializeCounter(DefaultNodeMetric.RETRIES, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_ABORTED, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_READ_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_WRITE_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_UNAVAILABLE, profile); + initializeCounter(DefaultNodeMetric.RETRIES_ON_OTHER_ERROR, profile); + initializeCounter(DefaultNodeMetric.IGNORES, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_ABORTED, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_WRITE_TIMEOUT, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_UNAVAILABLE, profile); + initializeCounter(DefaultNodeMetric.IGNORES_ON_OTHER_ERROR, profile); + initializeCounter(DefaultNodeMetric.SPECULATIVE_EXECUTIONS, profile); + initializeCounter(DefaultNodeMetric.CONNECTION_INIT_ERRORS, profile); + initializeCounter(DefaultNodeMetric.AUTHENTICATION_ERRORS, profile); - private String buildPrefix(String sessionName, EndPoint endPoint) { - return sessionName + ".nodes." + endPoint.asMetricPrefix() + "."; + initializeTimer(DefaultNodeMetric.CQL_MESSAGES, profile); + initializeTimer(DseNodeMetric.GRAPH_MESSAGES, profile); } @Override @@ -118,23 +104,17 @@ public void updateTimer(NodeMetric metric, String profileName, long duration, Ti super.updateTimer(metric, profileName, duration, unit); } - private void initializePoolGauge( - NodeMetric metric, - Node node, - Function reading, - InternalDriverContext context) { - if (enabledMetrics.contains(metric)) { - registry.register( - buildFullName(metric, null), - (Gauge) - () -> { - ChannelPool pool = context.getPoolManager().getPools().get(node); - return (pool == null) ? 0 : reading.apply(pool); - }); + public void cleanupNodeMetrics() { + for (NodeMetric metric : metrics.keySet()) { + MetricId id = getMetricId(metric); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + registry.remove(new MetricID(id.getName(), tags)); } + metrics.clear(); } - public void cleanupNodeMetrics() { - registry.removeMatching((id, metric) -> id.getName().startsWith(metricNamePrefix)); + @Override + protected MetricId getMetricId(NodeMetric metric) { + return context.getMetricIdGenerator().nodeMetricId(node, metric); } } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java index e46286b453c..7fddc8f150e 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java @@ -16,121 +16,43 @@ package com.datastax.oss.driver.internal.metrics.microprofile; import com.datastax.dse.driver.api.core.metrics.DseSessionMetric; -import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; -import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; -import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; +import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; -import com.datastax.oss.driver.internal.core.session.RequestProcessor; -import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; -import com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; -import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Set; -import org.eclipse.microprofile.metrics.Gauge; +import net.jcip.annotations.ThreadSafe; import org.eclipse.microprofile.metrics.MetricRegistry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@ThreadSafe public class MicroProfileSessionMetricUpdater extends MicroProfileMetricUpdater implements SessionMetricUpdater { - private static final Logger LOG = LoggerFactory.getLogger(MicroProfileSessionMetricUpdater.class); - - private final String metricNamePrefix; - public MicroProfileSessionMetricUpdater( - Set enabledMetrics, MetricRegistry registry, DriverContext driverContext) { - super(enabledMetrics, registry); - InternalDriverContext context = (InternalDriverContext) driverContext; - this.metricNamePrefix = driverContext.getSessionName() + "."; - if (enabledMetrics.contains(DefaultSessionMetric.CONNECTED_NODES)) { - this.registry.register( - buildFullName(DefaultSessionMetric.CONNECTED_NODES, null), - (Gauge) - () -> { - int count = 0; - for (Node node : context.getMetadataManager().getMetadata().getNodes().values()) { - if (node.getOpenConnections() > 0) { - count += 1; - } - } - return count; - }); - } - ; - if (enabledMetrics.contains(DefaultSessionMetric.THROTTLING_QUEUE_SIZE)) { - this.registry.register( - buildFullName(DefaultSessionMetric.THROTTLING_QUEUE_SIZE, null), - buildQueueGauge(context.getRequestThrottler(), context.getSessionName())); - } - if (enabledMetrics.contains(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE)) { - this.registry.register( - buildFullName(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, null), - createPreparedStatementsGauge(context)); - } - initializeTimer(DefaultSessionMetric.CQL_REQUESTS, context.getConfig().getDefaultProfile()); - initializeDefaultCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, null); - initializeTimer(DefaultSessionMetric.THROTTLING_DELAY, context.getConfig().getDefaultProfile()); - initializeDefaultCounter(DefaultSessionMetric.THROTTLING_ERRORS, null); - initializeTimer( - DseSessionMetric.CONTINUOUS_CQL_REQUESTS, context.getConfig().getDefaultProfile()); - initializeDefaultCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, null); - initializeTimer(DseSessionMetric.GRAPH_REQUESTS, context.getConfig().getDefaultProfile()); - } + InternalDriverContext context, Set enabledMetrics, MetricRegistry registry) { + super(context, enabledMetrics, registry); - private Gauge createPreparedStatementsGauge(InternalDriverContext context) { - Cache cache = getPreparedStatementCache(context); - Gauge gauge; - if (cache == null) { - LOG.warn( - "[{}] Metric {} is enabled in the config, " - + "but it looks like no CQL prepare processor is registered. " - + "The gauge will always return 0", - context.getSessionName(), - DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE.getPath()); - gauge = () -> 0L; - } else { - gauge = cache::size; - } - return gauge; - } + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); - @Override - public String buildFullName(SessionMetric metric, String profileName) { - return metricNamePrefix + metric.getPath(); - } + initializeGauge(DefaultSessionMetric.CONNECTED_NODES, profile, this::connectedNodes); + initializeGauge(DefaultSessionMetric.THROTTLING_QUEUE_SIZE, profile, this::throttlingQueueSize); + initializeGauge( + DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, profile, this::preparedStatementCacheSize); - private Gauge buildQueueGauge(RequestThrottler requestThrottler, String logPrefix) { - if (requestThrottler instanceof ConcurrencyLimitingRequestThrottler) { - return ((ConcurrencyLimitingRequestThrottler) requestThrottler)::getQueueSize; - } else if (requestThrottler instanceof RateLimitingRequestThrottler) { - return ((RateLimitingRequestThrottler) requestThrottler)::getQueueSize; - } else { - LOG.warn( - "[{}] Metric {} does not support {}, it will always return 0", - logPrefix, - DefaultSessionMetric.THROTTLING_QUEUE_SIZE.getPath(), - requestThrottler.getClass().getName()); - return () -> 0; - } + initializeTimer(DefaultSessionMetric.CQL_REQUESTS, profile); + initializeTimer(DefaultSessionMetric.THROTTLING_DELAY, profile); + initializeTimer(DseSessionMetric.CONTINUOUS_CQL_REQUESTS, profile); + initializeTimer(DseSessionMetric.GRAPH_REQUESTS, profile); + + initializeCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, profile); + initializeCounter(DefaultSessionMetric.THROTTLING_ERRORS, profile); + initializeCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, profile); } - @Nullable - private static Cache getPreparedStatementCache(InternalDriverContext context) { - // By default, both the sync processor and the async one are registered and they share the same - // cache. But with a custom processor registry, there could be only one of the two present. - for (RequestProcessor processor : context.getRequestProcessorRegistry().getProcessors()) { - if (processor instanceof CqlPrepareAsyncProcessor) { - return ((CqlPrepareAsyncProcessor) processor).getCache(); - } else if (processor instanceof CqlPrepareSyncProcessor) { - return ((CqlPrepareSyncProcessor) processor).getCache(); - } - } - return null; + @Override + protected MetricId getMetricId(SessionMetric metric) { + return context.getMetricIdGenerator().sessionMetricId(metric); } } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileTags.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileTags.java new file mode 100644 index 00000000000..fe87ee7c3e6 --- /dev/null +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileTags.java @@ -0,0 +1,33 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.metrics.microprofile; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.eclipse.microprofile.metrics.Tag; + +public class MicroProfileTags { + + public static Tag[] toMicroProfileTags(Map tags) { + List micrometerTags = new ArrayList<>(tags.size()); + for (Entry entry : tags.entrySet()) { + micrometerTags.add(new Tag(entry.getKey(), entry.getValue())); + } + return micrometerTags.toArray(new Tag[0]); + } +} diff --git a/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java b/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java index 453bf281284..e8a00c2dc8c 100644 --- a/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java +++ b/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java @@ -34,7 +34,7 @@ import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.time.Duration; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.eclipse.microprofile.metrics.MetricRegistry; import org.junit.Test; @@ -104,8 +104,8 @@ public void should_throw_if_wrong_or_missing_registry_type( InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); DriverConfig config = mock(DriverConfig.class); - Duration expireAfter = LOWEST_ACCEPTABLE_EXPIRE_AFTER.minusMinutes(1); - List enabledMetrics = Arrays.asList(DefaultSessionMetric.CQL_REQUESTS.getPath()); + List enabledMetrics = + Collections.singletonList(DefaultSessionMetric.CQL_REQUESTS.getPath()); // when when(config.getDefaultProfile()).thenReturn(profile); when(context.getConfig()).thenReturn(config); @@ -113,14 +113,14 @@ public void should_throw_if_wrong_or_missing_registry_type( // registry object is not a registry type when(context.getMetricRegistry()).thenReturn(registryObj); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); + .thenReturn(LOWEST_ACCEPTABLE_EXPIRE_AFTER); when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) .thenReturn(enabledMetrics); // then try { new MicroProfileMetricsFactory(context); fail( - "MetricsFactory should require correct registy object type: " + "MetricsFactory should require correct registry object type: " + MetricRegistry.class.getName()); } catch (IllegalArgumentException iae) { assertThat(iae.getMessage()).isEqualTo(expectedMsg); diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 54d1e86c6a7..55166b5b60b 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -11,6 +11,19 @@ been promoted from beta to production-ready in the upcoming Cassandra 4.0 releas Users should not experience any disruption. When connecting to Cassandra 4.0, V5 will be transparently selected as the protocol version to use. +#### Customizable metric names, support for metric tags + +[JAVA-2872](https://datastax-oss.atlassian.net/browse/JAVA-2872) introduced the ability to configure +how metric identifiers are generated. Metric names can now be configured, but most importantly, +metric tags are now supported. See the [metrics](../manual/core/metrics/) section of the online +manual, or the `advanced.metrics.id-generator` section in the +[reference.conf](../manual/core/configuration/reference/) file for details. + +Users should not experience any disruption. However, those using metrics libraries that support tags +are encouraged to try out the new `TaggingMetricIdGenerator`, as it generates metric names and tags +that will look more familiar to users of libraries such as Micrometer or MicroProfile Metrics (and +look nicer when exported to Prometheus or Graphite). + ### 4.10.0 #### Cross-datacenter failover From 9251657c8e0acc37a2d960c6e0fe7c8c664e6ca5 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 19 Mar 2021 19:12:23 +0100 Subject: [PATCH 082/395] JAVA-2928: Generate counter increment/decrement constructs compatible with legacy C* versions (#1538) --- changelog/README.md | 2 + .../api/querybuilder/update/Assignment.java | 15 +++--- .../update/CounterAssignment.java | 53 +++++++++++++++++-- .../update/DecrementAssignment.java | 29 ++++++++++ .../update/IncrementAssignment.java | 29 ++++++++++ .../update/UpdateFluentAssignmentTest.java | 12 ++--- .../update/UpdateIdempotenceTest.java | 4 +- 7 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/DecrementAssignment.java create mode 100644 query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/IncrementAssignment.java diff --git a/changelog/README.md b/changelog/README.md index 2d3d1d0c280..57b7d637d08 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,8 @@ ### 4.11.0 (in progress) +- [bug] JAVA-2928: Generate counter increment/decrement constructs compatible with legacy C* + versions - [new feature] JAVA-2872: Ability to customize metric names and tags - [bug] JAVA-2925: Consider protocol version unsupported when server requires USE_BETA flag for it - [improvement] JAVA-2704: Remove protocol v5 beta status, add v6-beta diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/update/Assignment.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/update/Assignment.java index f2590766767..a05d48ceebd 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/update/Assignment.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/update/Assignment.java @@ -28,8 +28,9 @@ import com.datastax.oss.driver.internal.querybuilder.update.AppendListElementAssignment; import com.datastax.oss.driver.internal.querybuilder.update.AppendMapEntryAssignment; import com.datastax.oss.driver.internal.querybuilder.update.AppendSetElementAssignment; -import com.datastax.oss.driver.internal.querybuilder.update.CounterAssignment; +import com.datastax.oss.driver.internal.querybuilder.update.DecrementAssignment; import com.datastax.oss.driver.internal.querybuilder.update.DefaultAssignment; +import com.datastax.oss.driver.internal.querybuilder.update.IncrementAssignment; import com.datastax.oss.driver.internal.querybuilder.update.PrependAssignment; import com.datastax.oss.driver.internal.querybuilder.update.PrependListElementAssignment; import com.datastax.oss.driver.internal.querybuilder.update.PrependMapEntryAssignment; @@ -109,10 +110,10 @@ static Assignment setListValue( return setListValue(CqlIdentifier.fromCql(columnName), index, value); } - /** Increments a counter, as in {@code SET c+=?}. */ + /** Increments a counter, as in {@code SET c=c+?}. */ @NonNull static Assignment increment(@NonNull CqlIdentifier columnId, @NonNull Term amount) { - return new CounterAssignment(new ColumnLeftOperand(columnId), "+=", amount); + return new IncrementAssignment(columnId, amount); } /** @@ -124,7 +125,7 @@ static Assignment increment(@NonNull String columnName, @NonNull Term amount) { return increment(CqlIdentifier.fromCql(columnName), amount); } - /** Increments a counter by 1, as in {@code SET c+=1} . */ + /** Increments a counter by 1, as in {@code SET c=c+1} . */ @NonNull static Assignment increment(@NonNull CqlIdentifier columnId) { return increment(columnId, QueryBuilder.literal(1)); @@ -136,10 +137,10 @@ static Assignment increment(@NonNull String columnName) { return increment(CqlIdentifier.fromCql(columnName)); } - /** Decrements a counter, as in {@code SET c-=?}. */ + /** Decrements a counter, as in {@code SET c=c-?}. */ @NonNull static Assignment decrement(@NonNull CqlIdentifier columnId, @NonNull Term amount) { - return new CounterAssignment(new ColumnLeftOperand(columnId), "-=", amount); + return new DecrementAssignment(columnId, amount); } /** @@ -151,7 +152,7 @@ static Assignment decrement(@NonNull String columnName, @NonNull Term amount) { return decrement(CqlIdentifier.fromCql(columnName), amount); } - /** Decrements a counter by 1, as in {@code SET c-=1} . */ + /** Decrements a counter by 1, as in {@code SET c=c-1} . */ @NonNull static Assignment decrement(@NonNull CqlIdentifier columnId) { return decrement(columnId, QueryBuilder.literal(1)); diff --git a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/CounterAssignment.java b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/CounterAssignment.java index ff1280de5dd..99c30e134fa 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/CounterAssignment.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/CounterAssignment.java @@ -15,21 +15,64 @@ */ package com.datastax.oss.driver.internal.querybuilder.update; +import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.querybuilder.term.Term; -import com.datastax.oss.driver.internal.querybuilder.lhs.LeftOperand; +import com.datastax.oss.driver.api.querybuilder.update.Assignment; +import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import edu.umd.cs.findbugs.annotations.NonNull; import net.jcip.annotations.Immutable; @Immutable -public class CounterAssignment extends DefaultAssignment { +public abstract class CounterAssignment implements Assignment { - public CounterAssignment( - @NonNull LeftOperand leftOperand, @NonNull String operator, @NonNull Term rightOperand) { - super(leftOperand, operator, rightOperand); + public enum Operator { + INCREMENT("%1$s=%1$s+%2$s"), + DECREMENT("%1$s=%1$s-%2$s"), + ; + + public final String pattern; + + Operator(String pattern) { + this.pattern = pattern; + } + } + + private final CqlIdentifier columnId; + private final Operator operator; + private final Term value; + + protected CounterAssignment( + @NonNull CqlIdentifier columnId, @NonNull Operator operator, @NonNull Term value) { + Preconditions.checkNotNull(columnId); + Preconditions.checkNotNull(value); + this.columnId = columnId; + this.operator = operator; + this.value = value; + } + + @Override + public void appendTo(@NonNull StringBuilder builder) { + builder.append(String.format(operator.pattern, columnId.asCql(true), buildRightOperand())); + } + + private String buildRightOperand() { + StringBuilder builder = new StringBuilder(); + value.appendTo(builder); + return builder.toString(); } @Override public boolean isIdempotent() { return false; } + + @NonNull + public CqlIdentifier getColumnId() { + return columnId; + } + + @NonNull + public Term getValue() { + return value; + } } diff --git a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/DecrementAssignment.java b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/DecrementAssignment.java new file mode 100644 index 00000000000..e91c6b2dbd1 --- /dev/null +++ b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/DecrementAssignment.java @@ -0,0 +1,29 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.querybuilder.update; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.querybuilder.term.Term; +import edu.umd.cs.findbugs.annotations.NonNull; +import net.jcip.annotations.Immutable; + +@Immutable +public class DecrementAssignment extends CounterAssignment { + + public DecrementAssignment(@NonNull CqlIdentifier columnId, @NonNull Term value) { + super(columnId, Operator.DECREMENT, value); + } +} diff --git a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/IncrementAssignment.java b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/IncrementAssignment.java new file mode 100644 index 00000000000..8c5bf6b40bb --- /dev/null +++ b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/update/IncrementAssignment.java @@ -0,0 +1,29 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.querybuilder.update; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.querybuilder.term.Term; +import edu.umd.cs.findbugs.annotations.NonNull; +import net.jcip.annotations.Immutable; + +@Immutable +public class IncrementAssignment extends CounterAssignment { + + public IncrementAssignment(@NonNull CqlIdentifier columnId, @NonNull Term value) { + super(columnId, Operator.INCREMENT, value); + } +} diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateFluentAssignmentTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateFluentAssignmentTest.java index 77cf9ed00ca..ad68d04b3ea 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateFluentAssignmentTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateFluentAssignmentTest.java @@ -73,18 +73,18 @@ public void should_generate_list_value_assignment() { @Test public void should_generate_counter_operations() { assertThat(update("foo").increment("c").whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c+=1 WHERE k=?"); + .hasCql("UPDATE foo SET c=c+1 WHERE k=?"); assertThat(update("foo").increment("c", literal(2)).whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c+=2 WHERE k=?"); + .hasCql("UPDATE foo SET c=c+2 WHERE k=?"); assertThat(update("foo").increment("c", bindMarker()).whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c+=? WHERE k=?"); + .hasCql("UPDATE foo SET c=c+? WHERE k=?"); assertThat(update("foo").decrement("c").whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c-=1 WHERE k=?"); + .hasCql("UPDATE foo SET c=c-1 WHERE k=?"); assertThat(update("foo").decrement("c", literal(2)).whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c-=2 WHERE k=?"); + .hasCql("UPDATE foo SET c=c-2 WHERE k=?"); assertThat(update("foo").decrement("c", bindMarker()).whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c-=? WHERE k=?"); + .hasCql("UPDATE foo SET c=c-? WHERE k=?"); } @Test diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateIdempotenceTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateIdempotenceTest.java index 1a3b05614ea..fb48b5deca8 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateIdempotenceTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/update/UpdateIdempotenceTest.java @@ -90,10 +90,10 @@ public void should_not_be_idempotent_if_using_non_idempotent_term_in_relation() @Test public void should_not_be_idempotent_if_updating_counter() { assertThat(update("foo").increment("c").whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c+=1 WHERE k=?") + .hasCql("UPDATE foo SET c=c+1 WHERE k=?") .isNotIdempotent(); assertThat(update("foo").decrement("c").whereColumn("k").isEqualTo(bindMarker())) - .hasCql("UPDATE foo SET c-=1 WHERE k=?") + .hasCql("UPDATE foo SET c=c-1 WHERE k=?") .isNotIdempotent(); } From ad278f5091c2a8f64693a0a6f6ddf99a8ef004af Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 19 Mar 2021 19:15:01 +0100 Subject: [PATCH 083/395] JAVA-2830: Add mapper support for Java streams (#1539) --- changelog/README.md | 1 + .../oss/driver/mapper/GetEntityIT.java | 12 ++++++ .../oss/driver/mapper/QueryProviderIT.java | 20 +++++++++ .../oss/driver/mapper/QueryReturnTypesIT.java | 10 +++++ .../datastax/oss/driver/mapper/SelectIT.java | 43 +++++++++++++++++++ manual/mapper/daos/getentity/README.md | 17 +++++++- manual/mapper/daos/query/README.md | 5 +++ manual/mapper/daos/select/README.md | 15 +++++++ .../dao/DaoGetEntityMethodGenerator.java | 32 ++++++++++++-- .../dao/DaoSelectMethodGenerator.java | 2 + .../dao/DefaultDaoReturnTypeKind.java | 20 +++++++++ .../dao/DefaultDaoReturnTypeParser.java | 2 + .../dao/DaoGetEntityMethodGeneratorTest.java | 18 ++++++-- .../dao/DaoQueryMethodGeneratorTest.java | 2 +- .../dao/DaoSelectMethodGeneratorTest.java | 4 +- .../oss/driver/internal/mapper/DaoBase.java | 7 +++ 16 files changed, 199 insertions(+), 11 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 57b7d637d08..bedafa80225 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [new feature] JAVA-2830: Add mapper support for Java streams - [bug] JAVA-2928: Generate counter increment/decrement constructs compatible with legacy C* versions - [new feature] JAVA-2872: Ability to customize metric names and tags diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java index dd789a70925..2ca29a688a9 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java @@ -38,6 +38,7 @@ import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; import com.datastax.oss.driver.shaded.guava.common.collect.Sets; +import java.util.stream.Stream; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -116,6 +117,14 @@ public void should_get_iterable_from_result_set() { assertThat(Sets.newHashSet(products)).containsOnly(FLAMETHROWER, MP3_DOWNLOAD); } + @Test + public void should_get_stream_from_result_set() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = session.execute("SELECT * FROM product"); + Stream products = dao.getAsStream(rs); + assertThat(products).containsOnly(FLAMETHROWER, MP3_DOWNLOAD); + } + @Test public void should_get_async_iterable_from_async_result_set() { CqlSession session = SESSION_RULE.session(); @@ -141,6 +150,9 @@ public interface ProductDao { @GetEntity PagingIterable get(ResultSet resultSet); + @GetEntity + Stream getAsStream(ResultSet resultSet); + @GetEntity MappedAsyncPagingIterable get(AsyncResultSet resultSet); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java index 6cb5c37f2ac..1fb92637b22 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java @@ -43,6 +43,8 @@ import com.datastax.oss.driver.categories.ParallelizableTests; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -115,9 +117,15 @@ public interface SensorMapper { @Dao @DefaultNullSavingStrategy(NullSavingStrategy.SET_TO_NULL) public interface SensorDao { + @QueryProvider(providerClass = FindSliceProvider.class, entityHelpers = SensorReading.class) PagingIterable findSlice(int id, Integer month, Integer day); + @QueryProvider( + providerClass = FindSliceStreamProvider.class, + entityHelpers = SensorReading.class) + Stream findSliceAsStream(int id, Integer month, Integer day); + @Insert void save(SensorReading reading); } @@ -164,6 +172,18 @@ public PagingIterable findSlice(int id, Integer month, Integer da } } + public static class FindSliceStreamProvider extends FindSliceProvider { + + public FindSliceStreamProvider( + MapperContext context, EntityHelper sensorReadingHelper) { + super(context, sensorReadingHelper); + } + + public Stream findSliceAsStream(int id, Integer month, Integer day) { + return StreamSupport.stream(findSlice(id, month, day).spliterator(), false); + } + } + @Entity public static class SensorReading { @PartitionKey private int id; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java index 716b35faebc..8002bf19f6a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java @@ -47,6 +47,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.stream.Stream; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -224,6 +225,12 @@ public void should_execute_query_and_map_to_iterable() { assertThat(iterable.all()).hasSize(10); } + @Test + public void should_execute_query_and_map_to_stream() { + Stream stream = dao.findByIdAsStream(1); + assertThat(stream).hasSize(10); + } + @Test public void should_execute_async_query_and_map_to_iterable() { MappedAsyncPagingIterable iterable = @@ -288,6 +295,9 @@ public interface TestDao { @Query("SELECT * FROM ${qualifiedTableId} WHERE id = :id") PagingIterable findById(int id); + @Query("SELECT * FROM ${qualifiedTableId} WHERE id = :id") + Stream findByIdAsStream(int id); + @Query("SELECT * FROM ${qualifiedTableId} WHERE id = :id") CompletableFuture> findByIdAsync(int id); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java index e47b86f74f3..2dda4b7e63a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java @@ -35,6 +35,7 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletionStage; +import java.util.stream.Stream; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -99,6 +100,11 @@ public void should_select_all() { assertThat(dao.all().all()).hasSize(2); } + @Test + public void should_select_all_stream() { + assertThat(dao.stream()).hasSize(2); + } + @Test public void should_select_by_primary_key_asynchronously() { assertThat(CompletableFutures.getUninterruptibly(dao.findByIdAsync(FLAMETHROWER.getId()))) @@ -141,6 +147,18 @@ public void should_select_all_sales() { MP3_DOWNLOAD_SALE_1); } + @Test + public void should_select_all_sales_stream() { + assertThat(saleDao.stream()) + .containsOnly( + FLAMETHROWER_SALE_1, + FLAMETHROWER_SALE_3, + FLAMETHROWER_SALE_4, + FLAMETHROWER_SALE_2, + FLAMETHROWER_SALE_5, + MP3_DOWNLOAD_SALE_1); + } + @Test public void should_select_by_partition_key() { assertThat(saleDao.salesByIdForDay(FLAMETHROWER.getId(), DATE_1).all()) @@ -148,12 +166,25 @@ public void should_select_by_partition_key() { FLAMETHROWER_SALE_1, FLAMETHROWER_SALE_3, FLAMETHROWER_SALE_2, FLAMETHROWER_SALE_4); } + @Test + public void should_select_by_partition_key_stream() { + assertThat(saleDao.salesByIdForDayStream(FLAMETHROWER.getId(), DATE_1)) + .containsOnly( + FLAMETHROWER_SALE_1, FLAMETHROWER_SALE_3, FLAMETHROWER_SALE_2, FLAMETHROWER_SALE_4); + } + @Test public void should_select_by_partition_key_and_partial_clustering() { assertThat(saleDao.salesByIdForCustomer(FLAMETHROWER.getId(), DATE_1, 1).all()) .containsOnly(FLAMETHROWER_SALE_1, FLAMETHROWER_SALE_3, FLAMETHROWER_SALE_4); } + @Test + public void should_select_by_partition_key_and_partial_clustering_stream() { + assertThat(saleDao.salesByIdForCustomerStream(FLAMETHROWER.getId(), DATE_1, 1)) + .containsOnly(FLAMETHROWER_SALE_1, FLAMETHROWER_SALE_3, FLAMETHROWER_SALE_4); + } + @Test public void should_select_by_primary_key_sales() { assertThat( @@ -180,6 +211,9 @@ public interface ProductDao { @Select PagingIterable all(); + @Select + Stream stream(); + @Select Optional findOptionalById(UUID productId); @@ -203,14 +237,23 @@ public interface ProductSaleDao { @Select PagingIterable all(); + @Select + Stream stream(); + // partition key provided @Select PagingIterable salesByIdForDay(UUID id, String day); + @Select + Stream salesByIdForDayStream(UUID id, String day); + // partition key and partial clustering key @Select PagingIterable salesByIdForCustomer(UUID id, String day, int customerId); + @Select + Stream salesByIdForCustomerStream(UUID id, String day, int customerId); + // full primary key @Select ProductSale salesByIdForCustomerAtTime(UUID id, String day, int customerId, UUID ts); diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index 87ab6f7f826..6eff3b1e88b 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -56,7 +56,20 @@ The method can return: @GetEntity PagingIterable asProducts(ResultSet resultSet); ``` - + +* a [Stream] of an entity class. In that case, the type of the parameter **must** be [ResultSet]. + Each row in the result set will be converted into an entity instance. + + Note: even if streams are lazily evaluated, results are fetched synchronously; therefore, as the + returned stream is traversed, blocking calls may occur, as more results are fetched from the + server in the background. For details about the stream's characteristics, see + [PagingIterable.spliterator]. + + ```java + @GetEntity + Stream asProducts(ResultSet resultSet); + ``` + * a [MappedAsyncPagingIterable] of an entity class. In that case, the type of the parameter **must** be [AsyncResultSet]. Each row in the result set will be converted into an entity instance. @@ -74,10 +87,12 @@ If the return type doesn't match the parameter type (for example [PagingIterable [GettableByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/GettableByName.html [MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html [PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- [ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html [Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html [UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html +[Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index e019ce9c5e8..81ac435b9cd 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -59,6 +59,9 @@ The method can return: * a [PagingIterable]. The method will convert each row into an entity instance. +* a [Stream]. The method will convert each row into an entity instance. For details about the + stream's characteristics, see [PagingIterable.spliterator]. + * a [CompletionStage] or [CompletableFuture] of any of the above. The method will execute the query asynchronously. Note that for result sets and iterables, you need to switch to the asynchronous equivalent [AsyncResultSet] and [MappedAsyncPagingIterable] respectively. @@ -117,6 +120,7 @@ Then: [ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- [MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html [PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- [Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html [BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html [ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html @@ -125,3 +129,4 @@ Then: [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html [Optional]: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html +[Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index d31c1ce9faa..1b00ae17438 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -108,6 +108,19 @@ In all cases, the method can return: PagingIterable findByDescription(String searchString); ``` +* a [Stream] of the entity class. It behaves like a result set, except that each element is a mapped + entity instead of a row. + + Note: even if streams are lazily evaluated, the query will be executed synchronously; also, as + the returned stream is traversed, more blocking calls may occur, as more results are fetched + from the server in the background. For details about the stream's characteristics, see + [PagingIterable.spliterator]. + + ```java + @Select(customWhereClause = "description LIKE :searchString") + Stream findByDescription(String searchString); + ``` + * a [CompletionStage] or [CompletableFuture] of any of the above. The method will execute the query asynchronously. Note that for iterables, you need to switch to the asynchronous equivalent [MappedAsyncPagingIterable]. @@ -154,8 +167,10 @@ entity class and the [naming strategy](../../entities/#naming-strategy)). [perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- [MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html [PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- [MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html [Optional]: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html +[Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java index 03fd61008f5..1d4d52fe940 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java @@ -29,6 +29,8 @@ import com.squareup.javapoet.MethodSpec; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; @@ -48,6 +50,8 @@ private enum Transformation { ONE, /** Iterable of rows to iterable of entity. */ MAP, + /** Iterable of rows to stream of entity. */ + STREAM, } public DaoGetEntityMethodGenerator( @@ -106,7 +110,7 @@ public Optional generate() { .getMessager() .error( methodElement, - "Invalid return type: %s methods must return %s if the argument is %s", + "Invalid return type: %s methods returning %s must have an argument of type %s", GetEntity.class.getSimpleName(), PagingIterable.class.getSimpleName(), ResultSet.class.getSimpleName()); @@ -114,13 +118,27 @@ public Optional generate() { } entityElement = EntityUtils.typeArgumentAsEntityElement(returnType, typeParameters); transformation = Transformation.MAP; + } else if (context.getClassUtils().isSame(element, Stream.class)) { + if (!parameterIsResultSet) { + context + .getMessager() + .error( + methodElement, + "Invalid return type: %s methods returning %s must have an argument of type %s", + GetEntity.class.getSimpleName(), + Stream.class.getSimpleName(), + ResultSet.class.getSimpleName()); + return Optional.empty(); + } + entityElement = EntityUtils.typeArgumentAsEntityElement(returnType, typeParameters); + transformation = Transformation.STREAM; } else if (context.getClassUtils().isSame(element, MappedAsyncPagingIterable.class)) { if (!parameterIsAsyncResultSet) { context .getMessager() .error( methodElement, - "Invalid return type: %s methods must return %s if the argument is %s", + "Invalid return type: %s methods returning %s must have an argument of type %s", GetEntity.class.getSimpleName(), MappedAsyncPagingIterable.class.getSimpleName(), AsyncResultSet.class.getSimpleName()); @@ -136,10 +154,11 @@ public Optional generate() { .error( methodElement, "Invalid return type: " - + "%s methods must return a %s-annotated class, or a %s or %s thereof", + + "%s methods must return a %s-annotated class, or a %s, a %s or %s thereof", GetEntity.class.getSimpleName(), Entity.class.getSimpleName(), PagingIterable.class.getSimpleName(), + Stream.class.getSimpleName(), MappedAsyncPagingIterable.class.getSimpleName()); return Optional.empty(); } @@ -162,6 +181,13 @@ public Optional generate() { overridingMethodBuilder.addStatement( "return $L.map($L::get)", parameterName, helperFieldName); break; + case STREAM: + overridingMethodBuilder.addStatement( + "return $T.stream($L.map($L::get).spliterator(), false)", + StreamSupport.class, + parameterName, + helperFieldName); + break; } return Optional.of(overridingMethodBuilder.build()); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java index d29f8e68099..8c8878b133b 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java @@ -23,6 +23,7 @@ import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.MAPPED_REACTIVE_RESULT_SET; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.OPTIONAL_ENTITY; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.PAGING_ITERABLE; +import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.STREAM; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; @@ -68,6 +69,7 @@ protected Set getSupportedReturnTypes() { FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, + STREAM, FUTURE_OF_ASYNC_PAGING_ITERABLE, MAPPED_REACTIVE_RESULT_SET, CUSTOM); diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java index e4501f06ef3..41c841cd2e7 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java @@ -455,6 +455,26 @@ public CodeBlock wrapWithErrorHandling( throw new AssertionError("Should never get here"); } }, + + STREAM { + @Override + public void addExecuteStatement( + CodeBlock.Builder methodBuilder, + String helperFieldName, + ExecutableElement methodElement, + Map typeParameters) { + methodBuilder.addStatement( + "return executeAndMapToEntityStream(boundStatement, $L)", helperFieldName); + } + + @Override + public CodeBlock wrapWithErrorHandling( + CodeBlock innerBlock, + ExecutableElement methodElement, + Map typeParameters) { + return innerBlock; + } + }, ; @Override diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java index 25f71c4bda6..5d7c18c63cf 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java @@ -32,6 +32,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.stream.Stream; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Name; @@ -75,6 +76,7 @@ public class DefaultDaoReturnTypeParser implements DaoReturnTypeParser { .put(CompletionStage.class, DefaultDaoReturnTypeKind.FUTURE_OF_ENTITY) .put(CompletableFuture.class, DefaultDaoReturnTypeKind.FUTURE_OF_ENTITY) .put(PagingIterable.class, DefaultDaoReturnTypeKind.PAGING_ITERABLE) + .put(Stream.class, DefaultDaoReturnTypeKind.STREAM) .put(MappedReactiveResultSet.class, DefaultDaoReturnTypeKind.MAPPED_REACTIVE_RESULT_SET) .build(); diff --git a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGeneratorTest.java b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGeneratorTest.java index 01a08149893..cf7591c1020 100644 --- a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGeneratorTest.java +++ b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGeneratorTest.java @@ -27,6 +27,7 @@ import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.stream.Stream; import javax.lang.model.element.Modifier; import org.junit.Test; import org.junit.runner.RunWith; @@ -69,7 +70,7 @@ public static Object[][] invalidSignatures() { .build(), }, { - "Invalid return type: GetEntity methods must return a Entity-annotated class, or a PagingIterable or MappedAsyncPagingIterable thereof", + "Invalid return type: GetEntity methods must return a Entity-annotated class, or a PagingIterable, a Stream or MappedAsyncPagingIterable thereof", MethodSpec.methodBuilder("get") .addAnnotation(GetEntity.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) @@ -77,7 +78,7 @@ public static Object[][] invalidSignatures() { .build(), }, { - "Invalid return type: GetEntity methods must return a Entity-annotated class, or a PagingIterable or MappedAsyncPagingIterable thereof", + "Invalid return type: GetEntity methods must return a Entity-annotated class, or a PagingIterable, a Stream or MappedAsyncPagingIterable thereof", MethodSpec.methodBuilder("get") .addAnnotation(GetEntity.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) @@ -86,7 +87,7 @@ public static Object[][] invalidSignatures() { .build(), }, { - "Invalid return type: GetEntity methods must return PagingIterable if the argument is ResultSet", + "Invalid return type: GetEntity methods returning PagingIterable must have an argument of type ResultSet", MethodSpec.methodBuilder("get") .addAnnotation(GetEntity.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) @@ -96,7 +97,16 @@ public static Object[][] invalidSignatures() { .build(), }, { - "Invalid return type: GetEntity methods must return MappedAsyncPagingIterable if the argument is AsyncResultSet", + "Invalid return type: GetEntity methods returning Stream must have an argument of type ResultSet", + MethodSpec.methodBuilder("get") + .addAnnotation(GetEntity.class) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addParameter(ParameterSpec.builder(Row.class, "source").build()) + .returns(ParameterizedTypeName.get(ClassName.get(Stream.class), ENTITY_CLASS_NAME)) + .build(), + }, + { + "Invalid return type: GetEntity methods returning MappedAsyncPagingIterable must have an argument of type AsyncResultSet", MethodSpec.methodBuilder("get") .addAnnotation(GetEntity.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) diff --git a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java index 882d8fd26e6..ea0f28badce 100644 --- a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java +++ b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java @@ -45,7 +45,7 @@ public static Object[][] invalidSignatures() { + "ENTITY, OPTIONAL_ENTITY, RESULT_SET, BOUND_STATEMENT, PAGING_ITERABLE, FUTURE_OF_VOID, " + "FUTURE_OF_BOOLEAN, FUTURE_OF_LONG, FUTURE_OF_ROW, FUTURE_OF_ENTITY, " + "FUTURE_OF_OPTIONAL_ENTITY, FUTURE_OF_ASYNC_RESULT_SET, " - + "FUTURE_OF_ASYNC_PAGING_ITERABLE, REACTIVE_RESULT_SET, MAPPED_REACTIVE_RESULT_SET]", + + "FUTURE_OF_ASYNC_PAGING_ITERABLE, REACTIVE_RESULT_SET, MAPPED_REACTIVE_RESULT_SET, STREAM]", MethodSpec.methodBuilder("select") .addAnnotation( AnnotationSpec.builder(Query.class) diff --git a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java index 01e2f6aa9dd..c133d19e41a 100644 --- a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java +++ b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java @@ -41,7 +41,7 @@ public static Object[][] invalidSignatures() { return new Object[][] { { "Invalid return type: Select methods must return one of [ENTITY, OPTIONAL_ENTITY, " - + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, " + + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, STREAM, " + "FUTURE_OF_ASYNC_PAGING_ITERABLE, MAPPED_REACTIVE_RESULT_SET]", MethodSpec.methodBuilder("select") .addAnnotation(Select.class) @@ -51,7 +51,7 @@ public static Object[][] invalidSignatures() { }, { "Invalid return type: Select methods must return one of [ENTITY, OPTIONAL_ENTITY, " - + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, " + + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, STREAM, " + "FUTURE_OF_ASYNC_PAGING_ITERABLE, MAPPED_REACTIVE_RESULT_SET]", MethodSpec.methodBuilder("select") .addAnnotation(Select.class) diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java index 27539ce0482..4af39a59b84 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java @@ -40,6 +40,8 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** Base class for generated implementations of {@link Dao}-annotated interfaces. */ public class DaoBase { @@ -240,6 +242,11 @@ protected PagingIterable executeAndMapToEntityIterable( return execute(statement).map(entityHelper::get); } + protected Stream executeAndMapToEntityStream( + Statement statement, EntityHelper entityHelper) { + return StreamSupport.stream(execute(statement).map(entityHelper::get).spliterator(), false); + } + protected CompletableFuture executeAsync(Statement statement) { CompletionStage stage = context.getSession().executeAsync(statement); // We allow DAO interfaces to return CompletableFuture instead of CompletionStage. This method From 02da73841c4aaefa8daa76fcd871d1203f322f69 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 19 Mar 2021 19:35:57 +0100 Subject: [PATCH 084/395] JAVA-2929: Revisit node-level metric eviction (#1541) --- changelog/README.md | 1 + .../core/metrics/AbstractMetricUpdater.java | 67 ++++- .../core/metrics/DropwizardMetricUpdater.java | 13 +- .../metrics/DropwizardMetricsFactory.java | 94 +++---- .../metrics/DropwizardNodeMetricUpdater.java | 47 +--- .../metrics/DropwizardMetricsFactoryTest.java | 73 +---- .../DropwizardNodeMetricUpdaterTest.java | 160 +++++++++++ .../core/metrics/DropwizardMetricsIT.java | 216 ++++++++++++++ .../oss/driver/core/metrics/FakeTicker.java | 40 --- .../oss/driver/core/metrics/MetricsIT.java | 133 --------- .../driver/core/metrics/MetricsITBase.java | 263 ++++++++++++++++++ .../core/metrics/MetricsSimulacronIT.java | 206 -------------- .../common/AbstractMetricsTestBase.java | 229 --------------- .../micrometer/MicrometerMetricsIT.java | 89 +++--- .../microprofile/MicroProfileMetricsIT.java | 115 +++----- .../micrometer/MicrometerMetricUpdater.java | 9 + .../micrometer/MicrometerMetricsFactory.java | 83 ++---- .../MicrometerNodeMetricUpdater.java | 40 +-- .../MicrometerMetricsFactoryTest.java | 91 +----- .../MicrometerNodeMetricUpdaterTest.java | 150 ++++++++++ metrics/microprofile/pom.xml | 5 + .../MicroProfileMetricUpdater.java | 12 + .../MicroProfileMetricsFactory.java | 85 +++--- .../MicroProfileNodeMetricUpdater.java | 43 +-- .../MicroProfileSessionMetricUpdater.java | 8 +- .../MicroProfileMetricsFactoryTest.java | 62 +---- .../MicroProfileNodeMetricsUpdaterTest.java | 152 ++++++++++ 27 files changed, 1248 insertions(+), 1238 deletions(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdaterTest.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java delete mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/FakeTicker.java delete mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsIT.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java delete mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsSimulacronIT.java delete mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java create mode 100644 metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java create mode 100644 metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricsUpdaterTest.java diff --git a/changelog/README.md b/changelog/README.md index bedafa80225..707ec720e58 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [improvement] JAVA-2929: Revisit node-level metric eviction - [new feature] JAVA-2830: Add mapper support for Java streams - [bug] JAVA-2928: Generate counter increment/decrement constructs compatible with legacy C* versions diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java index 04fdc2c58bc..53f704bfb98 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java @@ -15,6 +15,8 @@ */ package com.datastax.oss.driver.internal.core.metrics; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; @@ -27,7 +29,11 @@ import com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler; import com.datastax.oss.driver.shaded.guava.common.cache.Cache; import edu.umd.cs.findbugs.annotations.Nullable; +import io.netty.util.Timeout; +import java.time.Duration; import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,12 +41,30 @@ public abstract class AbstractMetricUpdater implements MetricUpdater enabledMetrics; + private final AtomicReference metricsExpirationTimeoutRef = new AtomicReference<>(); + private final Duration expireAfter; + protected AbstractMetricUpdater(InternalDriverContext context, Set enabledMetrics) { this.context = context; this.enabledMetrics = enabledMetrics; + DriverExecutionProfile config = context.getConfig().getDefaultProfile(); + Duration expireAfter = config.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER); + if (expireAfter.compareTo(MIN_EXPIRE_AFTER) < 0) { + LOG.warn( + "[{}] Value too low for {}: {}. Forcing to {} instead.", + context.getSessionName(), + DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), + expireAfter, + MIN_EXPIRE_AFTER); + expireAfter = MIN_EXPIRE_AFTER; + } + this.expireAfter = expireAfter; } @Override @@ -48,6 +72,10 @@ public boolean isEnabled(MetricT metric, String profileName) { return enabledMetrics.contains(metric); } + public Duration getExpireAfter() { + return expireAfter; + } + protected int connectedNodes() { int count = 0; for (Node node : context.getMetadataManager().getMetadata().getNodes().values()) { @@ -60,7 +88,6 @@ protected int connectedNodes() { protected int throttlingQueueSize() { RequestThrottler requestThrottler = context.getRequestThrottler(); - String logPrefix = context.getSessionName(); if (requestThrottler instanceof ConcurrencyLimitingRequestThrottler) { return ((ConcurrencyLimitingRequestThrottler) requestThrottler).getQueueSize(); } @@ -69,7 +96,7 @@ protected int throttlingQueueSize() { } LOG.warn( "[{}] Metric {} does not support {}, it will always return 0", - logPrefix, + context.getSessionName(), DefaultSessionMetric.THROTTLING_QUEUE_SIZE.getPath(), requestThrottler.getClass().getName()); return 0; @@ -117,4 +144,40 @@ protected int orphanedStreamIds(Node node) { ChannelPool pool = context.getPoolManager().getPools().get(node); return (pool == null) ? 0 : pool.getOrphanedIds(); } + + protected void startMetricsExpirationTimeout() { + metricsExpirationTimeoutRef.accumulateAndGet( + newTimeout(), + (current, update) -> { + if (current == null) { + return update; + } else { + update.cancel(); + return current; + } + }); + } + + protected void cancelMetricsExpirationTimeout() { + Timeout t = metricsExpirationTimeoutRef.getAndSet(null); + if (t != null) { + t.cancel(); + } + } + + protected Timeout newTimeout() { + return context + .getNettyOptions() + .getTimer() + .newTimeout( + t -> { + if (t.isExpired()) { + clearMetrics(); + } + }, + expireAfter.toNanos(), + TimeUnit.NANOSECONDS); + } + + protected abstract void clearMetrics(); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java index 7605d770069..275cfa1185d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java @@ -54,7 +54,8 @@ protected DropwizardMetricUpdater( } @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) - public T getMetric(MetricT metric, String profileName) { + public T getMetric( + MetricT metric, @SuppressWarnings("unused") String profileName) { return (T) metrics.get(metric); } @@ -87,6 +88,16 @@ public void updateTimer( } } + @Override + protected void clearMetrics() { + for (MetricT metric : metrics.keySet()) { + MetricId id = getMetricId(metric); + registry.remove(id.getName()); + } + metrics.clear(); + reservoirs.clear(); + } + protected abstract MetricId getMetricId(MetricT metric); protected void initializeGauge( diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java index 8cfac64fbe4..96ccceae270 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactory.java @@ -20,18 +20,15 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeState; import com.datastax.oss.driver.api.core.metrics.Metrics; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; -import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; -import com.datastax.oss.driver.shaded.guava.common.cache.RemovalNotification; +import com.datastax.oss.driver.internal.core.metadata.NodeStateEvent; +import com.datastax.oss.driver.internal.core.util.concurrent.RunOrSchedule; import edu.umd.cs.findbugs.annotations.Nullable; -import java.time.Duration; -import java.util.List; +import io.netty.util.concurrent.EventExecutor; import java.util.Optional; import java.util.Set; import net.jcip.annotations.ThreadSafe; @@ -42,44 +39,23 @@ public class DropwizardMetricsFactory implements MetricsFactory { private static final Logger LOG = LoggerFactory.getLogger(DropwizardMetricsFactory.class); - static final Duration LOWEST_ACCEPTABLE_EXPIRE_AFTER = Duration.ofMinutes(5); private final InternalDriverContext context; private final Set enabledNodeMetrics; private final MetricRegistry registry; @Nullable private final Metrics metrics; private final SessionMetricUpdater sessionUpdater; - private final Cache metricsCache; public DropwizardMetricsFactory(DriverContext context) { - this((InternalDriverContext) context, Ticker.systemTicker()); - } - - public DropwizardMetricsFactory(InternalDriverContext context, Ticker ticker) { - this.context = context; + this.context = (InternalDriverContext) context; String logPrefix = context.getSessionName(); DriverExecutionProfile config = context.getConfig().getDefaultProfile(); Set enabledSessionMetrics = - parseSessionMetricPaths(config.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)); - Duration evictionTime = getAndValidateEvictionTime(config, logPrefix); + MetricPaths.parseSessionMetricPaths( + config.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED), logPrefix); this.enabledNodeMetrics = - parseNodeMetricPaths(config.getStringList(DefaultDriverOption.METRICS_NODE_ENABLED)); - - metricsCache = - CacheBuilder.newBuilder() - .ticker(ticker) - .expireAfterAccess(evictionTime) - .removalListener( - (RemovalNotification notification) -> { - LOG.debug( - "[{}] Removing metrics for node: {} from cache after {}", - logPrefix, - notification.getKey(), - evictionTime); - notification.getValue().cleanupNodeMetrics(); - }) - .build(); - + MetricPaths.parseNodeMetricPaths( + config.getStringList(DefaultDriverOption.METRICS_NODE_ENABLED), logPrefix); if (enabledSessionMetrics.isEmpty() && enabledNodeMetrics.isEmpty()) { LOG.debug("[{}] All metrics are disabled, Session.getMetrics will be empty", logPrefix); this.registry = null; @@ -87,7 +63,7 @@ public DropwizardMetricsFactory(InternalDriverContext context, Ticker ticker) { this.metrics = null; } else { // try to get the metric registry from the context - Object possibleMetricRegistry = context.getMetricRegistry(); + Object possibleMetricRegistry = this.context.getMetricRegistry(); if (possibleMetricRegistry == null) { // metrics are enabled, but a metric registry was not supplied to the context // create a registry object @@ -96,7 +72,7 @@ public DropwizardMetricsFactory(InternalDriverContext context, Ticker ticker) { if (possibleMetricRegistry instanceof MetricRegistry) { this.registry = (MetricRegistry) possibleMetricRegistry; DropwizardSessionMetricUpdater dropwizardSessionUpdater = - new DropwizardSessionMetricUpdater(context, enabledSessionMetrics, registry); + new DropwizardSessionMetricUpdater(this.context, enabledSessionMetrics, registry); this.sessionUpdater = dropwizardSessionUpdater; this.metrics = new DefaultMetrics(registry, dropwizardSessionUpdater); } else { @@ -108,25 +84,18 @@ public DropwizardMetricsFactory(InternalDriverContext context, Ticker ticker) { + possibleMetricRegistry.getClass().getName() + "'"); } + if (!enabledNodeMetrics.isEmpty()) { + EventExecutor adminEventExecutor = + this.context.getNettyOptions().adminEventExecutorGroup().next(); + this.context + .getEventBus() + .register( + NodeStateEvent.class, + RunOrSchedule.on(adminEventExecutor, this::processNodeStateEvent)); + } } } - @VisibleForTesting - static Duration getAndValidateEvictionTime(DriverExecutionProfile config, String logPrefix) { - Duration evictionTime = config.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER); - - if (evictionTime.compareTo(LOWEST_ACCEPTABLE_EXPIRE_AFTER) < 0) { - LOG.warn( - "[{}] Value too low for {}: {}. Forcing to {} instead.", - logPrefix, - DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), - evictionTime, - LOWEST_ACCEPTABLE_EXPIRE_AFTER); - } - - return evictionTime; - } - @Override public Optional getMetrics() { return Optional.ofNullable(metrics); @@ -142,19 +111,20 @@ public NodeMetricUpdater newNodeUpdater(Node node) { if (registry == null) { return NoopNodeMetricUpdater.INSTANCE; } else { - DropwizardNodeMetricUpdater dropwizardNodeMetricUpdater = - new DropwizardNodeMetricUpdater( - node, context, enabledNodeMetrics, registry, () -> metricsCache.getIfPresent(node)); - metricsCache.put(node, dropwizardNodeMetricUpdater); - return dropwizardNodeMetricUpdater; + return new DropwizardNodeMetricUpdater(node, context, enabledNodeMetrics, registry); } } - protected Set parseSessionMetricPaths(List paths) { - return MetricPaths.parseSessionMetricPaths(paths, context.getSessionName()); - } - - protected Set parseNodeMetricPaths(List paths) { - return MetricPaths.parseNodeMetricPaths(paths, context.getSessionName()); + protected void processNodeStateEvent(NodeStateEvent event) { + if (event.newState == NodeState.DOWN + || event.newState == NodeState.FORCED_DOWN + || event.newState == null) { + // node is DOWN or REMOVED + ((DropwizardNodeMetricUpdater) event.node.getMetricUpdater()).startMetricsExpirationTimeout(); + } else if (event.newState == NodeState.UP || event.newState == NodeState.UNKNOWN) { + // node is UP or ADDED + ((DropwizardNodeMetricUpdater) event.node.getMetricUpdater()) + .cancelMetricsExpirationTimeout(); + } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java index ca50f57d1c1..e5de076b548 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdater.java @@ -15,7 +15,6 @@ */ package com.datastax.oss.driver.internal.core.metrics; -import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.api.core.metrics.DseNodeMetric; @@ -26,7 +25,6 @@ import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import java.util.Set; -import java.util.concurrent.TimeUnit; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -34,17 +32,14 @@ public class DropwizardNodeMetricUpdater extends DropwizardMetricUpdater enabledMetrics, - MetricRegistry registry, - Runnable signalMetricUpdated) { + MetricRegistry registry) { super(context, enabledMetrics, registry); this.node = node; - this.signalMetricUpdated = signalMetricUpdated; DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); @@ -89,46 +84,6 @@ public DropwizardNodeMetricUpdater( DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_INTERVAL); } - @Override - public void incrementCounter(NodeMetric metric, String profileName, long amount) { - signalMetricUpdated.run(); - super.incrementCounter(metric, profileName, amount); - } - - @Override - public void updateHistogram(NodeMetric metric, String profileName, long value) { - signalMetricUpdated.run(); - super.updateHistogram(metric, profileName, value); - } - - @Override - public void markMeter(NodeMetric metric, String profileName, long amount) { - signalMetricUpdated.run(); - super.markMeter(metric, profileName, amount); - } - - @Override - public void updateTimer(NodeMetric metric, String profileName, long duration, TimeUnit unit) { - signalMetricUpdated.run(); - super.updateTimer(metric, profileName, duration, unit); - } - - @Override - @SuppressWarnings("TypeParameterUnusedInFormals") - public T getMetric(NodeMetric metric, String profileName) { - signalMetricUpdated.run(); - return super.getMetric(metric, profileName); - } - - public void cleanupNodeMetrics() { - for (NodeMetric metric : metrics.keySet()) { - MetricId id = getMetricId(metric); - registry.remove(id.getName()); - } - metrics.clear(); - reservoirs.clear(); - } - @Override protected MetricId getMetricId(NodeMetric metric) { MetricId id = context.getMetricIdGenerator().nodeMetricId(node, metric); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java index 51886d712a6..7434bb5b74b 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricsFactoryTest.java @@ -15,87 +15,24 @@ */ package com.datastax.oss.driver.internal.core.metrics; -import static com.datastax.oss.driver.internal.core.metrics.DropwizardMetricsFactory.LOWEST_ACCEPTABLE_EXPIRE_AFTER; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import ch.qos.logback.classic.Level; import com.codahale.metrics.MetricRegistry; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.util.LoggerTest; -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.time.Duration; import java.util.Collections; import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(DataProviderRunner.class) public class DropwizardMetricsFactoryTest { - private static final String LOG_PREFIX = "prefix"; - - @Test - public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { - // given - Duration expireAfter = LOWEST_ACCEPTABLE_EXPIRE_AFTER.minusMinutes(1); - LoggerTest.LoggerSetup logger = - LoggerTest.setupTestLogger(DropwizardMetricsFactory.class, Level.WARN); - DriverExecutionProfile driverExecutionProfile = mock(DriverExecutionProfile.class); - - // when - when(driverExecutionProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); - DropwizardMetricsFactory.getAndValidateEvictionTime(driverExecutionProfile, LOG_PREFIX); - - // then - verify(logger.appender, timeout(500).times(1)).doAppend(logger.loggingEventCaptor.capture()); - assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); - assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) - .contains( - String.format( - "[%s] Value too low for %s: %s. Forcing to %s instead.", - LOG_PREFIX, - DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), - expireAfter, - LOWEST_ACCEPTABLE_EXPIRE_AFTER)); - } - - @Test - @UseDataProvider(value = "acceptableEvictionTimes") - public void should_not_log_warning_when_provided_eviction_time_setting_is_acceptable( - Duration expireAfter) { - // given - LoggerTest.LoggerSetup logger = - LoggerTest.setupTestLogger(DropwizardMetricsFactory.class, Level.WARN); - DriverExecutionProfile driverExecutionProfile = mock(DriverExecutionProfile.class); - - // when - when(driverExecutionProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); - DropwizardMetricsFactory.getAndValidateEvictionTime(driverExecutionProfile, LOG_PREFIX); - - // then - verify(logger.appender, timeout(500).times(0)).doAppend(logger.loggingEventCaptor.capture()); - } - - @DataProvider - public static Object[][] acceptableEvictionTimes() { - return new Object[][] { - {LOWEST_ACCEPTABLE_EXPIRE_AFTER}, {LOWEST_ACCEPTABLE_EXPIRE_AFTER.plusMinutes(1)} - }; - } - @Test public void should_throw_if_registry_of_wrong_type() { // given @@ -111,7 +48,7 @@ public void should_throw_if_registry_of_wrong_type() { // registry object is not a registry type when(context.getMetricRegistry()).thenReturn(Integer.MAX_VALUE); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(LOWEST_ACCEPTABLE_EXPIRE_AFTER); + .thenReturn(Duration.ofHours(1)); when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) .thenReturn(enabledMetrics); // then @@ -123,11 +60,9 @@ public void should_throw_if_registry_of_wrong_type() { } catch (IllegalArgumentException iae) { assertThat(iae.getMessage()) .isEqualTo( - "Unexpected Metrics registry object. Expected registry object to be of type '" - + MetricRegistry.class.getName() - + "', but was '" - + Integer.class.getName() - + "'"); + "Unexpected Metrics registry object. " + + "Expected registry object to be of type '%s', but was '%s'", + MetricRegistry.class.getName(), Integer.class.getName()); } } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdaterTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdaterTest.java new file mode 100644 index 00000000000..38ce2b45b19 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metrics/DropwizardNodeMetricUpdaterTest.java @@ -0,0 +1,160 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import ch.qos.logback.classic.Level; +import com.codahale.metrics.MetricRegistry; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.config.DriverOption; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.NodeMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.util.LoggerTest; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.time.Duration; +import java.util.Collections; +import java.util.Set; +import java.util.function.Supplier; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class DropwizardNodeMetricUpdaterTest { + + @Test + public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { + // given + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(AbstractMetricUpdater.class, Level.WARN); + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); + Duration expireAfter = AbstractMetricUpdater.MIN_EXPIRE_AFTER.minusMinutes(1); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(expireAfter); + + DropwizardNodeMetricUpdater updater = + new DropwizardNodeMetricUpdater(node, context, enabledMetrics, new MetricRegistry()) { + @Override + protected void initializeGauge( + NodeMetric metric, DriverExecutionProfile profile, Supplier supplier) { + // do nothing + } + + @Override + protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + + @Override + protected void initializeHdrTimer( + NodeMetric metric, + DriverExecutionProfile profile, + DriverOption highestLatency, + DriverOption significantDigits, + DriverOption interval) { + // do nothing + } + }; + + // then + assertThat(updater.getExpireAfter()).isEqualTo(AbstractMetricUpdater.MIN_EXPIRE_AFTER); + verify(logger.appender, timeout(500).times(1)).doAppend(logger.loggingEventCaptor.capture()); + assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); + assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) + .contains( + String.format( + "[prefix] Value too low for %s: %s. Forcing to %s instead.", + DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), + expireAfter, + AbstractMetricUpdater.MIN_EXPIRE_AFTER)); + } + + @Test + @UseDataProvider(value = "acceptableEvictionTimes") + public void should_not_log_warning_when_provided_eviction_time_setting_is_acceptable( + Duration expireAfter) { + // given + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(AbstractMetricUpdater.class, Level.WARN); + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(expireAfter); + + DropwizardNodeMetricUpdater updater = + new DropwizardNodeMetricUpdater(node, context, enabledMetrics, new MetricRegistry()) { + @Override + protected void initializeGauge( + NodeMetric metric, DriverExecutionProfile profile, Supplier supplier) { + // do nothing + } + + @Override + protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + + @Override + protected void initializeHdrTimer( + NodeMetric metric, + DriverExecutionProfile profile, + DriverOption highestLatency, + DriverOption significantDigits, + DriverOption interval) { + // do nothing + } + }; + + // then + assertThat(updater.getExpireAfter()).isEqualTo(expireAfter); + verify(logger.appender, timeout(500).times(0)).doAppend(logger.loggingEventCaptor.capture()); + } + + @DataProvider + public static Object[][] acceptableEvictionTimes() { + return new Object[][] { + {AbstractMetricUpdater.MIN_EXPIRE_AFTER}, + {AbstractMetricUpdater.MIN_EXPIRE_AFTER.plusMinutes(1)} + }; + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java new file mode 100644 index 00000000000..57bda625ce2 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java @@ -0,0 +1,216 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Meter; +import com.codahale.metrics.Metric; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.core.metrics.Metrics; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; +import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import java.util.ArrayList; +import java.util.List; +import org.junit.ClassRule; +import org.junit.experimental.categories.Category; + +@Category(ParallelizableTests.class) +public class DropwizardMetricsIT extends MetricsITBase { + + @ClassRule + public static final SimulacronRule SIMULACRON_RULE = + new SimulacronRule(ClusterSpec.builder().withNodes(3)); + + @Override + protected SimulacronRule simulacron() { + return SIMULACRON_RULE; + } + + @Override + protected MetricRegistry newMetricRegistry() { + return new MetricRegistry(); + } + + @Override + protected String getMetricsFactoryClass() { + return "DropwizardMetricsFactory"; + } + + @Override + protected void assertMetricsPresent(CqlSession session) { + + MetricRegistry registry = + (MetricRegistry) ((InternalDriverContext) session.getContext()).getMetricRegistry(); + assertThat(registry).isNotNull(); + + assertThat(registry.getMetrics()) + .hasSize(ENABLED_SESSION_METRICS.size() + ENABLED_NODE_METRICS.size() * 3); + + MetricIdGenerator metricIdGenerator = + ((InternalDriverContext) session.getContext()).getMetricIdGenerator(); + + assertThat(session.getMetrics()).isPresent(); + Metrics metrics = session.getMetrics().get(); + + for (DefaultSessionMetric metric : ENABLED_SESSION_METRICS) { + + MetricId id = metricIdGenerator.sessionMetricId(metric); + Metric m = registry.getMetrics().get(id.getName()); + assertThat(m).isNotNull(); + + // assert that the same metric is retrievable through the registry and through the driver API + assertThat(metrics.getSessionMetric(metric)) + .isPresent() + .hasValueSatisfying(v -> assertThat(v).isSameAs(m)); + + switch (metric) { + case CONNECTED_NODES: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Integer) ((Gauge) m).getValue()).isEqualTo(3); + break; + case CQL_REQUESTS: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).getCount()).isEqualTo(30); + break; + case CQL_PREPARED_CACHE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Long) ((Gauge) m).getValue()).isOne(); + break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Meter.class); + assertThat(((Meter) m).getCount()).isGreaterThan(0); + break; + case CQL_CLIENT_TIMEOUTS: + case THROTTLING_ERRORS: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).getCount()).isZero(); + break; + case THROTTLING_DELAY: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).getCount()).isZero(); + break; + case THROTTLING_QUEUE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Integer) ((Gauge) m).getValue()).isZero(); + break; + } + } + + for (Node node : session.getMetadata().getNodes().values()) { + + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + + MetricId id = metricIdGenerator.nodeMetricId(node, metric); + Metric m = registry.getMetrics().get(id.getName()); + assertThat(m).isNotNull(); + + // assert that the same metric is retrievable through the registry and through the driver + // API + assertThat(metrics.getNodeMetric(node, metric)) + .isPresent() + .hasValueSatisfying(v -> assertThat(v).isSameAs(m)); + + switch (metric) { + case OPEN_CONNECTIONS: + assertThat(m).isInstanceOf(Gauge.class); + // control node has 2 connections + assertThat((Integer) ((Gauge) m).getValue()).isBetween(1, 2); + break; + case CQL_MESSAGES: + assertThat(m).isInstanceOf(Timer.class); + assertThat(((Timer) m).getCount()).isEqualTo(10); + break; + case READ_TIMEOUTS: + case WRITE_TIMEOUTS: + case UNAVAILABLES: + case OTHER_ERRORS: + case ABORTED_REQUESTS: + case UNSENT_REQUESTS: + case RETRIES: + case IGNORES: + case RETRIES_ON_READ_TIMEOUT: + case RETRIES_ON_WRITE_TIMEOUT: + case RETRIES_ON_UNAVAILABLE: + case RETRIES_ON_OTHER_ERROR: + case RETRIES_ON_ABORTED: + case IGNORES_ON_READ_TIMEOUT: + case IGNORES_ON_WRITE_TIMEOUT: + case IGNORES_ON_UNAVAILABLE: + case IGNORES_ON_OTHER_ERROR: + case IGNORES_ON_ABORTED: + case SPECULATIVE_EXECUTIONS: + case CONNECTION_INIT_ERRORS: + case AUTHENTICATION_ERRORS: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).getCount()).isZero(); + break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Meter.class); + assertThat(((Meter) m).getCount()).isGreaterThan(0L); + break; + case AVAILABLE_STREAMS: + case IN_FLIGHT: + case ORPHANED_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + break; + } + } + } + } + + @Override + protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) { + InternalDriverContext context = (InternalDriverContext) session.getContext(); + MetricRegistry registry = (MetricRegistry) context.getMetricRegistry(); + assertThat(registry).isNotNull(); + for (String id : nodeMetricIds(context, node)) { + assertThat(registry.getMetrics()).containsKey(id); + } + } + + @Override + protected void assertNodeMetricsEvicted(CqlSession session, Node node) { + InternalDriverContext context = (InternalDriverContext) session.getContext(); + MetricRegistry registry = (MetricRegistry) context.getMetricRegistry(); + assertThat(registry).isNotNull(); + for (String id : nodeMetricIds(context, node)) { + assertThat(registry.getMetrics()).doesNotContainKey(id); + } + } + + private List nodeMetricIds(InternalDriverContext context, Node node) { + List ids = new ArrayList<>(); + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = context.getMetricIdGenerator().nodeMetricId(node, metric); + ids.add(id.getName()); + } + return ids; + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/FakeTicker.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/FakeTicker.java deleted file mode 100644 index 0ad0e3b31d5..00000000000 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/FakeTicker.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.core.metrics; - -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import java.time.Duration; -import java.util.concurrent.atomic.AtomicLong; - -/** A Ticker whose value can be advanced programmatically in test. */ -public class FakeTicker extends Ticker { - - private final AtomicLong nanos = new AtomicLong(); - - public FakeTicker advance(long nanoseconds) { - nanos.addAndGet(nanoseconds); - return this; - } - - public FakeTicker advance(Duration duration) { - return advance(duration.toNanos()); - } - - @Override - public long read() { - return nanos.get(); - } -} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsIT.java deleted file mode 100644 index 299b8ea7de2..00000000000 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsIT.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.core.metrics; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; - -import com.codahale.metrics.Meter; -import com.codahale.metrics.Timer; -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.config.DriverConfigLoader; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; -import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; -import com.datastax.oss.driver.api.testinfra.session.SessionUtils; -import com.datastax.oss.driver.categories.ParallelizableTests; -import com.google.common.collect.Lists; -import java.util.Collections; -import java.util.concurrent.TimeUnit; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -@Category(ParallelizableTests.class) -public class MetricsIT { - - @ClassRule public static final CcmRule CCM_RULE = CcmRule.getInstance(); - - @Test - public void should_expose_metrics() { - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList( - DefaultDriverOption.METRICS_SESSION_ENABLED, - Collections.singletonList("cql-requests")) - .build(); - try (CqlSession session = SessionUtils.newSession(CCM_RULE, loader)) { - for (int i = 0; i < 10; i++) { - session.execute("SELECT release_version FROM system.local"); - } - - // Should have 10 requests, check within 5 seconds as metric increments after - // caller is notified. - await() - .pollInterval(500, TimeUnit.MILLISECONDS) - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> - assertThat(session.getMetrics()) - .hasValueSatisfying( - metrics -> - assertThat( - metrics.getSessionMetric( - DefaultSessionMetric.CQL_REQUESTS)) - .hasValueSatisfying( - cqlRequests -> { - // No need to be very sophisticated, metrics are already - // covered individually in unit tests. - assertThat(cqlRequests.getCount()).isEqualTo(10); - }))); - } - } - - @Test - public void should_expose_bytes_sent_and_received() { - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList( - DefaultDriverOption.METRICS_SESSION_ENABLED, - Lists.newArrayList("bytes-sent", "bytes-received")) - .withStringList( - DefaultDriverOption.METRICS_NODE_ENABLED, - Lists.newArrayList("bytes-sent", "bytes-received")) - .build(); - try (CqlSession session = SessionUtils.newSession(CCM_RULE, loader)) { - for (int i = 0; i < 10; i++) { - session.execute("SELECT release_version FROM system.local"); - } - - assertThat(session.getMetrics()) - .hasValueSatisfying( - metrics -> { - assertThat(metrics.getSessionMetric(DefaultSessionMetric.BYTES_SENT)) - .hasValueSatisfying( - // Can't be precise here as payload can be dependent on protocol version. - bytesSent -> assertThat(bytesSent.getCount()).isGreaterThan(0)); - assertThat(metrics.getSessionMetric(DefaultSessionMetric.BYTES_RECEIVED)) - .hasValueSatisfying( - bytesReceived -> assertThat(bytesReceived.getCount()).isGreaterThan(0)); - - // get only node in cluster and evaluate its metrics. - Node node = session.getMetadata().getNodes().values().iterator().next(); - assertThat(metrics.getNodeMetric(node, DefaultNodeMetric.BYTES_SENT)) - .hasValueSatisfying( - bytesSent -> assertThat(bytesSent.getCount()).isGreaterThan(0)); - assertThat(metrics.getNodeMetric(node, DefaultNodeMetric.BYTES_RECEIVED)) - .hasValueSatisfying( - bytesReceived -> assertThat(bytesReceived.getCount()).isGreaterThan(0)); - }); - } - } - - @Test - public void should_not_expose_metrics_if_disabled() { - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList(DefaultDriverOption.METRICS_SESSION_ENABLED, Collections.emptyList()) - .withStringList(DefaultDriverOption.METRICS_NODE_ENABLED, Collections.emptyList()) - .build(); - try (CqlSession session = SessionUtils.newSession(CCM_RULE, loader)) { - for (int i = 0; i < 10; i++) { - session.execute("SELECT release_version FROM system.local"); - } - - assertThat(session.getMetrics()).isEmpty(); - } - } -} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java new file mode 100644 index 00000000000..b8ee7ed1b03 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java @@ -0,0 +1,263 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import com.codahale.metrics.MetricRegistry; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeState; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.internal.core.context.EventBus; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metadata.DefaultNode; +import com.datastax.oss.driver.internal.core.metadata.NodeStateEvent; +import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; +import com.datastax.oss.driver.internal.core.metrics.DefaultMetricIdGenerator; +import com.datastax.oss.driver.internal.core.metrics.TaggingMetricIdGenerator; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.net.InetSocketAddress; +import java.time.Duration; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public abstract class MetricsITBase { + + protected static final List ENABLED_SESSION_METRICS = + Arrays.asList(DefaultSessionMetric.values()); + + protected static final List ENABLED_NODE_METRICS = + Arrays.asList(DefaultNodeMetric.values()); + + protected abstract SimulacronRule simulacron(); + + protected abstract Object newMetricRegistry(); + + protected abstract String getMetricsFactoryClass(); + + protected abstract void assertMetricsPresent(CqlSession session); + + protected abstract void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception; + + protected abstract void assertNodeMetricsNotEvicted(CqlSession session, Node node) + throws Exception; + + @Before + public void resetSimulacron() { + simulacron().cluster().clearLogs(); + simulacron().cluster().clearPrimes(true); + } + + @Test + @UseDataProvider("descriptorsAndPrefixes") + public void should_expose_metrics_if_enabled(Class metricIdGenerator, String prefix) { + + Assume.assumeFalse( + "Cannot use metric tags with Dropwizard", + metricIdGenerator.getSimpleName().contains("Tagging") + && getMetricsFactoryClass().contains("Dropwizard")); + + DriverConfigLoader loader = + allMetricsEnabled() + .withString( + DefaultDriverOption.METRICS_ID_GENERATOR_CLASS, metricIdGenerator.getSimpleName()) + .withString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, prefix) + .build(); + + try (CqlSession session = + CqlSession.builder() + .addContactEndPoints(simulacron().getContactPoints()) + .withConfigLoader(loader) + .withMetricRegistry(newMetricRegistry()) + .build()) { + + session.prepare("irrelevant"); + queryAllNodes(session); + assertMetricsPresent(session); + } + } + + @DataProvider + public static Object[][] descriptorsAndPrefixes() { + return new Object[][] { + new Object[] {DefaultMetricIdGenerator.class, ""}, + new Object[] {DefaultMetricIdGenerator.class, "cassandra"}, + new Object[] {TaggingMetricIdGenerator.class, ""}, + new Object[] {TaggingMetricIdGenerator.class, "cassandra"}, + }; + } + + @Test + public void should_not_expose_metrics_if_disabled() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withStringList(DefaultDriverOption.METRICS_SESSION_ENABLED, Collections.emptyList()) + .withStringList(DefaultDriverOption.METRICS_NODE_ENABLED, Collections.emptyList()) + .withString(DefaultDriverOption.METRICS_FACTORY_CLASS, getMetricsFactoryClass()) + .build(); + try (CqlSession session = + CqlSession.builder() + .addContactEndPoints(simulacron().getContactPoints()) + .withConfigLoader(loader) + .build()) { + queryAllNodes(session); + MetricRegistry registry = + (MetricRegistry) ((InternalDriverContext) session.getContext()).getMetricRegistry(); + assertThat(registry).isNull(); + assertThat(session.getMetrics()).isEmpty(); + } + } + + @Test + public void should_evict_down_node_metrics_when_timeout_fires() throws Exception { + // given + Duration expireAfter = Duration.ofSeconds(1); + DriverConfigLoader loader = + allMetricsEnabled() + .withDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER, expireAfter) + .build(); + + AbstractMetricUpdater.MIN_EXPIRE_AFTER = expireAfter; + + try (CqlSession session = + CqlSession.builder() + .addContactEndPoints(simulacron().getContactPoints()) + .withConfigLoader(loader) + .withMetricRegistry(newMetricRegistry()) + .build()) { + + queryAllNodes(session); + + DefaultNode node1 = findNode(session, 0); + DefaultNode node2 = findNode(session, 1); + DefaultNode node3 = findNode(session, 2); + + EventBus eventBus = ((InternalDriverContext) session.getContext()).getEventBus(); + + // trigger node1 UP -> DOWN + eventBus.fire(NodeStateEvent.changed(NodeState.UP, NodeState.DOWN, node1)); + + Thread.sleep(expireAfter.toMillis()); + + // then node-level metrics should be evicted from node1, but + // node2 and node3 metrics should not have been evicted + await().untilAsserted(() -> assertNodeMetricsEvicted(session, node1)); + assertNodeMetricsNotEvicted(session, node2); + assertNodeMetricsNotEvicted(session, node3); + + } finally { + AbstractMetricUpdater.MIN_EXPIRE_AFTER = Duration.ofMinutes(5); + } + } + + @Test + public void should_not_evict_down_node_metrics_when_node_is_back_up_before_timeout() + throws Exception { + // given + Duration expireAfter = Duration.ofSeconds(2); + DriverConfigLoader loader = + allMetricsEnabled() + .withDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER, expireAfter) + .build(); + + AbstractMetricUpdater.MIN_EXPIRE_AFTER = expireAfter; + + try (CqlSession session = + CqlSession.builder() + .addContactEndPoints(simulacron().getContactPoints()) + .withConfigLoader(loader) + .withMetricRegistry(newMetricRegistry()) + .build()) { + + queryAllNodes(session); + + DefaultNode node1 = findNode(session, 0); + DefaultNode node2 = findNode(session, 1); + DefaultNode node3 = findNode(session, 2); + + EventBus eventBus = ((InternalDriverContext) session.getContext()).getEventBus(); + + // trigger nodes UP -> DOWN + eventBus.fire(NodeStateEvent.changed(NodeState.UP, NodeState.DOWN, node1)); + eventBus.fire(NodeStateEvent.changed(NodeState.UP, NodeState.FORCED_DOWN, node2)); + eventBus.fire(NodeStateEvent.removed(node3)); + + Thread.sleep(500); + + // trigger nodes DOWN -> UP, should cancel the timeouts + eventBus.fire(NodeStateEvent.changed(NodeState.DOWN, NodeState.UP, node1)); + eventBus.fire(NodeStateEvent.changed(NodeState.FORCED_DOWN, NodeState.UP, node2)); + eventBus.fire(NodeStateEvent.added(node3)); + + Thread.sleep(expireAfter.toMillis()); + + // then no node-level metrics should be evicted + assertNodeMetricsNotEvicted(session, node1); + assertNodeMetricsNotEvicted(session, node2); + assertNodeMetricsNotEvicted(session, node3); + + } finally { + AbstractMetricUpdater.MIN_EXPIRE_AFTER = Duration.ofMinutes(5); + } + } + + private ProgrammaticDriverConfigLoaderBuilder allMetricsEnabled() { + return SessionUtils.configLoaderBuilder() + .withStringList( + DefaultDriverOption.METRICS_SESSION_ENABLED, + ENABLED_SESSION_METRICS.stream() + .map(DefaultSessionMetric::getPath) + .collect(Collectors.toList())) + .withStringList( + DefaultDriverOption.METRICS_NODE_ENABLED, + ENABLED_NODE_METRICS.stream() + .map(DefaultNodeMetric::getPath) + .collect(Collectors.toList())) + .withString(DefaultDriverOption.METRICS_FACTORY_CLASS, getMetricsFactoryClass()); + } + + private void queryAllNodes(CqlSession session) { + for (Node node : session.getMetadata().getNodes().values()) { + for (int i = 0; i < 10; i++) { + session.execute(SimpleStatement.newInstance("irrelevant").setNode(node)); + } + } + } + + private DefaultNode findNode(CqlSession session, int id) { + InetSocketAddress address1 = simulacron().cluster().node(id).inetSocketAddress(); + return (DefaultNode) + session.getMetadata().findNode(address1).orElseThrow(IllegalStateException::new); + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsSimulacronIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsSimulacronIT.java deleted file mode 100644 index ecb549382f9..00000000000 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsSimulacronIT.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.core.metrics; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; - -import com.codahale.metrics.Meter; -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.config.DriverConfigLoader; -import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; -import com.datastax.oss.driver.api.core.metrics.Metrics; -import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; -import com.datastax.oss.driver.api.core.session.SessionBuilder; -import com.datastax.oss.driver.api.testinfra.session.SessionUtils; -import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; -import com.datastax.oss.driver.categories.ParallelizableTests; -import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; -import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.metrics.DropwizardMetricsFactory; -import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.datastax.oss.simulacron.common.cluster.ClusterSpec; -import com.google.common.collect.Lists; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.time.Duration; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -@Category(ParallelizableTests.class) -public class MetricsSimulacronIT { - - @ClassRule - public static final SimulacronRule SIMULACRON_RULE = - new SimulacronRule(ClusterSpec.builder().withNodes(1)); - - @Before - public void clearPrimes() { - SIMULACRON_RULE.cluster().clearLogs(); - SIMULACRON_RULE.cluster().clearPrimes(true); - } - - @Test - public void should_remove_node_metrics_and_not_remove_session_metrics_after_eviction_time() { - - // given - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList( - DefaultDriverOption.METRICS_SESSION_ENABLED, - Lists.newArrayList("bytes-sent", "bytes-received")) - .withStringList( - DefaultDriverOption.METRICS_NODE_ENABLED, - Lists.newArrayList("bytes-sent", "bytes-received")) - .withDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER, Duration.ofHours(1)) - .build(); - FakeTicker fakeTicker = new FakeTicker(); - try (CqlSession session = - new MetricsTestContextBuilder() - .addContactEndPoints(SIMULACRON_RULE.getContactPoints()) - .withConfigLoader(loader) - .withTicker(fakeTicker) - .build()) { - for (int i = 0; i < 10; i++) { - session.execute("SELECT release_version FROM system.local"); - } - - // when - fakeTicker.advance(Duration.ofHours(2)); - - // then session metrics are not evicted - assertThat(session.getMetrics()) - .hasValueSatisfying( - metrics -> { - assertThat(metrics.getSessionMetric(DefaultSessionMetric.BYTES_SENT)) - .hasValueSatisfying( - bytesSent -> assertThat(bytesSent.getCount()).isGreaterThan(0)); - assertThat(metrics.getSessionMetric(DefaultSessionMetric.BYTES_RECEIVED)) - .hasValueSatisfying( - bytesReceived -> assertThat(bytesReceived.getCount()).isGreaterThan(0)); - }); - - // and node metrics are evicted - await() - .until( - () -> { - // get only node in a cluster and evaluate its metrics. - Node node = session.getMetadata().getNodes().values().iterator().next(); - Metrics metrics = session.getMetrics().get(); - return !metrics.getNodeMetric(node, DefaultNodeMetric.BYTES_SENT).isPresent() - && !metrics - .getNodeMetric(node, DefaultNodeMetric.BYTES_RECEIVED) - .isPresent(); - }); - } - } - - @Test - public void - should_not_evict_not_updated_node_metric_if_any_other_node_level_metric_was_updated() { - // given - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList( - DefaultDriverOption.METRICS_NODE_ENABLED, - Lists.newArrayList("bytes-sent", "errors.request.aborted")) - .withDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER, Duration.ofHours(1)) - .build(); - FakeTicker fakeTicker = new FakeTicker(); - try (CqlSession session = - new MetricsTestContextBuilder() - .addContactEndPoints(SIMULACRON_RULE.getContactPoints()) - .withConfigLoader(loader) - .withTicker(fakeTicker) - .build()) { - for (int i = 0; i < 10; i++) { - session.execute("SELECT release_version FROM system.local"); - } - - // when advance time to before eviction - fakeTicker.advance(Duration.ofMinutes(59)); - // execute query that update only bytes-sent - session.execute("SELECT release_version FROM system.local"); - // advance time to after eviction - fakeTicker.advance(Duration.ofMinutes(2)); - - // then all node-level metrics should not be evicted - await() - .until( - () -> { - // get only node in a cluster and evaluate its metrics. - Node node = session.getMetadata().getNodes().values().iterator().next(); - Metrics metrics = session.getMetrics().get(); - return metrics.getNodeMetric(node, DefaultNodeMetric.BYTES_SENT).isPresent() - && metrics - .getNodeMetric(node, DefaultNodeMetric.ABORTED_REQUESTS) - .isPresent(); - }); - } - } - - private static class MetricsTestContextBuilder - extends SessionBuilder { - - private Ticker ticker; - - @Override - protected CqlSession wrap(@NonNull CqlSession defaultSession) { - return defaultSession; - } - - public MetricsTestContextBuilder withTicker(Ticker ticker) { - this.ticker = ticker; - return this; - } - - @Override - protected DriverContext buildContext( - DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { - return new MetricsTestContext(configLoader, programmaticArguments, ticker); - } - } - - private static class MetricsTestContext extends DefaultDriverContext { - private final Ticker ticker; - - public MetricsTestContext( - @NonNull DriverConfigLoader configLoader, - @NonNull ProgrammaticArguments programmaticArguments, - @NonNull Ticker ticker) { - super(configLoader, programmaticArguments); - this.ticker = ticker; - } - - @Override - protected MetricsFactory buildMetricsFactory() { - return new DropwizardMetricsFactoryCustomTicker(this, ticker); - } - - private static class DropwizardMetricsFactoryCustomTicker extends DropwizardMetricsFactory { - - public DropwizardMetricsFactoryCustomTicker(InternalDriverContext context, Ticker ticker) { - super(context, ticker); - } - } - } -} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java deleted file mode 100644 index f6bd9c23c5e..00000000000 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/common/AbstractMetricsTestBase.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.metrics.common; - -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.config.DriverConfigLoader; -import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.cql.SimpleStatement; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; -import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; -import com.datastax.oss.driver.api.core.session.SessionBuilder; -import com.datastax.oss.driver.api.testinfra.session.SessionUtils; -import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; -import com.datastax.oss.driver.core.metrics.FakeTicker; -import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; -import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.metrics.DefaultMetricIdGenerator; -import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; -import com.datastax.oss.driver.internal.core.metrics.TaggingMetricIdGenerator; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.net.InetSocketAddress; -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(DataProviderRunner.class) -public abstract class AbstractMetricsTestBase { - - protected static final List ENABLED_SESSION_METRICS = - Arrays.asList(DefaultSessionMetric.values()); - - protected static final List ENABLED_NODE_METRICS = - Arrays.asList(DefaultNodeMetric.values()); - - protected abstract SimulacronRule simulacron(); - - protected abstract Object newMetricRegistry(); - - protected abstract String getMetricsFactoryClass(); - - protected abstract MetricsFactory newTickingMetricsFactory( - InternalDriverContext context, Ticker ticker); - - protected abstract void assertMetrics(CqlSession session); - - protected abstract void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception; - - protected abstract void assertNodeMetricsNotEvicted(CqlSession session, Node node) - throws Exception; - - @Before - public void clearPrimes() { - simulacron().cluster().clearLogs(); - simulacron().cluster().clearPrimes(true); - } - - @Test - @UseDataProvider("descriptorsAndPrefixes") - public void should_expose_metrics(Class descriptorClass, String prefix) { - - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList( - DefaultDriverOption.METRICS_SESSION_ENABLED, - ENABLED_SESSION_METRICS.stream() - .map(DefaultSessionMetric::getPath) - .collect(Collectors.toList())) - .withStringList( - DefaultDriverOption.METRICS_NODE_ENABLED, - ENABLED_NODE_METRICS.stream() - .map(DefaultNodeMetric::getPath) - .collect(Collectors.toList())) - .withString(DefaultDriverOption.METRICS_FACTORY_CLASS, getMetricsFactoryClass()) - .withString( - DefaultDriverOption.METRICS_ID_GENERATOR_CLASS, descriptorClass.getSimpleName()) - .withString(DefaultDriverOption.METRICS_ID_GENERATOR_PREFIX, prefix) - .build(); - - try (CqlSession session = - CqlSession.builder() - .addContactEndPoints(simulacron().getContactPoints()) - .withConfigLoader(loader) - .withMetricRegistry(newMetricRegistry()) - .build()) { - - for (Node node : session.getMetadata().getNodes().values()) { - for (int i = 0; i < 10; i++) { - session.execute( - SimpleStatement.newInstance("SELECT release_version FROM system.local") - .setNode(node)); - } - } - - assertMetrics(session); - } - } - - @DataProvider - public static Object[][] descriptorsAndPrefixes() { - return new Object[][] { - new Object[] {DefaultMetricIdGenerator.class, ""}, - new Object[] {DefaultMetricIdGenerator.class, "cassandra"}, - new Object[] {TaggingMetricIdGenerator.class, ""}, - new Object[] {TaggingMetricIdGenerator.class, "cassandra"}, - }; - } - - @Test - public void should_evict_node_level_metrics() throws Exception { - // given - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withStringList( - DefaultDriverOption.METRICS_SESSION_ENABLED, - ENABLED_SESSION_METRICS.stream() - .map(DefaultSessionMetric::getPath) - .collect(Collectors.toList())) - .withStringList( - DefaultDriverOption.METRICS_NODE_ENABLED, - ENABLED_NODE_METRICS.stream() - .map(DefaultNodeMetric::getPath) - .collect(Collectors.toList())) - .withDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER, Duration.ofHours(1)) - .build(); - FakeTicker fakeTicker = new FakeTicker(); - try (CqlSession session = - new TestSessionBuilder() - .addContactEndPoints(simulacron().getContactPoints()) - .withConfigLoader(loader) - .withMetricRegistry(newMetricRegistry()) - .withTicker(fakeTicker) - .build()) { - - for (Node node : session.getMetadata().getNodes().values()) { - for (int i = 0; i < 10; i++) { - session.execute( - SimpleStatement.newInstance("SELECT release_version FROM system.local") - .setNode(node)); - } - } - - Node node1 = findNode(session, 0); - Node node2 = findNode(session, 1); - Node node3 = findNode(session, 2); - - // when advance time to before eviction - fakeTicker.advance(Duration.ofMinutes(59)); - // execute query that updates only node1 - session.execute( - SimpleStatement.newInstance("SELECT release_version FROM system.local").setNode(node1)); - // advance time to after eviction - fakeTicker.advance(Duration.ofMinutes(2)); - - // then no node-level metrics should be evicted from node1 - assertNodeMetricsNotEvicted(session, node1); - // node2 and node3 metrics should have been evicted - assertNodeMetricsEvicted(session, node2); - assertNodeMetricsEvicted(session, node3); - } - } - - private Node findNode(CqlSession session, int id) { - InetSocketAddress address1 = simulacron().cluster().node(id).inetSocketAddress(); - return session.getMetadata().findNode(address1).orElseThrow(IllegalStateException::new); - } - - private class TestSessionBuilder extends SessionBuilder { - - private Ticker ticker; - - @Override - protected CqlSession wrap(@NonNull CqlSession defaultSession) { - return defaultSession; - } - - public TestSessionBuilder withTicker(Ticker ticker) { - this.ticker = ticker; - return this; - } - - @Override - protected DriverContext buildContext( - DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { - return new TestDriverContext(configLoader, programmaticArguments, ticker); - } - } - - private class TestDriverContext extends DefaultDriverContext { - - private final Ticker ticker; - - public TestDriverContext( - @NonNull DriverConfigLoader configLoader, - @NonNull ProgrammaticArguments programmaticArguments, - @NonNull Ticker ticker) { - super(configLoader, programmaticArguments); - this.ticker = ticker; - } - - @Override - protected MetricsFactory buildMetricsFactory() { - return newTickingMetricsFactory(this, ticker); - } - } -} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java index d4261c2d967..ddfc8913d63 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java @@ -23,16 +23,11 @@ import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.core.metrics.MetricsITBase; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; -import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; -import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerMetricsFactory; -import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerNodeMetricUpdater; import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerTags; -import com.datastax.oss.driver.metrics.common.AbstractMetricsTestBase; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.Gauge; @@ -41,12 +36,11 @@ import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import java.lang.reflect.Field; import org.junit.ClassRule; import org.junit.experimental.categories.Category; @Category(ParallelizableTests.class) -public class MicrometerMetricsIT extends AbstractMetricsTestBase { +public class MicrometerMetricsIT extends MetricsITBase { @ClassRule public static final SimulacronRule SIMULACRON_RULE = @@ -68,12 +62,7 @@ protected String getMetricsFactoryClass() { } @Override - protected MetricsFactory newTickingMetricsFactory(InternalDriverContext context, Ticker ticker) { - return new MicrometerMetricsFactory(context, ticker); - } - - @Override - protected void assertMetrics(CqlSession session) { + protected void assertMetricsPresent(CqlSession session) { MeterRegistry registry = (MeterRegistry) ((InternalDriverContext) session.getContext()).getMetricRegistry(); @@ -91,19 +80,23 @@ protected void assertMetrics(CqlSession session) { Meter m = registry.find(id.getName()).tags(tags).meter(); assertThat(m).isNotNull(); switch (metric) { - case BYTES_SENT: - case BYTES_RECEIVED: - assertThat(m).isInstanceOf(Counter.class); - assertThat(((Counter) m).count()).isGreaterThan(0.0); - break; case CONNECTED_NODES: assertThat(m).isInstanceOf(Gauge.class); - assertThat(((Gauge) m).value()).isEqualTo(3.0); + assertThat(((Gauge) m).value()).isEqualTo(3); break; case CQL_REQUESTS: assertThat(m).isInstanceOf(Timer.class); assertThat(((Timer) m).count()).isEqualTo(30); break; + case CQL_PREPARED_CACHE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat(((Gauge) m).value()).isOne(); + break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).count()).isGreaterThan(0); + break; case CQL_CLIENT_TIMEOUTS: case THROTTLING_ERRORS: assertThat(m).isInstanceOf(Counter.class); @@ -114,7 +107,6 @@ protected void assertMetrics(CqlSession session) { assertThat(((Timer) m).count()).isZero(); break; case THROTTLING_QUEUE_SIZE: - case CQL_PREPARED_CACHE_SIZE: assertThat(m).isInstanceOf(Gauge.class); assertThat(((Gauge) m).value()).isZero(); break; @@ -138,59 +130,51 @@ protected void assertMetrics(CqlSession session) { assertThat(m).isInstanceOf(Timer.class); assertThat(((Timer) m).count()).isEqualTo(10); break; - case AVAILABLE_STREAMS: - assertThat(m).isInstanceOf(Gauge.class); - assertThat(((Gauge) m).value()).isGreaterThan(100); - break; - case IN_FLIGHT: - assertThat(m).isInstanceOf(Gauge.class); - break; - case ORPHANED_STREAMS: - assertThat(m).isInstanceOf(Gauge.class); - assertThat(((Gauge) m).value()).isZero(); - break; - case BYTES_SENT: - case BYTES_RECEIVED: - assertThat(m).isInstanceOf(Counter.class); - assertThat(((Counter) m).count()).isGreaterThan(0.0); - break; - case UNSENT_REQUESTS: - case ABORTED_REQUESTS: - case WRITE_TIMEOUTS: case READ_TIMEOUTS: + case WRITE_TIMEOUTS: case UNAVAILABLES: case OTHER_ERRORS: + case ABORTED_REQUESTS: + case UNSENT_REQUESTS: case RETRIES: - case RETRIES_ON_ABORTED: + case IGNORES: case RETRIES_ON_READ_TIMEOUT: case RETRIES_ON_WRITE_TIMEOUT: case RETRIES_ON_UNAVAILABLE: case RETRIES_ON_OTHER_ERROR: - case IGNORES: - case IGNORES_ON_ABORTED: + case RETRIES_ON_ABORTED: case IGNORES_ON_READ_TIMEOUT: case IGNORES_ON_WRITE_TIMEOUT: case IGNORES_ON_UNAVAILABLE: case IGNORES_ON_OTHER_ERROR: + case IGNORES_ON_ABORTED: case SPECULATIVE_EXECUTIONS: case CONNECTION_INIT_ERRORS: case AUTHENTICATION_ERRORS: assertThat(m).isInstanceOf(Counter.class); assertThat(((Counter) m).count()).isZero(); break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Counter.class); + assertThat(((Counter) m).count()).isGreaterThan(0.0); + break; + case AVAILABLE_STREAMS: + case IN_FLIGHT: + case ORPHANED_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + break; } } } } @Override - protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) throws Exception { + protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); MeterRegistry registry = (MeterRegistry) context.getMetricRegistry(); assertThat(registry).isNotNull(); - // FIXME see JAVA-2929 - triggerCacheCleanup(context.getMetricsFactory()); for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { MetricId id = metricIdGenerator.nodeMetricId(node, metric); Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); @@ -200,13 +184,11 @@ protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) throws } @Override - protected void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception { + protected void assertNodeMetricsEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); MeterRegistry registry = (MeterRegistry) context.getMetricRegistry(); assertThat(registry).isNotNull(); - // FIXME see JAVA-2929 - triggerCacheCleanup(context.getMetricsFactory()); for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { MetricId id = metricIdGenerator.nodeMetricId(node, metric); Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); @@ -214,13 +196,4 @@ protected void assertNodeMetricsEvicted(CqlSession session, Node node) throws Ex assertThat(m).isNull(); } } - - private void triggerCacheCleanup(MetricsFactory metricsFactory) throws Exception { - Field metricsCache = MicrometerMetricsFactory.class.getDeclaredField("metricsCache"); - metricsCache.setAccessible(true); - @SuppressWarnings("unchecked") - Cache cache = - (Cache) metricsCache.get(metricsFactory); - cache.cleanUp(); - } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java index 52a05f7d593..67a7f83c982 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java @@ -23,19 +23,15 @@ import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.core.metrics.MetricsITBase; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; -import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; -import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerNodeMetricUpdater; -import com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileMetricsFactory; import com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileTags; -import com.datastax.oss.driver.metrics.common.AbstractMetricsTestBase; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import io.smallrye.metrics.MetricsRegistryImpl; -import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; import org.eclipse.microprofile.metrics.Counter; import org.eclipse.microprofile.metrics.Gauge; import org.eclipse.microprofile.metrics.Meter; @@ -48,7 +44,7 @@ import org.junit.experimental.categories.Category; @Category(ParallelizableTests.class) -public class MicroProfileMetricsIT extends AbstractMetricsTestBase { +public class MicroProfileMetricsIT extends MetricsITBase { @ClassRule public static final SimulacronRule SIMULACRON_RULE = @@ -70,12 +66,7 @@ protected String getMetricsFactoryClass() { } @Override - protected MetricsFactory newTickingMetricsFactory(InternalDriverContext context, Ticker ticker) { - return new MicroProfileMetricsFactory(context, ticker); - } - - @Override - protected void assertMetrics(CqlSession session) { + protected void assertMetricsPresent(CqlSession session) { MetricRegistry registry = (MetricRegistry) ((InternalDriverContext) session.getContext()).getMetricRegistry(); @@ -94,18 +85,22 @@ protected void assertMetrics(CqlSession session) { Metric m = registry.getMetrics().get(id); assertThat(m).isNotNull(); switch (metric) { - case BYTES_SENT: - case BYTES_RECEIVED: - assertThat(m).isInstanceOf(Meter.class); - assertThat(((Meter) m).getCount()).isGreaterThan(0L); - break; case CONNECTED_NODES: assertThat(m).isInstanceOf(Gauge.class); assertThat((Integer) ((Gauge) m).getValue()).isEqualTo(3); break; case CQL_REQUESTS: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).getCount()).isEqualTo(30L); + assertThat(((Timer) m).getCount()).isEqualTo(30); + break; + case CQL_PREPARED_CACHE_SIZE: + assertThat(m).isInstanceOf(Gauge.class); + assertThat((Long) ((Gauge) m).getValue()).isOne(); + break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Meter.class); + assertThat(((Meter) m).getCount()).isGreaterThan(0); break; case CQL_CLIENT_TIMEOUTS: case THROTTLING_ERRORS: @@ -120,10 +115,6 @@ protected void assertMetrics(CqlSession session) { assertThat(m).isInstanceOf(Gauge.class); assertThat((Integer) ((Gauge) m).getValue()).isZero(); break; - case CQL_PREPARED_CACHE_SIZE: - assertThat(m).isInstanceOf(Gauge.class); - assertThat((Long) ((Gauge) m).getValue()).isZero(); - break; } } @@ -143,89 +134,73 @@ protected void assertMetrics(CqlSession session) { break; case CQL_MESSAGES: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).getCount()).isEqualTo(10L); - break; - case AVAILABLE_STREAMS: - assertThat(m).isInstanceOf(Gauge.class); - assertThat((Integer) ((Gauge) m).getValue()).isGreaterThan(100); - break; - case IN_FLIGHT: - assertThat(m).isInstanceOf(Gauge.class); - break; - case ORPHANED_STREAMS: - assertThat(m).isInstanceOf(Gauge.class); - assertThat((Integer) ((Gauge) m).getValue()).isZero(); + assertThat(((Timer) m).getCount()).isEqualTo(10); break; - case BYTES_SENT: - case BYTES_RECEIVED: - assertThat(m).isInstanceOf(Meter.class); - assertThat(((Meter) m).getCount()).isGreaterThan(0L); - break; - case UNSENT_REQUESTS: - case ABORTED_REQUESTS: - case WRITE_TIMEOUTS: case READ_TIMEOUTS: + case WRITE_TIMEOUTS: case UNAVAILABLES: case OTHER_ERRORS: + case ABORTED_REQUESTS: + case UNSENT_REQUESTS: case RETRIES: - case RETRIES_ON_ABORTED: + case IGNORES: case RETRIES_ON_READ_TIMEOUT: case RETRIES_ON_WRITE_TIMEOUT: case RETRIES_ON_UNAVAILABLE: case RETRIES_ON_OTHER_ERROR: - case IGNORES: - case IGNORES_ON_ABORTED: + case RETRIES_ON_ABORTED: case IGNORES_ON_READ_TIMEOUT: case IGNORES_ON_WRITE_TIMEOUT: case IGNORES_ON_UNAVAILABLE: case IGNORES_ON_OTHER_ERROR: + case IGNORES_ON_ABORTED: case SPECULATIVE_EXECUTIONS: case CONNECTION_INIT_ERRORS: case AUTHENTICATION_ERRORS: assertThat(m).isInstanceOf(Counter.class); assertThat(((Counter) m).getCount()).isZero(); break; + case BYTES_SENT: + case BYTES_RECEIVED: + assertThat(m).isInstanceOf(Meter.class); + assertThat(((Meter) m).getCount()).isGreaterThan(0L); + break; + case AVAILABLE_STREAMS: + case IN_FLIGHT: + case ORPHANED_STREAMS: + assertThat(m).isInstanceOf(Gauge.class); + break; } } } } @Override - protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) throws Exception { + protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); - MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); MetricRegistry registry = (MetricRegistry) context.getMetricRegistry(); assertThat(registry).isNotNull(); - // FIXME see JAVA-2929 - triggerCacheCleanup(context.getMetricsFactory()); - for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { - MetricId id = metricIdGenerator.nodeMetricId(node, metric); - Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); - assertThat(registry.getMetrics()).containsKey(new MetricID(id.getName(), tags)); + for (MetricID id : nodeMetricIds(context, node)) { + assertThat(registry.getMetrics()).containsKey(id); } } @Override - protected void assertNodeMetricsEvicted(CqlSession session, Node node) throws Exception { + protected void assertNodeMetricsEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); - MetricIdGenerator metricIdGenerator = context.getMetricIdGenerator(); MetricRegistry registry = (MetricRegistry) context.getMetricRegistry(); assertThat(registry).isNotNull(); - // FIXME see JAVA-2929 - triggerCacheCleanup(context.getMetricsFactory()); - for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { - MetricId id = metricIdGenerator.nodeMetricId(node, metric); - Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); - assertThat(registry.getMetrics()).doesNotContainKey(new MetricID(id.getName(), tags)); + for (MetricID id : nodeMetricIds(context, node)) { + assertThat(registry.getMetrics()).doesNotContainKey(id); } } - private void triggerCacheCleanup(MetricsFactory metricsFactory) throws Exception { - Field metricsCache = MicroProfileMetricsFactory.class.getDeclaredField("metricsCache"); - metricsCache.setAccessible(true); - @SuppressWarnings("unchecked") - Cache cache = - (Cache) metricsCache.get(metricsFactory); - cache.cleanUp(); + private List nodeMetricIds(InternalDriverContext context, Node node) { + List ids = new ArrayList<>(); + for (DefaultNodeMetric metric : ENABLED_NODE_METRICS) { + MetricId id = context.getMetricIdGenerator().nodeMetricId(node, metric); + ids.add(new MetricID(id.getName(), MicroProfileTags.toMicroProfileTags(id.getTags()))); + } + return ids; } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java index d00539df191..89f6c03bff2 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java @@ -38,6 +38,7 @@ public abstract class MicrometerMetricUpdater extends AbstractMetricUpdater { protected final MeterRegistry registry; + protected final ConcurrentMap metrics = new ConcurrentHashMap<>(); protected MicrometerMetricUpdater( @@ -76,6 +77,14 @@ public void updateTimer( } } + @Override + protected void clearMetrics() { + for (Meter metric : metrics.values()) { + registry.remove(metric); + } + metrics.clear(); + } + protected abstract MetricId getMetricId(MetricT metric); protected void initializeGauge( diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java index f326b308733..a39a4924612 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactory.java @@ -19,23 +19,21 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeState; import com.datastax.oss.driver.api.core.metrics.Metrics; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metadata.NodeStateEvent; import com.datastax.oss.driver.internal.core.metrics.MetricPaths; import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.NoopNodeMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.NoopSessionMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; -import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; -import com.datastax.oss.driver.shaded.guava.common.cache.RemovalNotification; +import com.datastax.oss.driver.internal.core.util.concurrent.RunOrSchedule; import io.micrometer.core.instrument.MeterRegistry; -import java.time.Duration; +import io.netty.util.concurrent.EventExecutor; import java.util.Optional; import java.util.Set; import net.jcip.annotations.ThreadSafe; @@ -46,20 +44,14 @@ public class MicrometerMetricsFactory implements MetricsFactory { private static final Logger LOG = LoggerFactory.getLogger(MicrometerMetricsFactory.class); - static final Duration LOWEST_ACCEPTABLE_EXPIRE_AFTER = Duration.ofMinutes(5); private final InternalDriverContext context; private final Set enabledNodeMetrics; private final MeterRegistry registry; private final SessionMetricUpdater sessionUpdater; - private final Cache metricsCache; public MicrometerMetricsFactory(DriverContext context) { - this((InternalDriverContext) context, Ticker.systemTicker()); - } - - public MicrometerMetricsFactory(InternalDriverContext context, Ticker ticker) { - this.context = context; + this.context = (InternalDriverContext) context; String logPrefix = context.getSessionName(); DriverExecutionProfile config = context.getConfig().getDefaultProfile(); Set enabledSessionMetrics = @@ -68,31 +60,13 @@ public MicrometerMetricsFactory(InternalDriverContext context, Ticker ticker) { this.enabledNodeMetrics = MetricPaths.parseNodeMetricPaths( config.getStringList(DefaultDriverOption.METRICS_NODE_ENABLED), logPrefix); - - Duration evictionTime = getAndValidateEvictionTime(config, logPrefix); - - metricsCache = - CacheBuilder.newBuilder() - .ticker(ticker) - .expireAfterAccess(evictionTime) - .removalListener( - (RemovalNotification notification) -> { - LOG.debug( - "[{}] Removing metrics for node: {} from cache after {}", - logPrefix, - notification.getKey(), - evictionTime); - notification.getValue().cleanupNodeMetrics(); - }) - .build(); - if (enabledSessionMetrics.isEmpty() && enabledNodeMetrics.isEmpty()) { LOG.debug("[{}] All metrics are disabled, Session.getMetrics will be empty", logPrefix); this.registry = null; this.sessionUpdater = NoopSessionMetricUpdater.INSTANCE; } else { // try to get the metric registry from the context - Object possibleMetricRegistry = context.getMetricRegistry(); + Object possibleMetricRegistry = this.context.getMetricRegistry(); if (possibleMetricRegistry == null) { // metrics are enabled, but a metric registry was not supplied to the context // use the global registry @@ -111,25 +85,18 @@ public MicrometerMetricsFactory(InternalDriverContext context, Ticker ticker) { + possibleMetricRegistry.getClass().getName() + "'"); } + if (!enabledNodeMetrics.isEmpty()) { + EventExecutor adminEventExecutor = + this.context.getNettyOptions().adminEventExecutorGroup().next(); + this.context + .getEventBus() + .register( + NodeStateEvent.class, + RunOrSchedule.on(adminEventExecutor, this::processNodeStateEvent)); + } } } - @VisibleForTesting - static Duration getAndValidateEvictionTime(DriverExecutionProfile config, String logPrefix) { - Duration evictionTime = config.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER); - - if (evictionTime.compareTo(LOWEST_ACCEPTABLE_EXPIRE_AFTER) < 0) { - LOG.warn( - "[{}] Value too low for {}: {}. Forcing to {} instead.", - logPrefix, - DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), - evictionTime, - LOWEST_ACCEPTABLE_EXPIRE_AFTER); - } - - return evictionTime; - } - @Override public Optional getMetrics() { return Optional.empty(); @@ -144,11 +111,21 @@ public SessionMetricUpdater getSessionUpdater() { public NodeMetricUpdater newNodeUpdater(Node node) { if (registry == null) { return NoopNodeMetricUpdater.INSTANCE; + } else { + return new MicrometerNodeMetricUpdater(node, context, enabledNodeMetrics, registry); + } + } + + protected void processNodeStateEvent(NodeStateEvent event) { + if (event.newState == NodeState.DOWN + || event.newState == NodeState.FORCED_DOWN + || event.newState == null) { + // node is DOWN or REMOVED + ((MicrometerNodeMetricUpdater) event.node.getMetricUpdater()).startMetricsExpirationTimeout(); + } else if (event.newState == NodeState.UP || event.newState == NodeState.UNKNOWN) { + // node is UP or ADDED + ((MicrometerNodeMetricUpdater) event.node.getMetricUpdater()) + .cancelMetricsExpirationTimeout(); } - MicrometerNodeMetricUpdater updater = - new MicrometerNodeMetricUpdater( - node, context, enabledNodeMetrics, registry, () -> metricsCache.getIfPresent(node)); - metricsCache.put(node, updater); - return updater; } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java index 3c77839c4b5..a0c4cbd05a6 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java @@ -23,10 +23,8 @@ import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; -import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; import java.util.Set; -import java.util.concurrent.TimeUnit; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -34,17 +32,14 @@ public class MicrometerNodeMetricUpdater extends MicrometerMetricUpdater enabledMetrics, - MeterRegistry registry, - Runnable signalMetricUpdated) { + MeterRegistry registry) { super(context, enabledMetrics, registry); this.node = node; - this.signalMetricUpdated = signalMetricUpdated; DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); @@ -80,38 +75,17 @@ public MicrometerNodeMetricUpdater( } @Override - public void incrementCounter(NodeMetric metric, String profileName, long amount) { - signalMetricUpdated.run(); - super.incrementCounter(metric, profileName, amount); - } - - @Override - public void updateHistogram(NodeMetric metric, String profileName, long value) { - signalMetricUpdated.run(); - super.updateHistogram(metric, profileName, value); - } - - @Override - public void markMeter(NodeMetric metric, String profileName, long amount) { - signalMetricUpdated.run(); - super.markMeter(metric, profileName, amount); + protected MetricId getMetricId(NodeMetric metric) { + return context.getMetricIdGenerator().nodeMetricId(node, metric); } @Override - public void updateTimer(NodeMetric metric, String profileName, long duration, TimeUnit unit) { - signalMetricUpdated.run(); - super.updateTimer(metric, profileName, duration, unit); - } - - public void cleanupNodeMetrics() { - for (Meter meter : metrics.values()) { - registry.remove(meter); - } - metrics.clear(); + protected void startMetricsExpirationTimeout() { + super.startMetricsExpirationTimeout(); } @Override - protected MetricId getMetricId(NodeMetric metric) { - return context.getMetricIdGenerator().nodeMetricId(node, metric); + protected void cancelMetricsExpirationTimeout() { + super.cancelMetricsExpirationTimeout(); } } diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java index 17532ff30bd..e2ad28f08e6 100644 --- a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricsFactoryTest.java @@ -15,91 +15,26 @@ */ package com.datastax.oss.driver.internal.metrics.micrometer; -import static com.datastax.oss.driver.internal.metrics.micrometer.MicrometerMetricsFactory.LOWEST_ACCEPTABLE_EXPIRE_AFTER; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import ch.qos.logback.classic.Level; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.util.LoggerTest; -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; import io.micrometer.core.instrument.MeterRegistry; import java.time.Duration; import java.util.Collections; import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(DataProviderRunner.class) public class MicrometerMetricsFactoryTest { - private static final String LOG_PREFIX = "prefix"; - @Test - public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { - // given - Duration expireAfter = LOWEST_ACCEPTABLE_EXPIRE_AFTER.minusMinutes(1); - LoggerTest.LoggerSetup logger = - LoggerTest.setupTestLogger(MicrometerMetricsFactory.class, Level.WARN); - DriverExecutionProfile driverExecutionProfile = mock(DriverExecutionProfile.class); - - // when - when(driverExecutionProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); - MicrometerMetricsFactory.getAndValidateEvictionTime(driverExecutionProfile, LOG_PREFIX); - - // then - verify(logger.appender, timeout(500).times(1)).doAppend(logger.loggingEventCaptor.capture()); - assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); - assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) - .contains( - String.format( - "[%s] Value too low for %s: %s. Forcing to %s instead.", - LOG_PREFIX, - DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), - expireAfter, - LOWEST_ACCEPTABLE_EXPIRE_AFTER)); - } - - @Test - @UseDataProvider(value = "acceptableEvictionTimes") - public void should_not_log_warning_when_provided_eviction_time_setting_is_acceptable( - Duration expireAfter) { - // given - LoggerTest.LoggerSetup logger = - LoggerTest.setupTestLogger(MicrometerMetricsFactory.class, Level.WARN); - DriverExecutionProfile driverExecutionProfile = mock(DriverExecutionProfile.class); - - // when - when(driverExecutionProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); - MicrometerMetricsFactory.getAndValidateEvictionTime(driverExecutionProfile, LOG_PREFIX); - - // then - verify(logger.appender, timeout(500).times(0)).doAppend(logger.loggingEventCaptor.capture()); - } - - @DataProvider - public static Object[][] acceptableEvictionTimes() { - return new Object[][] { - {LOWEST_ACCEPTABLE_EXPIRE_AFTER}, {LOWEST_ACCEPTABLE_EXPIRE_AFTER.plusMinutes(1)} - }; - } - - @Test - @UseDataProvider(value = "invalidRegistryTypes") - public void should_throw_if_wrong_or_missing_registry_type( - Object registryObj, String expectedMsg) { + public void should_throw_if_wrong_or_missing_registry_type() { // given InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); @@ -111,9 +46,9 @@ public void should_throw_if_wrong_or_missing_registry_type( when(context.getConfig()).thenReturn(config); when(context.getSessionName()).thenReturn("MockSession"); // registry object is not a registry type - when(context.getMetricRegistry()).thenReturn(registryObj); + when(context.getMetricRegistry()).thenReturn(Integer.MAX_VALUE); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(LOWEST_ACCEPTABLE_EXPIRE_AFTER); + .thenReturn(Duration.ofHours(1)); when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) .thenReturn(enabledMetrics); // then @@ -123,21 +58,11 @@ public void should_throw_if_wrong_or_missing_registry_type( "MetricsFactory should require correct registry object type: " + MeterRegistry.class.getName()); } catch (IllegalArgumentException iae) { - assertThat(iae.getMessage()).isEqualTo(expectedMsg); + assertThat(iae.getMessage()) + .isEqualTo( + "Unexpected Metrics registry object. " + + "Expected registry object to be of type '%s', but was '%s'", + MeterRegistry.class.getName(), Integer.class.getName()); } } - - @DataProvider - public static Object[][] invalidRegistryTypes() { - return new Object[][] { - { - Integer.MAX_VALUE, - "Unexpected Metrics registry object. Expected registry object to be of type '" - + MeterRegistry.class.getName() - + "', but was '" - + Integer.class.getName() - + "'" - }, - }; - } } diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java new file mode 100644 index 00000000000..badea84e6db --- /dev/null +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java @@ -0,0 +1,150 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.metrics.micrometer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import ch.qos.logback.classic.Level; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.NodeMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; +import com.datastax.oss.driver.internal.core.util.LoggerTest; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import java.time.Duration; +import java.util.Collections; +import java.util.Set; +import java.util.function.Supplier; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class MicrometerNodeMetricUpdaterTest { + + @Test + public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { + // given + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(AbstractMetricUpdater.class, Level.WARN); + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); + Duration expireAfter = AbstractMetricUpdater.MIN_EXPIRE_AFTER.minusMinutes(1); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(expireAfter); + + MicrometerNodeMetricUpdater updater = + new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()) { + @Override + protected void initializeGauge( + NodeMetric metric, DriverExecutionProfile profile, Supplier supplier) { + // do nothing + } + + @Override + protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + + @Override + protected void initializeTimer(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + }; + + // then + assertThat(updater.getExpireAfter()).isEqualTo(AbstractMetricUpdater.MIN_EXPIRE_AFTER); + verify(logger.appender, timeout(500).times(1)).doAppend(logger.loggingEventCaptor.capture()); + assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); + assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) + .contains( + String.format( + "[prefix] Value too low for %s: %s. Forcing to %s instead.", + DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), + expireAfter, + AbstractMetricUpdater.MIN_EXPIRE_AFTER)); + } + + @Test + @UseDataProvider(value = "acceptableEvictionTimes") + public void should_not_log_warning_when_provided_eviction_time_setting_is_acceptable( + Duration expireAfter) { + // given + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(AbstractMetricUpdater.class, Level.WARN); + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(expireAfter); + + MicrometerNodeMetricUpdater updater = + new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()) { + @Override + protected void initializeGauge( + NodeMetric metric, DriverExecutionProfile profile, Supplier supplier) { + // do nothing + } + + @Override + protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + + @Override + protected void initializeTimer(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + }; + + // then + assertThat(updater.getExpireAfter()).isEqualTo(expireAfter); + verify(logger.appender, timeout(500).times(0)).doAppend(logger.loggingEventCaptor.capture()); + } + + @DataProvider + public static Object[][] acceptableEvictionTimes() { + return new Object[][] { + {AbstractMetricUpdater.MIN_EXPIRE_AFTER}, + {AbstractMetricUpdater.MIN_EXPIRE_AFTER.plusMinutes(1)} + }; + } +} diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index f6549e4d73c..454562e3ed2 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -57,6 +57,11 @@ + + io.smallrye + smallrye-metrics + test + ch.qos.logback logback-classic diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java index 2d5ea9013c5..ea06e2bff47 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java @@ -31,6 +31,7 @@ import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.Meter; import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.MetricType; import org.eclipse.microprofile.metrics.Tag; @@ -40,6 +41,7 @@ public abstract class MicroProfileMetricUpdater extends AbstractMetricUpdater { protected final MetricRegistry registry; + protected final ConcurrentMap metrics = new ConcurrentHashMap<>(); protected MicroProfileMetricUpdater( @@ -77,6 +79,16 @@ public void updateTimer( } } + @Override + protected void clearMetrics() { + for (MetricT metric : metrics.keySet()) { + MetricId id = getMetricId(metric); + Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); + registry.remove(new MetricID(id.getName(), tags)); + } + metrics.clear(); + } + protected abstract MetricId getMetricId(MetricT metric); protected void initializeGauge( diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java index f06974a20d4..11987af7cfa 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactory.java @@ -19,22 +19,20 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeState; import com.datastax.oss.driver.api.core.metrics.Metrics; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metadata.NodeStateEvent; import com.datastax.oss.driver.internal.core.metrics.MetricPaths; import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.NoopNodeMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.NoopSessionMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; -import com.datastax.oss.driver.shaded.guava.common.base.Ticker; -import com.datastax.oss.driver.shaded.guava.common.cache.Cache; -import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; -import com.datastax.oss.driver.shaded.guava.common.cache.RemovalNotification; -import java.time.Duration; +import com.datastax.oss.driver.internal.core.util.concurrent.RunOrSchedule; +import io.netty.util.concurrent.EventExecutor; import java.util.Optional; import java.util.Set; import net.jcip.annotations.ThreadSafe; @@ -44,21 +42,16 @@ @ThreadSafe public class MicroProfileMetricsFactory implements MetricsFactory { + private static final Logger LOG = LoggerFactory.getLogger(MicroProfileMetricsFactory.class); - static final Duration LOWEST_ACCEPTABLE_EXPIRE_AFTER = Duration.ofMinutes(5); private final InternalDriverContext context; private final Set enabledNodeMetrics; private final MetricRegistry registry; private final SessionMetricUpdater sessionUpdater; - private final Cache metricsCache; public MicroProfileMetricsFactory(DriverContext context) { - this((InternalDriverContext) context, Ticker.systemTicker()); - } - - public MicroProfileMetricsFactory(InternalDriverContext context, Ticker ticker) { - this.context = context; + this.context = (InternalDriverContext) context; String logPrefix = context.getSessionName(); DriverExecutionProfile config = context.getConfig().getDefaultProfile(); Set enabledSessionMetrics = @@ -67,30 +60,12 @@ public MicroProfileMetricsFactory(InternalDriverContext context, Ticker ticker) this.enabledNodeMetrics = MetricPaths.parseNodeMetricPaths( config.getStringList(DefaultDriverOption.METRICS_NODE_ENABLED), logPrefix); - - Duration evictionTime = getAndValidateEvictionTime(config, logPrefix); - - metricsCache = - CacheBuilder.newBuilder() - .ticker(ticker) - .expireAfterAccess(evictionTime) - .removalListener( - (RemovalNotification notification) -> { - LOG.debug( - "[{}] Removing metrics for node: {} from cache after {}", - logPrefix, - notification.getKey(), - evictionTime); - notification.getValue().cleanupNodeMetrics(); - }) - .build(); - if (enabledSessionMetrics.isEmpty() && enabledNodeMetrics.isEmpty()) { LOG.debug("[{}] All metrics are disabled.", logPrefix); this.registry = null; this.sessionUpdater = NoopSessionMetricUpdater.INSTANCE; } else { - Object possibleMetricRegistry = context.getMetricRegistry(); + Object possibleMetricRegistry = this.context.getMetricRegistry(); if (possibleMetricRegistry == null) { // metrics are enabled, but a metric registry was not supplied to the context throw new IllegalArgumentException( @@ -112,25 +87,18 @@ public MicroProfileMetricsFactory(InternalDriverContext context, Ticker ticker) + possibleMetricRegistry.getClass().getName() + "'"); } + if (!enabledNodeMetrics.isEmpty()) { + EventExecutor adminEventExecutor = + this.context.getNettyOptions().adminEventExecutorGroup().next(); + this.context + .getEventBus() + .register( + NodeStateEvent.class, + RunOrSchedule.on(adminEventExecutor, this::processNodeStateEvent)); + } } } - @VisibleForTesting - static Duration getAndValidateEvictionTime(DriverExecutionProfile config, String logPrefix) { - Duration evictionTime = config.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER); - - if (evictionTime.compareTo(LOWEST_ACCEPTABLE_EXPIRE_AFTER) < 0) { - LOG.warn( - "[{}] Value too low for {}: {}. Forcing to {} instead.", - logPrefix, - DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), - evictionTime, - LOWEST_ACCEPTABLE_EXPIRE_AFTER); - } - - return evictionTime; - } - @Override public Optional getMetrics() { return Optional.empty(); @@ -145,11 +113,22 @@ public SessionMetricUpdater getSessionUpdater() { public NodeMetricUpdater newNodeUpdater(Node node) { if (registry == null) { return NoopNodeMetricUpdater.INSTANCE; + } else { + return new MicroProfileNodeMetricUpdater(node, context, enabledNodeMetrics, registry); + } + } + + protected void processNodeStateEvent(NodeStateEvent event) { + if (event.newState == NodeState.DOWN + || event.newState == NodeState.FORCED_DOWN + || event.newState == null) { + // node is DOWN or REMOVED + ((MicroProfileNodeMetricUpdater) event.node.getMetricUpdater()) + .startMetricsExpirationTimeout(); + } else if (event.newState == NodeState.UP || event.newState == NodeState.UNKNOWN) { + // node is UP or ADDED + ((MicroProfileNodeMetricUpdater) event.node.getMetricUpdater()) + .cancelMetricsExpirationTimeout(); } - MicroProfileNodeMetricUpdater updater = - new MicroProfileNodeMetricUpdater( - node, context, enabledNodeMetrics, registry, () -> metricsCache.getIfPresent(node)); - metricsCache.put(node, updater); - return updater; } } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java index 5693819ac56..0994425f2e9 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricUpdater.java @@ -24,28 +24,22 @@ import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; import java.util.Set; -import java.util.concurrent.TimeUnit; import net.jcip.annotations.ThreadSafe; -import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Tag; @ThreadSafe public class MicroProfileNodeMetricUpdater extends MicroProfileMetricUpdater implements NodeMetricUpdater { private final Node node; - private final Runnable signalMetricUpdated; public MicroProfileNodeMetricUpdater( Node node, InternalDriverContext context, Set enabledMetrics, - MetricRegistry registry, - Runnable signalMetricUpdated) { + MetricRegistry registry) { super(context, enabledMetrics, registry); this.node = node; - this.signalMetricUpdated = signalMetricUpdated; DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); @@ -81,40 +75,17 @@ public MicroProfileNodeMetricUpdater( } @Override - public void incrementCounter(NodeMetric metric, String profileName, long amount) { - signalMetricUpdated.run(); - super.incrementCounter(metric, profileName, amount); - } - - @Override - public void updateHistogram(NodeMetric metric, String profileName, long value) { - signalMetricUpdated.run(); - super.updateHistogram(metric, profileName, value); - } - - @Override - public void markMeter(NodeMetric metric, String profileName, long amount) { - signalMetricUpdated.run(); - super.markMeter(metric, profileName, amount); + protected MetricId getMetricId(NodeMetric metric) { + return context.getMetricIdGenerator().nodeMetricId(node, metric); } @Override - public void updateTimer(NodeMetric metric, String profileName, long duration, TimeUnit unit) { - signalMetricUpdated.run(); - super.updateTimer(metric, profileName, duration, unit); - } - - public void cleanupNodeMetrics() { - for (NodeMetric metric : metrics.keySet()) { - MetricId id = getMetricId(metric); - Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); - registry.remove(new MetricID(id.getName(), tags)); - } - metrics.clear(); + protected void startMetricsExpirationTimeout() { + super.startMetricsExpirationTimeout(); } @Override - protected MetricId getMetricId(NodeMetric metric) { - return context.getMetricIdGenerator().nodeMetricId(node, metric); + protected void cancelMetricsExpirationTimeout() { + super.cancelMetricsExpirationTimeout(); } } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java index 7fddc8f150e..f507f3e25d2 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileSessionMetricUpdater.java @@ -41,14 +41,14 @@ public MicroProfileSessionMetricUpdater( initializeGauge( DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE, profile, this::preparedStatementCacheSize); + initializeCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, profile); + initializeCounter(DefaultSessionMetric.THROTTLING_ERRORS, profile); + initializeCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, profile); + initializeTimer(DefaultSessionMetric.CQL_REQUESTS, profile); initializeTimer(DefaultSessionMetric.THROTTLING_DELAY, profile); initializeTimer(DseSessionMetric.CONTINUOUS_CQL_REQUESTS, profile); initializeTimer(DseSessionMetric.GRAPH_REQUESTS, profile); - - initializeCounter(DefaultSessionMetric.CQL_CLIENT_TIMEOUTS, profile); - initializeCounter(DefaultSessionMetric.THROTTLING_ERRORS, profile); - initializeCounter(DseSessionMetric.GRAPH_CLIENT_TIMEOUTS, profile); } @Override diff --git a/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java b/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java index e8a00c2dc8c..07b7e107ba3 100644 --- a/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java +++ b/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricsFactoryTest.java @@ -15,25 +15,20 @@ */ package com.datastax.oss.driver.internal.metrics.microprofile; -import static com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileMetricsFactory.LOWEST_ACCEPTABLE_EXPIRE_AFTER; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import ch.qos.logback.classic.Level; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.util.LoggerTest; +import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.time.Duration; import java.util.Collections; import java.util.List; import org.eclipse.microprofile.metrics.MetricRegistry; @@ -43,59 +38,6 @@ @RunWith(DataProviderRunner.class) public class MicroProfileMetricsFactoryTest { - private static final String LOG_PREFIX = "prefix"; - - @Test - public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { - // given - Duration expireAfter = LOWEST_ACCEPTABLE_EXPIRE_AFTER.minusMinutes(1); - LoggerTest.LoggerSetup logger = - LoggerTest.setupTestLogger(MicroProfileMetricsFactory.class, Level.WARN); - DriverExecutionProfile driverExecutionProfile = mock(DriverExecutionProfile.class); - - // when - when(driverExecutionProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); - MicroProfileMetricsFactory.getAndValidateEvictionTime(driverExecutionProfile, LOG_PREFIX); - - // then - verify(logger.appender, timeout(500).times(1)).doAppend(logger.loggingEventCaptor.capture()); - assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); - assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) - .contains( - String.format( - "[%s] Value too low for %s: %s. Forcing to %s instead.", - LOG_PREFIX, - DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), - expireAfter, - LOWEST_ACCEPTABLE_EXPIRE_AFTER)); - } - - @Test - @UseDataProvider(value = "acceptableEvictionTimes") - public void should_not_log_warning_when_provided_eviction_time_setting_is_acceptable( - Duration expireAfter) { - // given - LoggerTest.LoggerSetup logger = - LoggerTest.setupTestLogger(MicroProfileMetricsFactory.class, Level.WARN); - DriverExecutionProfile driverExecutionProfile = mock(DriverExecutionProfile.class); - - // when - when(driverExecutionProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(expireAfter); - MicroProfileMetricsFactory.getAndValidateEvictionTime(driverExecutionProfile, LOG_PREFIX); - - // then - verify(logger.appender, timeout(500).times(0)).doAppend(logger.loggingEventCaptor.capture()); - } - - @DataProvider - public static Object[][] acceptableEvictionTimes() { - return new Object[][] { - {LOWEST_ACCEPTABLE_EXPIRE_AFTER}, {LOWEST_ACCEPTABLE_EXPIRE_AFTER.plusMinutes(1)} - }; - } - @Test @UseDataProvider(value = "invalidRegistryTypes") public void should_throw_if_wrong_or_missing_registry_type( @@ -113,7 +55,7 @@ public void should_throw_if_wrong_or_missing_registry_type( // registry object is not a registry type when(context.getMetricRegistry()).thenReturn(registryObj); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(LOWEST_ACCEPTABLE_EXPIRE_AFTER); + .thenReturn(AbstractMetricUpdater.MIN_EXPIRE_AFTER); when(profile.getStringList(DefaultDriverOption.METRICS_SESSION_ENABLED)) .thenReturn(enabledMetrics); // then diff --git a/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricsUpdaterTest.java b/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricsUpdaterTest.java new file mode 100644 index 00000000000..81414b5de8e --- /dev/null +++ b/metrics/microprofile/src/test/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileNodeMetricsUpdaterTest.java @@ -0,0 +1,152 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.metrics.microprofile; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import ch.qos.logback.classic.Level; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; +import com.datastax.oss.driver.api.core.metrics.NodeMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; +import com.datastax.oss.driver.internal.core.util.LoggerTest; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import io.smallrye.metrics.MetricsRegistryImpl; +import java.time.Duration; +import java.util.Collections; +import java.util.Set; +import org.eclipse.microprofile.metrics.Gauge; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class MicroProfileNodeMetricsUpdaterTest { + + @Test + public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { + // given + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(AbstractMetricUpdater.class, Level.WARN); + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); + Duration expireAfter = AbstractMetricUpdater.MIN_EXPIRE_AFTER.minusMinutes(1); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(expireAfter); + + MicroProfileNodeMetricUpdater updater = + new MicroProfileNodeMetricUpdater( + node, context, enabledMetrics, new MetricsRegistryImpl()) { + @Override + protected void initializeGauge( + NodeMetric metric, DriverExecutionProfile profile, Gauge supplier) { + // do nothing + } + + @Override + protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + + @Override + protected void initializeTimer(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + }; + + // then + assertThat(updater.getExpireAfter()).isEqualTo(AbstractMetricUpdater.MIN_EXPIRE_AFTER); + verify(logger.appender, timeout(500).times(1)).doAppend(logger.loggingEventCaptor.capture()); + assertThat(logger.loggingEventCaptor.getValue().getMessage()).isNotNull(); + assertThat(logger.loggingEventCaptor.getValue().getFormattedMessage()) + .contains( + String.format( + "[prefix] Value too low for %s: %s. Forcing to %s instead.", + DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER.getPath(), + expireAfter, + AbstractMetricUpdater.MIN_EXPIRE_AFTER)); + } + + @Test + @UseDataProvider(value = "acceptableEvictionTimes") + public void should_not_log_warning_when_provided_eviction_time_setting_is_acceptable( + Duration expireAfter) { + // given + LoggerTest.LoggerSetup logger = + LoggerTest.setupTestLogger(AbstractMetricUpdater.class, Level.WARN); + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(expireAfter); + + MicroProfileNodeMetricUpdater updater = + new MicroProfileNodeMetricUpdater( + node, context, enabledMetrics, new MetricsRegistryImpl()) { + @Override + protected void initializeGauge( + NodeMetric metric, DriverExecutionProfile profile, Gauge supplier) { + // do nothing + } + + @Override + protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + + @Override + protected void initializeTimer(NodeMetric metric, DriverExecutionProfile profile) { + // do nothing + } + }; + + // then + assertThat(updater.getExpireAfter()).isEqualTo(expireAfter); + verify(logger.appender, timeout(500).times(0)).doAppend(logger.loggingEventCaptor.capture()); + } + + @DataProvider + public static Object[][] acceptableEvictionTimes() { + return new Object[][] { + {AbstractMetricUpdater.MIN_EXPIRE_AFTER}, + {AbstractMetricUpdater.MIN_EXPIRE_AFTER.plusMinutes(1)} + }; + } +} From 130fd257467f05e838bf23ce904733bc14936b79 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 22 Mar 2021 17:39:34 +0100 Subject: [PATCH 085/395] JAVA-2914: Transform node filter into a more flexible node distance evaluator (#1524) --- changelog/README.md | 1 + .../insights/ExecutionProfilesInfoFinder.java | 9 +- .../api/core/config/DefaultDriverOption.java | 11 ++ .../api/core/config/TypedDriverOption.java | 14 ++- .../loadbalancing/NodeDistanceEvaluator.java | 52 ++++++++ .../core/session/ProgrammaticArguments.java | 42 +++++++ .../api/core/session/SessionBuilder.java | 76 +++++++++++- .../core/context/DefaultDriverContext.java | 9 +- .../core/context/InternalDriverContext.java | 12 +- .../BasicLoadBalancingPolicy.java | 33 +++--- .../DefaultNodeDistanceEvaluatorHelper.java | 112 ++++++++++++++++++ .../helper/DefaultNodeFilterHelper.java | 96 --------------- ....java => NodeDistanceEvaluatorHelper.java} | 15 +-- .../NodeFilterToDistanceEvaluatorAdapter.java | 38 ++++++ core/src/main/resources/reference.conf | 21 ++++ .../insights/ExecutionProfileMockUtil.java | 4 +- .../context/MockedDriverContextFactory.java | 2 +- .../BasicLoadBalancingPolicyDistanceTest.java | 24 ++-- .../BasicLoadBalancingPolicyEventsTest.java | 23 ++-- .../BasicLoadBalancingPolicyInitTest.java | 15 +-- ...cInferringLoadBalancingPolicyInitTest.java | 14 +-- .../DefaultLoadBalancingPolicyInitTest.java | 16 +-- manual/core/load_balancing/README.md | 32 ++--- upgrade_guide/README.md | 44 +++++++ 24 files changed, 517 insertions(+), 198 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeDistanceEvaluatorHelper.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java rename core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/{NodeFilterHelper.java => NodeDistanceEvaluatorHelper.java} (76%) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterToDistanceEvaluatorAdapter.java diff --git a/changelog/README.md b/changelog/README.md index 707ec720e58..4a5c5399f04 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [improvement] JAVA-2914: Transform node filter into a more flexible node distance evaluator - [improvement] JAVA-2929: Revisit node-level metric eviction - [new feature] JAVA-2830: Add mapper support for Java streams - [bug] JAVA-2928: Generate counter increment/decrement constructs compatible with legacy C* diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfilesInfoFinder.java b/core/src/main/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfilesInfoFinder.java index a255b5b0de0..8e7a8e59982 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfilesInfoFinder.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfilesInfoFinder.java @@ -158,9 +158,12 @@ private LoadBalancingInfo getLoadBalancingInfo(DriverExecutionProfile driverExec "localDataCenter", driverExecutionProfile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)); } - options.put( - "filterFunction", - driverExecutionProfile.isDefined(DefaultDriverOption.LOAD_BALANCING_FILTER_CLASS)); + @SuppressWarnings("deprecation") + boolean hasNodeFiltering = + driverExecutionProfile.isDefined(DefaultDriverOption.LOAD_BALANCING_FILTER_CLASS) + || driverExecutionProfile.isDefined( + DefaultDriverOption.LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS); + options.put("filterFunction", hasNodeFiltering); ClassSettingDetails loadBalancingDetails = PackageUtil.getLoadBalancingDetails( driverExecutionProfile.getString(DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS)); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 150305dfea4..fde3e87857a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -97,7 +97,10 @@ public enum DefaultDriverOption implements DriverOption { * A custom filter to include/exclude nodes. * *

    Value-Type: {@link String} + * + * @deprecated use {@link #LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS} instead. */ + @Deprecated LOAD_BALANCING_FILTER_CLASS("basic.load-balancing-policy.filter.class"), /** @@ -852,6 +855,14 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: {@link String} */ METRICS_ID_GENERATOR_PREFIX("advanced.metrics.id-generator.prefix"), + + /** + * The class name of a custom {@link + * com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator}. + * + *

    Value-Type: {@link String} + */ + LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS("basic.load-balancing-policy.evaluator.class"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index d2687da68d7..094f928d83c 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -137,9 +137,21 @@ public String toString() { public static final TypedDriverOption LOAD_BALANCING_LOCAL_DATACENTER = new TypedDriverOption<>( DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, GenericType.STRING); - /** A custom filter to include/exclude nodes. */ + /** + * A custom filter to include/exclude nodes. + * + * @deprecated Use {@link #LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS} instead. + */ + @Deprecated public static final TypedDriverOption LOAD_BALANCING_FILTER_CLASS = new TypedDriverOption<>(DefaultDriverOption.LOAD_BALANCING_FILTER_CLASS, GenericType.STRING); + /** + * The class name of a custom {@link + * com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator}. + */ + public static final TypedDriverOption LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS = + new TypedDriverOption<>( + DefaultDriverOption.LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS, GenericType.STRING); /** The timeout to use for internal queries that run as part of the initialization process. */ public static final TypedDriverOption CONNECTION_INIT_QUERY_TIMEOUT = new TypedDriverOption<>( diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.java b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.java new file mode 100644 index 00000000000..21f610e3f21 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.java @@ -0,0 +1,52 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.loadbalancing; + +import com.datastax.oss.driver.api.core.metadata.Node; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +/** + * A pluggable {@link NodeDistance} evaluator. + * + *

    Node distance evaluators are recognized by all the driver built-in load balancing policies. + * They can be specified {@linkplain + * com.datastax.oss.driver.api.core.session.SessionBuilder#withNodeDistanceEvaluator(String, + * NodeDistanceEvaluator) programmatically} or through the configuration (with the {@code + * load-balancing-policy.evaluator.class} option). + * + * @see com.datastax.oss.driver.api.core.session.SessionBuilder#withNodeDistanceEvaluator(String, + * NodeDistanceEvaluator) + */ +@FunctionalInterface +public interface NodeDistanceEvaluator { + + /** + * Evaluates the distance to apply to the given node. + * + *

    This method will be invoked each time the {@link LoadBalancingPolicy} processes a topology + * or state change, and will be passed the node being inspected, and the local datacenter name (or + * null if none is defined). If it returns a non-null {@link NodeDistance}, the policy will + * suggest that distance for the node; if it returns null, the policy will assign a default + * distance instead, based on its internal algorithm for computing node distances. + * + * @param node The node to assign a new distance to. + * @param localDc The local datacenter name, if defined, or null otherwise. + * @return The {@link NodeDistance} to assign to the node, or null to let the policy decide. + */ + @Nullable + NodeDistance evaluateDistance(@NonNull Node node, @Nullable String localDc); +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java index 75a49fb3a59..9e4f034ef00 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.api.core.session; import com.datastax.oss.driver.api.core.auth.AuthProvider; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; @@ -23,6 +24,7 @@ import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; +import com.datastax.oss.driver.internal.core.loadbalancing.helper.NodeFilterToDistanceEvaluatorAdapter; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import edu.umd.cs.findbugs.annotations.NonNull; @@ -30,6 +32,7 @@ import java.net.InetSocketAddress; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.UUID; import java.util.function.Predicate; @@ -52,6 +55,7 @@ public static Builder builder() { private final RequestTracker requestTracker; private final Map localDatacenters; private final Map> nodeFilters; + private final Map nodeDistanceEvaluators; private final ClassLoader classLoader; private final AuthProvider authProvider; private final SslEngineFactory sslEngineFactory; @@ -69,6 +73,7 @@ private ProgrammaticArguments( @Nullable RequestTracker requestTracker, @NonNull Map localDatacenters, @NonNull Map> nodeFilters, + @NonNull Map nodeDistanceEvaluators, @Nullable ClassLoader classLoader, @Nullable AuthProvider authProvider, @Nullable SslEngineFactory sslEngineFactory, @@ -85,6 +90,7 @@ private ProgrammaticArguments( this.requestTracker = requestTracker; this.localDatacenters = localDatacenters; this.nodeFilters = nodeFilters; + this.nodeDistanceEvaluators = nodeDistanceEvaluators; this.classLoader = classLoader; this.authProvider = authProvider; this.sslEngineFactory = sslEngineFactory; @@ -122,10 +128,17 @@ public Map getLocalDatacenters() { } @NonNull + @Deprecated + @SuppressWarnings("DeprecatedIsStillUsed") public Map> getNodeFilters() { return nodeFilters; } + @NonNull + public Map getNodeDistanceEvaluators() { + return nodeDistanceEvaluators; + } + @Nullable public ClassLoader getClassLoader() { return classLoader; @@ -180,6 +193,8 @@ public static class Builder { private ImmutableMap.Builder localDatacentersBuilder = ImmutableMap.builder(); private final ImmutableMap.Builder> nodeFiltersBuilder = ImmutableMap.builder(); + private final ImmutableMap.Builder + nodeDistanceEvaluatorsBuilder = ImmutableMap.builder(); private ClassLoader classLoader; private AuthProvider authProvider; private SslEngineFactory sslEngineFactory; @@ -236,16 +251,42 @@ public Builder withLocalDatacenters(Map localDatacenters) { } @NonNull + public Builder withNodeDistanceEvaluator( + @NonNull String profileName, @NonNull NodeDistanceEvaluator nodeDistanceEvaluator) { + this.nodeDistanceEvaluatorsBuilder.put(profileName, nodeDistanceEvaluator); + return this; + } + + @NonNull + public Builder withNodeDistanceEvaluators( + Map nodeDistanceReporters) { + for (Entry entry : nodeDistanceReporters.entrySet()) { + this.nodeDistanceEvaluatorsBuilder.put(entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * @deprecated Use {@link #withNodeDistanceEvaluator(String, NodeDistanceEvaluator)} instead. + */ + @NonNull + @Deprecated public Builder withNodeFilter( @NonNull String profileName, @NonNull Predicate nodeFilter) { this.nodeFiltersBuilder.put(profileName, nodeFilter); + this.nodeDistanceEvaluatorsBuilder.put( + profileName, new NodeFilterToDistanceEvaluatorAdapter(nodeFilter)); return this; } + /** @deprecated Use {@link #withNodeDistanceEvaluators(Map)} instead. */ @NonNull + @Deprecated public Builder withNodeFilters(Map> nodeFilters) { for (Map.Entry> entry : nodeFilters.entrySet()) { this.nodeFiltersBuilder.put(entry.getKey(), entry.getValue()); + this.nodeDistanceEvaluatorsBuilder.put( + entry.getKey(), new NodeFilterToDistanceEvaluatorAdapter(entry.getValue())); } return this; } @@ -313,6 +354,7 @@ public ProgrammaticArguments build() { requestTracker, localDatacentersBuilder.build(), nodeFiltersBuilder.build(), + nodeDistanceEvaluatorsBuilder.build(), classLoader, authProvider, sslEngineFactory, diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index abe28786b62..990044b66c9 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -25,6 +25,7 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeStateListener; @@ -389,6 +390,36 @@ public SelfT withLocalDatacenter(@NonNull String localDatacenter) { return withLocalDatacenter(DriverExecutionProfile.DEFAULT_NAME, localDatacenter); } + /** + * Adds a custom {@link NodeDistanceEvaluator} for a particular execution profile. This assumes + * that you're also using a dedicated load balancing policy for that profile. + * + *

    Node distance evaluators are honored by all the driver built-in load balancing policies. If + * you use a custom policy implementation however, you'll need to explicitly invoke the evaluator + * whenever appropriate. + * + *

    If an evaluator is specified programmatically with this method, it overrides the + * configuration (that is, the {@code load-balancing-policy.evaluator.class} option will be + * ignored). + * + * @see #withNodeDistanceEvaluator(NodeDistanceEvaluator) + */ + @NonNull + public SelfT withNodeDistanceEvaluator( + @NonNull String profileName, @NonNull NodeDistanceEvaluator nodeDistanceEvaluator) { + this.programmaticArgumentsBuilder.withNodeDistanceEvaluator(profileName, nodeDistanceEvaluator); + return self; + } + + /** + * Alias to {@link #withNodeDistanceEvaluator(String, NodeDistanceEvaluator)} for the default + * profile. + */ + @NonNull + public SelfT withNodeDistanceEvaluator(@NonNull NodeDistanceEvaluator nodeDistanceEvaluator) { + return withNodeDistanceEvaluator(DriverExecutionProfile.DEFAULT_NAME, nodeDistanceEvaluator); + } + /** * Adds a custom filter to include/exclude nodes for a particular execution profile. This assumes * that you're also using a dedicated load balancing policy for that profile. @@ -398,21 +429,60 @@ public SelfT withLocalDatacenter(@NonNull String localDatacenter) { * policy will suggest distance IGNORED (meaning the driver won't ever connect to it if all * policies agree), and never included in any query plan. * - *

    Note that this behavior is implemented in the default load balancing policy. If you use a - * custom policy implementation, you'll need to explicitly invoke the filter. + *

    Note that this behavior is implemented in the driver built-in load balancing policies. If + * you use a custom policy implementation, you'll need to explicitly invoke the filter. * *

    If the filter is specified programmatically with this method, it overrides the configuration * (that is, the {@code load-balancing-policy.filter.class} option will be ignored). * + *

    This method has been deprecated in favor of {@link + * #withNodeDistanceEvaluator(String, NodeDistanceEvaluator)}. If you were using node + * filters, you can easily replace your filters with the following implementation of {@link + * NodeDistanceEvaluator}: + * + *

    {@code
    +   * public class NodeFilterToDistanceEvaluatorAdapter implements NodeDistanceEvaluator {
    +   *
    +   *   private final Predicate nodeFilter;
    +   *
    +   *   public NodeFilterToDistanceEvaluatorAdapter(Predicate nodeFilter) {
    +   *     this.nodeFilter = nodeFilter;
    +   *   }
    +   *
    +   *   public NodeDistance evaluateDistance(Node node, String localDc) {
    +   *     return nodeFilter.test(node) ? null : NodeDistance.IGNORED;
    +   *   }
    +   * }
    +   * }
    + * + * The same can be achieved using a lambda + closure: + * + *
    {@code
    +   * Predicate nodeFilter = ...
    +   * NodeDistanceEvaluator evaluator =
    +   *   (node, localDc) -> nodeFilter.test(node) ? null : NodeDistance.IGNORED;
    +   * }
    + * * @see #withNodeFilter(Predicate) + * @deprecated Use {@link #withNodeDistanceEvaluator(String, NodeDistanceEvaluator)} instead. */ + @Deprecated @NonNull public SelfT withNodeFilter(@NonNull String profileName, @NonNull Predicate nodeFilter) { this.programmaticArgumentsBuilder.withNodeFilter(profileName, nodeFilter); return self; } - /** Alias to {@link #withNodeFilter(String, Predicate)} for the default profile. */ + /** + * Alias to {@link #withNodeFilter(String, Predicate)} for the default profile. + * + *

    This method has been deprecated in favor of {@link + * #withNodeDistanceEvaluator(NodeDistanceEvaluator)}. See the javadocs of {@link + * #withNodeFilter(String, Predicate)} to understand how to migrate your legacy node filters. + * + * @deprecated Use {@link #withNodeDistanceEvaluator(NodeDistanceEvaluator)} instead. + */ + @Deprecated @NonNull public SelfT withNodeFilter(@NonNull Predicate nodeFilter) { return withNodeFilter(DriverExecutionProfile.DEFAULT_NAME, nodeFilter); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index 8cbe488253b..64925699a64 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -31,6 +31,7 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.connection.ReconnectionPolicy; import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; @@ -223,7 +224,7 @@ public class DefaultDriverContext implements InternalDriverContext { private final SchemaChangeListener schemaChangeListenerFromBuilder; private final RequestTracker requestTrackerFromBuilder; private final Map localDatacentersFromBuilder; - private final Map> nodeFiltersFromBuilder; + private final Map nodeDistanceEvaluatorsFromBuilder; private final ClassLoader classLoader; private final InetSocketAddress cloudProxyAddress; private final LazyReference requestLogFormatterRef = @@ -275,7 +276,7 @@ public DefaultDriverContext( "sslEngineFactory", () -> buildSslEngineFactory(programmaticArguments.getSslEngineFactory()), cycleDetector); - this.nodeFiltersFromBuilder = programmaticArguments.getNodeFilters(); + this.nodeDistanceEvaluatorsFromBuilder = programmaticArguments.getNodeDistanceEvaluators(); this.classLoader = programmaticArguments.getClassLoader(); this.cloudProxyAddress = programmaticArguments.getCloudProxyAddress(); this.startupClientId = programmaticArguments.getStartupClientId(); @@ -908,8 +909,8 @@ public String getLocalDatacenter(@NonNull String profileName) { @Nullable @Override - public Predicate getNodeFilter(@NonNull String profileName) { - return nodeFiltersFromBuilder.get(profileName); + public NodeDistanceEvaluator getNodeDistanceEvaluator(@NonNull String profileName) { + return nodeDistanceEvaluatorsFromBuilder.get(profileName); } @Nullable diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java index 0bfc07d73a2..3e3f21d0e41 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java @@ -16,7 +16,7 @@ package com.datastax.oss.driver.internal.core.context; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.ProtocolVersionRegistry; @@ -49,7 +49,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Predicate; /** Extends the driver context with additional components that are not exposed by our public API. */ public interface InternalDriverContext extends DriverContext { @@ -138,12 +137,13 @@ public interface InternalDriverContext extends DriverContext { String getLocalDatacenter(@NonNull String profileName); /** - * This is the filter from {@link SessionBuilder#withNodeFilter(String, Predicate)}. If the filter - * for this profile was specified through the configuration instead, this method will return - * {@code null}. + * This is the node distance evaluator from {@link + * SessionBuilder#withNodeDistanceEvaluator(String, NodeDistanceEvaluator)}. If the evaluator for + * this profile was specified through the configuration instead, this method will return {@code + * null}. */ @Nullable - Predicate getNodeFilter(@NonNull String profileName); + NodeDistanceEvaluator getNodeDistanceEvaluator(@NonNull String profileName); /** * The {@link ClassLoader} to use to reflectively load class names defined in configuration. If diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java index dd9b4145b18..395412272ce 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java @@ -23,6 +23,7 @@ import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeState; import com.datastax.oss.driver.api.core.metadata.TokenMap; @@ -30,7 +31,7 @@ import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.loadbalancing.helper.DefaultNodeFilterHelper; +import com.datastax.oss.driver.internal.core.loadbalancing.helper.DefaultNodeDistanceEvaluatorHelper; import com.datastax.oss.driver.internal.core.loadbalancing.helper.OptionalLocalDcHelper; import com.datastax.oss.driver.internal.core.loadbalancing.nodeset.DcAgnosticNodeSet; import com.datastax.oss.driver.internal.core.loadbalancing.nodeset.MultiDcNodeSet; @@ -53,7 +54,6 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntUnaryOperator; -import java.util.function.Predicate; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -111,7 +111,7 @@ public class BasicLoadBalancingPolicy implements LoadBalancingPolicy { // private because they should be set in init() and never be modified after private volatile DistanceReporter distanceReporter; - private volatile Predicate filter; + private volatile NodeDistanceEvaluator nodeDistanceEvaluator; private volatile String localDc; private volatile NodeSet liveNodes; @@ -155,7 +155,7 @@ protected NodeSet getLiveNodes() { public void init(@NonNull Map nodes, @NonNull DistanceReporter distanceReporter) { this.distanceReporter = distanceReporter; localDc = discoverLocalDc(nodes).orElse(null); - filter = createNodeFilter(localDc, nodes); + nodeDistanceEvaluator = createNodeDistanceEvaluator(localDc, nodes); liveNodes = localDc == null ? new DcAgnosticNodeSet() @@ -200,7 +200,7 @@ protected Optional discoverLocalDc(@NonNull Map nodes) { } /** - * Creates a new node filter to use with this policy. + * Creates a new node distance evaluator to use with this policy. * *

    This method is called only once, during {@linkplain LoadBalancingPolicy#init(Map, * LoadBalancingPolicy.DistanceReporter) initialization}, and only after local datacenter @@ -209,14 +209,14 @@ protected Optional discoverLocalDc(@NonNull Map nodes) { * @param localDc The local datacenter that was just discovered, or null if none found. * @param nodes All the nodes that were known to exist in the cluster (regardless of their state) * when the load balancing policy was initialized. This argument is provided in case - * implementors need to inspect the cluster topology to create the node filter. - * @return the node filter to use. + * implementors need to inspect the cluster topology to create the evaluator. + * @return the distance evaluator to use. */ @NonNull - protected Predicate createNodeFilter( + protected NodeDistanceEvaluator createNodeDistanceEvaluator( @Nullable String localDc, @NonNull Map nodes) { - return new DefaultNodeFilterHelper(context, profile, logPrefix) - .createNodeFilter(localDc, nodes); + return new DefaultNodeDistanceEvaluatorHelper(context, profile, logPrefix) + .createNodeDistanceEvaluator(localDc, nodes); } @NonNull @@ -399,20 +399,21 @@ public void onRemove(@NonNull Node node) { * a node {@linkplain #onAdd(Node) is added}, and when a node {@linkplain #onUp(Node) is back UP}. */ protected NodeDistance computeNodeDistance(@NonNull Node node) { - // We interrogate the filter every time since it could be dynamic + // We interrogate the custom evaluator every time since it could be dynamic // and change its verdict between two invocations of this method. - if (!filter.test(node)) { - return NodeDistance.IGNORED; + NodeDistance distance = nodeDistanceEvaluator.evaluateDistance(node, localDc); + if (distance != null) { + return distance; } - // no local DC is defined, all nodes accepted by the filter are LOCAL. + // no local DC defined: all nodes are considered LOCAL. if (localDc == null) { return NodeDistance.LOCAL; } - // the node is LOCAL if its datacenter is the local datacenter. + // otherwise, the node is LOCAL if its datacenter is the local datacenter. if (Objects.equals(node.getDatacenter(), localDc)) { return NodeDistance.LOCAL; } - // otherwise the node will be either REMOTE or IGNORED, depending + // otherwise, the node will be either REMOTE or IGNORED, depending // on how many remote nodes we accept per DC. if (maxNodesPerRemoteDc > 0) { Object[] remoteNodes = liveNodes.dc(node.getDatacenter()).toArray(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeDistanceEvaluatorHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeDistanceEvaluatorHelper.java new file mode 100644 index 00000000000..446533b23c7 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeDistanceEvaluatorHelper.java @@ -0,0 +1,112 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.helper; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.util.Reflection; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Map; +import java.util.UUID; +import java.util.function.Predicate; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link NodeDistanceEvaluatorHelper} implementation that fetches the user-supplied evaluator, if + * any, from the programmatic configuration API, or else, from the driver configuration. If no + * user-supplied evaluator can be retrieved, a dummy evaluator will be used which always evaluates + * null distances. + */ +@ThreadSafe +public class DefaultNodeDistanceEvaluatorHelper implements NodeDistanceEvaluatorHelper { + + private static final Logger LOG = + LoggerFactory.getLogger(DefaultNodeDistanceEvaluatorHelper.class); + + @NonNull protected final InternalDriverContext context; + @NonNull protected final DriverExecutionProfile profile; + @NonNull protected final String logPrefix; + + public DefaultNodeDistanceEvaluatorHelper( + @NonNull InternalDriverContext context, + @NonNull DriverExecutionProfile profile, + @NonNull String logPrefix) { + this.context = context; + this.profile = profile; + this.logPrefix = logPrefix; + } + + @NonNull + @Override + public NodeDistanceEvaluator createNodeDistanceEvaluator( + @Nullable String localDc, @NonNull Map nodes) { + NodeDistanceEvaluator nodeDistanceEvaluatorFromConfig = nodeDistanceEvaluatorFromConfig(); + return (node, dc) -> { + NodeDistance distance = nodeDistanceEvaluatorFromConfig.evaluateDistance(node, dc); + if (distance != null) { + LOG.debug("[{}] Evaluator assigned distance {} to node {}", logPrefix, distance, node); + } else { + LOG.debug("[{}] Evaluator did not assign a distance to node {}", logPrefix, node); + } + return distance; + }; + } + + @NonNull + protected NodeDistanceEvaluator nodeDistanceEvaluatorFromConfig() { + NodeDistanceEvaluator evaluator = context.getNodeDistanceEvaluator(profile.getName()); + if (evaluator != null) { + LOG.debug("[{}] Node distance evaluator set programmatically", logPrefix); + } else { + evaluator = + Reflection.buildFromConfig( + context, + profile.getName(), + DefaultDriverOption.LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS, + NodeDistanceEvaluator.class) + .orElse(null); + if (evaluator != null) { + LOG.debug("[{}] Node distance evaluator set from configuration", logPrefix); + } else { + @SuppressWarnings({"unchecked", "deprecation"}) + Predicate nodeFilterFromConfig = + Reflection.buildFromConfig( + context, + profile.getName(), + DefaultDriverOption.LOAD_BALANCING_FILTER_CLASS, + Predicate.class) + .orElse(null); + if (nodeFilterFromConfig != null) { + evaluator = new NodeFilterToDistanceEvaluatorAdapter(nodeFilterFromConfig); + LOG.debug( + "[{}] Node distance evaluator set from deprecated node filter configuration", + logPrefix); + } + } + } + if (evaluator == null) { + evaluator = PASS_THROUGH_DISTANCE_EVALUATOR; + } + return evaluator; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java deleted file mode 100644 index 9eae21589ed..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/DefaultNodeFilterHelper.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.internal.core.loadbalancing.helper; - -import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.internal.core.context.InternalDriverContext; -import com.datastax.oss.driver.internal.core.util.Reflection; -import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.Nullable; -import java.util.Map; -import java.util.UUID; -import java.util.function.Predicate; -import net.jcip.annotations.ThreadSafe; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A {@link NodeFilterHelper} implementation that fetches the user-supplied filter, if any, from the - * programmatic configuration API, or else, from the driver configuration. If no user-supplied - * filter can be retrieved, a dummy filter will be used which accepts all nodes unconditionally. - * - *

    Note that, regardless of the filter supplied by the end user, if a local datacenter is defined - * the filter returned by this implementation will always reject nodes that report a datacenter - * different from the local one. - */ -@ThreadSafe -public class DefaultNodeFilterHelper implements NodeFilterHelper { - - private static final Logger LOG = LoggerFactory.getLogger(DefaultNodeFilterHelper.class); - - @NonNull protected final InternalDriverContext context; - @NonNull protected final DriverExecutionProfile profile; - @NonNull protected final String logPrefix; - - public DefaultNodeFilterHelper( - @NonNull InternalDriverContext context, - @NonNull DriverExecutionProfile profile, - @NonNull String logPrefix) { - this.context = context; - this.profile = profile; - this.logPrefix = logPrefix; - } - - @NonNull - @Override - public Predicate createNodeFilter( - @Nullable String localDc, @NonNull Map nodes) { - Predicate filterFromConfig = nodeFilterFromConfig(); - return node -> { - if (!filterFromConfig.test(node)) { - LOG.debug( - "[{}] Ignoring {} because it doesn't match the user-provided predicate", - logPrefix, - node); - return false; - } else { - return true; - } - }; - } - - @NonNull - protected Predicate nodeFilterFromConfig() { - Predicate filter = context.getNodeFilter(profile.getName()); - if (filter != null) { - LOG.debug("[{}] Node filter set programmatically", logPrefix); - } else { - @SuppressWarnings("unchecked") - Predicate filterFromConfig = - Reflection.buildFromConfig( - context, - profile.getName(), - DefaultDriverOption.LOAD_BALANCING_FILTER_CLASS, - Predicate.class) - .orElse(INCLUDE_ALL_NODES); - filter = filterFromConfig; - LOG.debug("[{}] Node filter set from configuration", logPrefix); - } - return filter; - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeDistanceEvaluatorHelper.java similarity index 76% rename from core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterHelper.java rename to core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeDistanceEvaluatorHelper.java index 2b082bfe324..76256db94e1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterHelper.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeDistanceEvaluatorHelper.java @@ -16,30 +16,31 @@ package com.datastax.oss.driver.internal.core.loadbalancing.helper; import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.metadata.Node; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Map; import java.util.UUID; -import java.util.function.Predicate; import net.jcip.annotations.ThreadSafe; @FunctionalInterface @ThreadSafe -public interface NodeFilterHelper { +public interface NodeDistanceEvaluatorHelper { - Predicate INCLUDE_ALL_NODES = n -> true; + NodeDistanceEvaluator PASS_THROUGH_DISTANCE_EVALUATOR = (node, localDc) -> null; /** - * Creates a new node filter. + * Creates a new node distance evaluator. * * @param localDc The local datacenter, or null if none defined. * @param nodes All the nodes that were known to exist in the cluster (regardless of their state) * when the load balancing policy was {@linkplain LoadBalancingPolicy#init(Map, * LoadBalancingPolicy.DistanceReporter) initialized}. This argument is provided in case - * implementors need to inspect the cluster topology to create the node filter. - * @return the node filter to use. + * implementors need to inspect the cluster topology to create the node distance evaluator. + * @return the node distance evaluator to use. */ @NonNull - Predicate createNodeFilter(@Nullable String localDc, @NonNull Map nodes); + NodeDistanceEvaluator createNodeDistanceEvaluator( + @Nullable String localDc, @NonNull Map nodes); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterToDistanceEvaluatorAdapter.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterToDistanceEvaluatorAdapter.java new file mode 100644 index 00000000000..f95ad626f5a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/NodeFilterToDistanceEvaluatorAdapter.java @@ -0,0 +1,38 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing.helper; + +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; +import com.datastax.oss.driver.api.core.metadata.Node; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.function.Predicate; + +public class NodeFilterToDistanceEvaluatorAdapter implements NodeDistanceEvaluator { + + private final Predicate nodeFilter; + + public NodeFilterToDistanceEvaluatorAdapter(@NonNull Predicate nodeFilter) { + this.nodeFilter = nodeFilter; + } + + @Nullable + @Override + public NodeDistance evaluateDistance(@NonNull Node node, @Nullable String localDc) { + return nodeFilter.test(node) ? null : NodeDistance.IGNORED; + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 49ae947d556..ffbc6caebac 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -194,6 +194,27 @@ datastax-java-driver { # are specified, the programmatic value takes precedence. // local-datacenter = datacenter1 + # The class of a custom node distance evaluator. + # + # This option is not required; if present, it must be the fully-qualified name of a class that + # implements `com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator`, and has a + # public constructor taking two arguments: the DriverContext and a String representing the + # profile name. + # + # Alternatively, you can pass an instance of your distance evaluator to + # CqlSession.builder().withNodeDistanceEvaluator(). In that case, this option will be ignored. + # + # The evaluator will be invoked each time the policy processes a topology or state change. The + # evaluator's `evaluateDistance` method will be called with the node affected by the change, and + # the local datacenter name (or null if none is defined). If it returns a non-null distance, the + # policy will suggest that distance for the node; if the function returns null, the policy will + # will assign a default distance instead, based on its internal algorithm for computing node + # distances. + // evaluator.class= + + # DEPRECATED. Use evaluator.class instead (see above). If both evaluator.class and filter.class + # are defined, the former wins. + # # A custom filter to include/exclude nodes. # # This option is not required; if present, it must be the fully-qualified name of a class that diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfileMockUtil.java b/core/src/test/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfileMockUtil.java index de8a4693d5e..ac176ebcc64 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfileMockUtil.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/insights/ExecutionProfileMockUtil.java @@ -20,7 +20,7 @@ import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE; import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.CONNECTION_POOL_REMOTE_SIZE; import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.HEARTBEAT_INTERVAL; -import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.LOAD_BALANCING_FILTER_CLASS; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS; import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER; import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS; import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.PROTOCOL_COMPRESSION; @@ -50,7 +50,7 @@ static DriverExecutionProfile mockDefaultExecutionProfile() { when(profile.getDuration(REQUEST_TIMEOUT)).thenReturn(Duration.ofMillis(100)); when(profile.getString(LOAD_BALANCING_POLICY_CLASS)).thenReturn("LoadBalancingPolicyImpl"); - when(profile.isDefined(LOAD_BALANCING_FILTER_CLASS)).thenReturn(true); + when(profile.isDefined(LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS)).thenReturn(true); when(profile.isDefined(LOAD_BALANCING_LOCAL_DATACENTER)).thenReturn(true); when(profile.getString(LOAD_BALANCING_LOCAL_DATACENTER)).thenReturn(DEFAULT_LOCAL_DC); when(profile.isDefined(SPECULATIVE_EXECUTION_MAX)).thenReturn(true); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java index 580f558dc33..126345f4716 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java @@ -67,7 +67,7 @@ public static DefaultDriverContext defaultDriverContext( .withSchemaChangeListener(mock(SchemaChangeListener.class)) .withRequestTracker(mock(RequestTracker.class)) .withLocalDatacenters(Maps.newHashMap()) - .withNodeFilters(Maps.newHashMap()) + .withNodeDistanceEvaluators(Maps.newHashMap()) .build(); return new DefaultDriverContext(configLoader, args); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java index 762720ac014..d327410a93f 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyDistanceTest.java @@ -23,12 +23,12 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.UUID; -import java.util.function.Predicate; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,7 +39,7 @@ @RunWith(MockitoJUnitRunner.Silent.class) public class BasicLoadBalancingPolicyDistanceTest extends LoadBalancingPolicyTestBase { - @Mock private Predicate filter; + @Mock private NodeDistanceEvaluator nodeDistanceEvaluator; private ImmutableMap nodes; @@ -47,11 +47,8 @@ public class BasicLoadBalancingPolicyDistanceTest extends LoadBalancingPolicyTes @Override public void setup() { super.setup(); - when(filter.test(node1)).thenReturn(true); - when(filter.test(node2)).thenReturn(true); - when(filter.test(node3)).thenReturn(true); - when(filter.test(node4)).thenReturn(true); - when(context.getNodeFilter(DriverExecutionProfile.DEFAULT_NAME)).thenReturn(filter); + when(context.getNodeDistanceEvaluator(DriverExecutionProfile.DEFAULT_NAME)) + .thenReturn(nodeDistanceEvaluator); when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2, node3)); nodes = ImmutableMap.of( @@ -59,15 +56,20 @@ public void setup() { } @Test - public void should_report_IGNORED_when_excluded_by_filter() { + public void should_report_distance_reported_by_user_distance_reporter() { // Given - given(filter.test(node1)).willReturn(false); + given(node2.getDatacenter()).willReturn("dc2"); + given(nodeDistanceEvaluator.evaluateDistance(node1, "dc1")).willReturn(NodeDistance.LOCAL); + given(nodeDistanceEvaluator.evaluateDistance(node2, "dc1")).willReturn(NodeDistance.REMOTE); + given(nodeDistanceEvaluator.evaluateDistance(node3, "dc1")).willReturn(NodeDistance.IGNORED); BasicLoadBalancingPolicy policy = createPolicy(); // When policy.init(nodes, distanceReporter); // Then - verify(distanceReporter).setDistance(node1, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node2, node3); + verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node2, NodeDistance.REMOTE); + verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java index 6640b2b946c..07723446027 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyEventsTest.java @@ -25,12 +25,11 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; -import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.UUID; -import java.util.function.Predicate; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,7 +40,7 @@ @RunWith(MockitoJUnitRunner.Silent.class) public class BasicLoadBalancingPolicyEventsTest extends LoadBalancingPolicyTestBase { - @Mock private Predicate filter; + @Mock private NodeDistanceEvaluator nodeDistanceEvaluator; private BasicLoadBalancingPolicy policy; @@ -49,8 +48,8 @@ public class BasicLoadBalancingPolicyEventsTest extends LoadBalancingPolicyTestB @Override public void setup() { super.setup(); - when(filter.test(any(Node.class))).thenReturn(true); - when(context.getNodeFilter(DriverExecutionProfile.DEFAULT_NAME)).thenReturn(filter); + when(context.getNodeDistanceEvaluator(DriverExecutionProfile.DEFAULT_NAME)) + .thenReturn(nodeDistanceEvaluator); when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1)); policy = createAndInitPolicy(); reset(distanceReporter); @@ -65,7 +64,7 @@ public void should_remove_down_node_from_live_set() { assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); verify(distanceReporter, never()).setDistance(eq(node2), any(NodeDistance.class)); // should have been called only once, during initialization, but not during onDown - verify(filter).test(node2); + verify(nodeDistanceEvaluator).evaluateDistance(node2, "dc1"); } @Test @@ -77,7 +76,7 @@ public void should_remove_removed_node_from_live_set() { assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); verify(distanceReporter, never()).setDistance(eq(node2), any(NodeDistance.class)); // should have been called only once, during initialization, but not during onRemove - verify(filter).test(node2); + verify(nodeDistanceEvaluator).evaluateDistance(node2, "dc1"); } @Test @@ -87,7 +86,7 @@ public void should_set_added_node_to_local() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); - verify(filter).test(node3); + verify(nodeDistanceEvaluator).evaluateDistance(node3, "dc1"); // Not added to the live set yet, we're waiting for the pool to open assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); } @@ -95,7 +94,7 @@ public void should_set_added_node_to_local() { @Test public void should_ignore_added_node_when_filtered() { // Given - when(filter.test(node3)).thenReturn(false); + when(nodeDistanceEvaluator.evaluateDistance(node3, "dc1")).thenReturn(NodeDistance.IGNORED); // When policy.onAdd(node3); @@ -126,21 +125,21 @@ public void should_add_up_node_to_live_set() { // Then verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); - verify(filter).test(node3); + verify(nodeDistanceEvaluator).evaluateDistance(node3, "dc1"); assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3); } @Test public void should_ignore_up_node_when_filtered() { // Given - when(filter.test(node3)).thenReturn(false); + when(nodeDistanceEvaluator.evaluateDistance(node3, "dc1")).thenReturn(NodeDistance.IGNORED); // When policy.onUp(node3); // Then verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - verify(filter).test(node3); + verify(nodeDistanceEvaluator).evaluateDistance(node3, "dc1"); assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java index 56caff5c0aa..7fd16361817 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyInitTest.java @@ -195,10 +195,11 @@ public void should_not_ignore_nodes_from_remote_dcs_if_local_dc_not_set() { } @Test - public void should_ignore_nodes_excluded_by_filter() { + public void should_ignore_nodes_excluded_by_distance_reporter() { // Given - when(context.getNodeFilter(DriverExecutionProfile.DEFAULT_NAME)) - .thenReturn(node -> node.equals(node1)); + when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2)); + when(context.getNodeDistanceEvaluator(DriverExecutionProfile.DEFAULT_NAME)) + .thenReturn((node, dc) -> node.equals(node1) ? NodeDistance.IGNORED : null); BasicLoadBalancingPolicy policy = createPolicy(); @@ -209,10 +210,10 @@ public void should_ignore_nodes_excluded_by_filter() { distanceReporter); // Then - verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); - verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); - verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); + verify(distanceReporter).setDistance(node1, NodeDistance.IGNORED); + verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node2, node3); } @NonNull diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java index b57f0050985..e58d0e8b6bd 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java @@ -215,11 +215,11 @@ public void should_ignore_nodes_from_remote_dcs() { } @Test - public void should_ignore_nodes_excluded_by_filter() { + public void should_ignore_nodes_excluded_by_distance_reporter() { // Given when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2)); - when(context.getNodeFilter(DriverExecutionProfile.DEFAULT_NAME)) - .thenReturn(node -> node.equals(node1)); + when(context.getNodeDistanceEvaluator(DriverExecutionProfile.DEFAULT_NAME)) + .thenReturn((node, dc) -> node.equals(node1) ? NodeDistance.IGNORED : null); BasicLoadBalancingPolicy policy = createPolicy(); @@ -230,10 +230,10 @@ public void should_ignore_nodes_excluded_by_filter() { distanceReporter); // Then - verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); - verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); - verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); + verify(distanceReporter).setDistance(node1, NodeDistance.IGNORED); + verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node2, node3); } @NonNull diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java index c6202c3432b..6efe9661d89 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java @@ -185,13 +185,13 @@ public void should_ignore_nodes_from_remote_dcs() { } @Test - public void should_ignore_nodes_excluded_by_filter() { + public void should_ignore_nodes_excluded_by_distance_reporter() { // Given when(metadataManager.getContactPoints()).thenReturn(ImmutableSet.of(node1, node2)); - when(context.getNodeFilter(DriverExecutionProfile.DEFAULT_NAME)) - .thenReturn(node -> node.equals(node1)); + when(context.getNodeDistanceEvaluator(DriverExecutionProfile.DEFAULT_NAME)) + .thenReturn((node, dc) -> node.equals(node1) ? NodeDistance.IGNORED : null); - DefaultLoadBalancingPolicy policy = createPolicy(); + BasicLoadBalancingPolicy policy = createPolicy(); // When policy.init( @@ -200,10 +200,10 @@ public void should_ignore_nodes_excluded_by_filter() { distanceReporter); // Then - verify(distanceReporter).setDistance(node1, NodeDistance.LOCAL); - verify(distanceReporter).setDistance(node2, NodeDistance.IGNORED); - verify(distanceReporter).setDistance(node3, NodeDistance.IGNORED); - assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1); + verify(distanceReporter).setDistance(node1, NodeDistance.IGNORED); + verify(distanceReporter).setDistance(node2, NodeDistance.LOCAL); + verify(distanceReporter).setDistance(node3, NodeDistance.LOCAL); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node2, node3); } @NonNull diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index 3d09f0282b6..cb9dde4196c 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -346,37 +346,40 @@ nodes in query plans will likely fail, causing the query plans to eventually try instead. If the local datacenter unavailability persists, local nodes will be eventually marked down and will be removed from query plans completely from query plans, until they are back up again. -#### Optional node filtering +#### Customizing node distance assignment -Finally, the default policy accepts an optional node filter that gets applied just after the test -for inclusion in the local DC. If a node doesn't pass this test, it will be set at distance -`IGNORED` and the driver will never try to connect to it. This is a good way to exclude nodes on -some custom criteria. +Finally, all the driver the built-in policies accept an optional node distance evaluator that gets +invoked each time a node is added to the cluster or comes back up. If the evaluator returns a +non-null distance for the node, that distance will be used, otherwise the driver will use its +built-in logic to assign a default distance to it. This is a good way to exclude nodes or to adjust +their distance according to custom, dynamic criteria. -You can pass the filter through the configuration: +You can pass the node distance evaluator through the configuration: ``` datastax-java-driver.basic.load-balancing-policy { class = DefaultLoadBalancingPolicy local-datacenter = datacenter1 - filter-class = com.acme.MyNodeFilter + evaluator.class = com.acme.MyNodeDistanceEvaluator } ``` -The filter class must implement `java.util.function.predicate`, and have a public constructor -that takes a [DriverContext] argument: `public MyNodeFilter(DriverContext context)`. +The node distance evaluator class must implement [NodeDistanceEvaluator], and have a public +constructor that takes a [DriverContext] argument: `public MyNodeDistanceEvaluator(DriverContext +context)`. -Sometimes it's more convenient to pass the filter programmatically; you can do that with -`SessionBuilder.withNodeFilter`: +Sometimes it's more convenient to pass the evaluator programmatically; you can do that with +`SessionBuilder.withNodeDistanceEvaluator`: ```java -List whiteList = ... +Map distances = ... CqlSession session = CqlSession.builder() - .withNodeFilter(whiteList::contains) + .withNodeDistanceEvaluator((node, dc) -> distances.get(node)) .build(); ``` -If a programmatic filter is provided, the configuration option is ignored. +If a programmatic node distance evaluator evaluator is provided, the configuration option is +ignored. ### Custom implementation @@ -429,5 +432,6 @@ Then it uses the "closest" distance for any given node. For example: [getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- [getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- [getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 55166b5b60b..bf40f0fce47 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -24,6 +24,50 @@ are encouraged to try out the new `TaggingMetricIdGenerator`, as it generates me that will look more familiar to users of libraries such as Micrometer or MicroProfile Metrics (and look nicer when exported to Prometheus or Graphite). +#### New `NodeDistanceEvaluator` API + +All driver built-in load-balancing policies now accept a new optional component called +[NodeDistanceEvaluator]. This component gets invoked each time a node is added to the cluster or +comes back up. If the evaluator returns a non-null distance for the node, that distance will be +used, otherwise the driver will use its built-in logic to assign a default distance to it. + +[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html + +This component replaces the old "node filter" component. As a consequence, all `withNodeFilter` +methods in `SessionBuilder` are now deprecated and should be replaced by the equivalent +`withNodeDistanceEvaluator` methods. + +If you have an existing node filter implementation, it can be converted to a `NodeDistanceEvaluator` +very easily: + +```java +Predicate nodeFilter = ... +NodeDistanceEvaluator nodeEvaluator = + (node, dc) -> nodeFilter.test(node) ? null : NodeDistance.IGNORED; +``` + +The above can also be achieved by an adapter class as shown below: + +```java +public class NodeFilterToDistanceEvaluatorAdapter implements NodeDistanceEvaluator { + + private final Predicate nodeFilter; + + public NodeFilterToDistanceEvaluatorAdapter(@NonNull Predicate nodeFilter) { + this.nodeFilter = nodeFilter; + } + + @Nullable @Override + public NodeDistance evaluateDistance(@NonNull Node node, @Nullable String localDc) { + return nodeFilter.test(node) ? null : NodeDistance.IGNORED; + } +} +``` + +Finally, the `datastax-java-driver.basic.load-balancing-policy.filter.class` configuration option +has been deprecated; it should be replaced with a node distance evaluator class defined by the +`datastax-java-driver.basic.load-balancing-policy.evaluator.class` option instead. + ### 4.10.0 #### Cross-datacenter failover From f84648f9d77ac62ea5fbf493f52a1e823b337b87 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 22 Mar 2021 20:10:59 +0100 Subject: [PATCH 086/395] Fix flaky metrics integration tests --- .../oss/driver/core/metrics/DropwizardMetricsIT.java | 5 +++-- .../oss/driver/metrics/micrometer/MicrometerMetricsIT.java | 5 +++-- .../driver/metrics/microprofile/MicroProfileMetricsIT.java | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java index 57bda625ce2..9a769c3c02d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.metrics; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; @@ -95,7 +96,7 @@ protected void assertMetricsPresent(CqlSession session) { break; case CQL_REQUESTS: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).getCount()).isEqualTo(30); + await().untilAsserted(() -> assertThat(((Timer) m).getCount()).isEqualTo(30)); break; case CQL_PREPARED_CACHE_SIZE: assertThat(m).isInstanceOf(Gauge.class); @@ -144,7 +145,7 @@ protected void assertMetricsPresent(CqlSession session) { break; case CQL_MESSAGES: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).getCount()).isEqualTo(10); + await().untilAsserted(() -> assertThat(((Timer) m).getCount()).isEqualTo(10)); break; case READ_TIMEOUTS: case WRITE_TIMEOUTS: diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java index ddfc8913d63..8c546c239cd 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.metrics.micrometer; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Node; @@ -86,7 +87,7 @@ protected void assertMetricsPresent(CqlSession session) { break; case CQL_REQUESTS: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).count()).isEqualTo(30); + await().untilAsserted(() -> assertThat(((Timer) m).count()).isEqualTo(30)); break; case CQL_PREPARED_CACHE_SIZE: assertThat(m).isInstanceOf(Gauge.class); @@ -128,7 +129,7 @@ protected void assertMetricsPresent(CqlSession session) { break; case CQL_MESSAGES: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).count()).isEqualTo(10); + await().untilAsserted(() -> assertThat(((Timer) m).count()).isEqualTo(10)); break; case READ_TIMEOUTS: case WRITE_TIMEOUTS: diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java index 67a7f83c982..13d28936ad1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.metrics.microprofile; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Node; @@ -91,7 +92,7 @@ protected void assertMetricsPresent(CqlSession session) { break; case CQL_REQUESTS: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).getCount()).isEqualTo(30); + await().untilAsserted(() -> assertThat(((Timer) m).getCount()).isEqualTo(30)); break; case CQL_PREPARED_CACHE_SIZE: assertThat(m).isInstanceOf(Gauge.class); @@ -134,7 +135,7 @@ protected void assertMetricsPresent(CqlSession session) { break; case CQL_MESSAGES: assertThat(m).isInstanceOf(Timer.class); - assertThat(((Timer) m).getCount()).isEqualTo(10); + await().untilAsserted(() -> assertThat(((Timer) m).getCount()).isEqualTo(10)); break; case READ_TIMEOUTS: case WRITE_TIMEOUTS: From ef56d561d97adcae48e0e6e8807f334aedc0d783 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 23 Mar 2021 16:53:56 +0100 Subject: [PATCH 087/395] Minor enhancement to the documentation of metrics.node.expire-after option --- core/src/main/resources/reference.conf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index ffbc6caebac..26a6dbc3dcd 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1820,9 +1820,8 @@ datastax-java-driver { # The time after which the node level metrics will be evicted. # # This is used to unregister stale metrics if a node leaves the cluster or gets a new address. - # The eviction will happen only if none of the enabled node-level metrics is updated for a - # given node for a given time. When this interval elapses, all metrics for the idle node are - # removed. + # If the node does not come back up when this interval elapses, all its metrics are removed + # from the registry. # # The lowest allowed value is 5 minutes. If you try to set it lower, the driver will log a # warning and use 5 minutes. From 1f60c94e7af8c10bd0230b1fe649014602bfc42e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 11:58:24 +0100 Subject: [PATCH 088/395] JAVA-2930: Allow Micrometer to record histograms for timers (#1542) --- changelog/README.md | 1 + .../api/core/config/DseDriverOption.java | 41 ++++++ .../api/core/config/DefaultDriverOption.java | 39 +++++ .../driver/api/core/config/OptionsMap.java | 8 ++ .../api/core/config/TypedDriverOption.java | 57 ++++++++ core/src/main/resources/reference.conf | 107 +++++--------- manual/core/metrics/README.md | 9 +- .../micrometer/MicrometerMetricUpdater.java | 19 ++- .../MicrometerNodeMetricUpdater.java | 40 ++++++ .../MicrometerSessionMetricUpdater.java | 84 +++++++++++ .../MicrometerNodeMetricUpdaterTest.java | 124 +++++++++++----- .../MicrometerSessionMetricUpdaterTest.java | 134 ++++++++++++++++++ 12 files changed, 552 insertions(+), 111 deletions(-) create mode 100644 metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java diff --git a/changelog/README.md b/changelog/README.md index 4a5c5399f04..74a96b61d02 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.0 (in progress) +- [improvement] JAVA-2930: Allow Micrometer to record histograms for timers - [improvement] JAVA-2914: Transform node filter into a more flexible node distance evaluator - [improvement] JAVA-2929: Revisit node-level metric eviction - [new feature] JAVA-2830: Add mapper support for Java streams diff --git a/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java b/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java index ac493719ef6..74907c177b6 100644 --- a/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java +++ b/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java @@ -247,6 +247,47 @@ public enum DseDriverOption implements DriverOption { *

    Value-type: {@link java.time.Duration Duration} */ METRICS_NODE_GRAPH_MESSAGES_INTERVAL("advanced.metrics.node.graph-messages.refresh-interval"), + + /** + * The shortest latency that we expect to record for continuous requests. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST( + "advanced.metrics.session.continuous-cql-requests.lowest-latency"), + /** + * Optional service-level objectives to meet, as a list of latencies to track. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO( + "advanced.metrics.session.continuous-cql-requests.slo"), + + /** + * The shortest latency that we expect to record for graph requests. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_SESSION_GRAPH_REQUESTS_LOWEST("advanced.metrics.session.graph-requests.lowest-latency"), + /** + * Optional service-level objectives to meet, as a list of latencies to track. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_SESSION_GRAPH_REQUESTS_SLO("advanced.metrics.session.graph-requests.slo"), + + /** + * The shortest latency that we expect to record for graph requests. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_NODE_GRAPH_MESSAGES_LOWEST("advanced.metrics.node.graph-messages.lowest-latency"), + /** + * Optional service-level objectives to meet, as a list of latencies to track. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_NODE_GRAPH_MESSAGES_SLO("advanced.metrics.node.graph-messages.slo"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index fde3e87857a..8a916705b1b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -863,6 +863,45 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-Type: {@link String} */ LOAD_BALANCING_DISTANCE_EVALUATOR_CLASS("basic.load-balancing-policy.evaluator.class"), + + /** + * The shortest latency that we expect to record for requests. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_SESSION_CQL_REQUESTS_LOWEST("advanced.metrics.session.cql-requests.lowest-latency"), + /** + * Optional service-level objectives to meet, as a list of latencies to track. + * + *

    Value-type: List of {@link java.time.Duration Duration} + */ + METRICS_SESSION_CQL_REQUESTS_SLO("advanced.metrics.session.cql-requests.slo"), + + /** + * The shortest latency that we expect to record for throttling. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_SESSION_THROTTLING_LOWEST("advanced.metrics.session.throttling.delay.lowest-latency"), + /** + * Optional service-level objectives to meet, as a list of latencies to track. + * + *

    Value-type: List of {@link java.time.Duration Duration} + */ + METRICS_SESSION_THROTTLING_SLO("advanced.metrics.session.throttling.delay.slo"), + + /** + * The shortest latency that we expect to record for requests. + * + *

    Value-type: {@link java.time.Duration Duration} + */ + METRICS_NODE_CQL_MESSAGES_LOWEST("advanced.metrics.node.cql-messages.lowest-latency"), + /** + * Optional service-level objectives to meet, as a list of latencies to track. + * + *

    Value-type: List of {@link java.time.Duration Duration} + */ + METRICS_NODE_CQL_MESSAGES_SLO("advanced.metrics.node.cql-messages.slo"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 9c4758f531f..90e66126dd9 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -310,14 +310,19 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.MONITOR_REPORTING_ENABLED, true); map.put(TypedDriverOption.METRICS_SESSION_ENABLED, Collections.emptyList()); map.put(TypedDriverOption.METRICS_SESSION_CQL_REQUESTS_HIGHEST, Duration.ofSeconds(3)); + map.put(TypedDriverOption.METRICS_SESSION_CQL_REQUESTS_LOWEST, Duration.ofMillis(1)); map.put(TypedDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS, 3); map.put(TypedDriverOption.METRICS_SESSION_CQL_REQUESTS_INTERVAL, Duration.ofMinutes(5)); map.put(TypedDriverOption.METRICS_SESSION_THROTTLING_HIGHEST, Duration.ofSeconds(3)); + map.put(TypedDriverOption.METRICS_SESSION_THROTTLING_LOWEST, Duration.ofMillis(1)); map.put(TypedDriverOption.METRICS_SESSION_THROTTLING_DIGITS, 3); map.put(TypedDriverOption.METRICS_SESSION_THROTTLING_INTERVAL, Duration.ofMinutes(5)); map.put( TypedDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_HIGHEST, Duration.ofMinutes(2)); + map.put( + TypedDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST, + Duration.ofMillis(10)); map.put(TypedDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS, 3); map.put( TypedDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_INTERVAL, @@ -325,13 +330,16 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.METRICS_FACTORY_CLASS, "DefaultMetricsFactory"); map.put(TypedDriverOption.METRICS_ID_GENERATOR_CLASS, "DefaultMetricIdGenerator"); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, Duration.ofSeconds(12)); + map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_LOWEST, Duration.ofMillis(1)); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS, 3); map.put(TypedDriverOption.METRICS_SESSION_GRAPH_REQUESTS_INTERVAL, Duration.ofMinutes(5)); map.put(TypedDriverOption.METRICS_NODE_ENABLED, Collections.emptyList()); map.put(TypedDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST, Duration.ofSeconds(3)); + map.put(TypedDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST, Duration.ofMillis(1)); map.put(TypedDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS, 3); map.put(TypedDriverOption.METRICS_NODE_CQL_MESSAGES_INTERVAL, Duration.ofMinutes(5)); map.put(TypedDriverOption.METRICS_NODE_GRAPH_MESSAGES_HIGHEST, Duration.ofSeconds(3)); + map.put(TypedDriverOption.METRICS_NODE_GRAPH_MESSAGES_LOWEST, Duration.ofMillis(1)); map.put(TypedDriverOption.METRICS_NODE_GRAPH_MESSAGES_DIGITS, 3); map.put(TypedDriverOption.METRICS_NODE_GRAPH_MESSAGES_INTERVAL, Duration.ofMinutes(5)); map.put(TypedDriverOption.METRICS_NODE_EXPIRE_AFTER, Duration.ofHours(1)); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index 094f928d83c..25d6ac97136 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -363,6 +363,15 @@ public String toString() { public static final TypedDriverOption METRICS_SESSION_CQL_REQUESTS_HIGHEST = new TypedDriverOption<>( DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_HIGHEST, GenericType.DURATION); + /** The shortest latency that we expect to record for requests. */ + public static final TypedDriverOption METRICS_SESSION_CQL_REQUESTS_LOWEST = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_LOWEST, GenericType.DURATION); + /** Optional service-level objectives to meet, as a list of latencies to track. */ + public static final TypedDriverOption> METRICS_SESSION_CQL_REQUESTS_SLO = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_SLO, + GenericType.listOf(GenericType.DURATION)); /** * The number of significant decimal digits to which internal structures will maintain for * requests. @@ -378,6 +387,15 @@ public String toString() { public static final TypedDriverOption METRICS_SESSION_THROTTLING_HIGHEST = new TypedDriverOption<>( DefaultDriverOption.METRICS_SESSION_THROTTLING_HIGHEST, GenericType.DURATION); + /** The shortest latency that we expect to record for throttling. */ + public static final TypedDriverOption METRICS_SESSION_THROTTLING_LOWEST = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_SESSION_THROTTLING_LOWEST, GenericType.DURATION); + /** Optional service-level objectives to meet, as a list of latencies to track. */ + public static final TypedDriverOption> METRICS_SESSION_THROTTLING_SLO = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_SESSION_THROTTLING_SLO, + GenericType.listOf(GenericType.DURATION)); /** * The number of significant decimal digits to which internal structures will maintain for * throttling. @@ -393,6 +411,15 @@ public String toString() { public static final TypedDriverOption METRICS_NODE_CQL_MESSAGES_HIGHEST = new TypedDriverOption<>( DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST, GenericType.DURATION); + /** The shortest latency that we expect to record for requests. */ + public static final TypedDriverOption METRICS_NODE_CQL_MESSAGES_LOWEST = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST, GenericType.DURATION); + /** Optional service-level objectives to meet, as a list of latencies to track. */ + public static final TypedDriverOption> METRICS_NODE_CQL_MESSAGES_SLO = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_SLO, + GenericType.listOf(GenericType.DURATION)); /** * The number of significant decimal digits to which internal structures will maintain for * requests. @@ -621,6 +648,18 @@ public String toString() { new TypedDriverOption<>( DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_HIGHEST, GenericType.DURATION); + /** The shortest latency that we expect to record for continuous requests. */ + public static final TypedDriverOption + CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST = + new TypedDriverOption<>( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST, + GenericType.DURATION); + /** Optional service-level objectives to meet, as a list of latencies to track. */ + public static final TypedDriverOption> + CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO = + new TypedDriverOption<>( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO, + GenericType.listOf(GenericType.DURATION)); /** * The number of significant decimal digits to which internal structures will maintain for * continuous requests. @@ -686,6 +725,15 @@ public String toString() { public static final TypedDriverOption METRICS_SESSION_GRAPH_REQUESTS_HIGHEST = new TypedDriverOption<>( DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, GenericType.DURATION); + /** The shortest latency that we expect to record for graph requests. */ + public static final TypedDriverOption METRICS_SESSION_GRAPH_REQUESTS_LOWEST = + new TypedDriverOption<>( + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_LOWEST, GenericType.DURATION); + /** Optional service-level objectives to meet, as a list of latencies to track. */ + public static final TypedDriverOption> METRICS_SESSION_GRAPH_REQUESTS_SLO = + new TypedDriverOption<>( + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_SLO, + GenericType.listOf(GenericType.DURATION)); /** * The number of significant decimal digits to which internal structures will maintain for graph * requests. @@ -701,6 +749,15 @@ public String toString() { public static final TypedDriverOption METRICS_NODE_GRAPH_MESSAGES_HIGHEST = new TypedDriverOption<>( DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_HIGHEST, GenericType.DURATION); + /** The shortest latency that we expect to record for graph requests. */ + public static final TypedDriverOption METRICS_NODE_GRAPH_MESSAGES_LOWEST = + new TypedDriverOption<>( + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_LOWEST, GenericType.DURATION); + /** Optional service-level objectives to meet, as a list of latencies to track. */ + public static final TypedDriverOption> METRICS_NODE_GRAPH_MESSAGES_SLO = + new TypedDriverOption<>( + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_SLO, + GenericType.listOf(GenericType.DURATION)); /** * The number of significant decimal digits to which internal structures will maintain for graph * requests. diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 26a6dbc3dcd..0d56febf841 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1515,10 +1515,11 @@ datastax-java-driver { # Extra configuration (for the metrics that need it) - # Required: if the 'cql-requests' metric is enabled, and Dropwizard / HdrHistogram is used. + # Required: if the 'cql-requests' metric is enabled, and Dropwizard or Micrometer is used. # Modifiable at runtime: no # Overridable in a profile: no cql-requests { + # The largest latency that we expect to record. # # This should be slightly higher than request.timeout (in theory, readings can't be higher @@ -1526,14 +1527,21 @@ datastax-java-driver { # # This is used to scale internal data structures. If a higher recording is encountered at # runtime, it is discarded and a warning is logged. + # Valid for: Dropwizard, Micrometer. highest-latency = 3 seconds + # The shortest latency that we expect to record. This is used to scale internal data + # structures. + # Valid for: Micrometer. + lowest-latency = 1 millisecond + # The number of significant decimal digits to which internal structures will maintain # value resolution and separation (for example, 3 means that recordings up to 1 second # will be recorded with a resolution of 1 millisecond or better). # - # This must be between 0 and 5. If the value is out of range, it defaults to 3 and a - # warning is logged. + # For Dropwizard, this must be between 0 and 5. If the value is out of range, it defaults to + # 3 and a warning is logged. + # Valid for: Dropwizard, Micrometer. significant-digits = 3 # The interval at which percentile data is refreshed. @@ -1552,96 +1560,51 @@ datastax-java-driver { # # Note that this does not apply to the total count and rates (those are updated in real # time). + # Valid for: Dropwizard. refresh-interval = 5 minutes + + # An optional list of latencies to track as part of the application's service-level + # objectives (SLOs). + # + # If defined, the histogram is guaranteed to contain these boundaries alongside other + # buckets used to generate aggregable percentile approximations. + # Valid for: Micrometer. + // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] + } - # Required: if the 'throttling.delay' metric is enabled, and Dropwizard / HdrHistogram is - # used. + # Required: if the 'throttling.delay' metric is enabled, and Dropwizard or Micrometer is used. # Modifiable at runtime: no # Overridable in a profile: no throttling.delay { highest-latency = 3 seconds + lowest-latency = 1 millisecond significant-digits = 3 refresh-interval = 5 minutes + // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] } - # Required: if the 'continuous-cql-requests' metric is enabled, and Dropwizard / HdrHistogram - # is used + # Required: if the 'continuous-cql-requests' metric is enabled, and Dropwizard or Micrometer + # is used. # Modifiable at runtime: no # Overridable in a profile: no continuous-cql-requests { - - # The largest latency that we expect to record for a continuous paging request. - # - # This is used to scale internal data structures. If a higher recording is encountered at - # runtime, it is discarded and a warning is logged. highest-latency = 120 seconds - - # The number of significant decimal digits to which internal structures will maintain - # value resolution and separation (for example, 3 means that recordings up to 1 second - # will be recorded with a resolution of 1 millisecond or better). - # - # This must be between 0 and 5. If the value is out of range, it defaults to 3 and a - # warning is logged. + lowest-latency = 10 milliseconds significant-digits = 3 - - # The interval at which percentile data is refreshed. - # - # The driver records latency data in a "live" histogram, and serves results from a cached - # snapshot. Each time the snapshot gets older than the interval, the two are switched. - # Note that this switch happens upon fetching the metrics, so if you never fetch the - # recording interval might grow higher (that shouldn't be an issue in a production - # environment because you would typically have a metrics reporter that exports to a - # monitoring tool at a regular interval). - # - # In practice, this means that if you set this to 5 minutes, you're looking at data from a - # 5-minute interval in the past, that is at most 5 minutes old. If you fetch the metrics - # at a faster pace, you will observe the same data for 5 minutes until the interval - # expires. - # - # Note that this does not apply to the total count and rates (those are updated in real - # time). refresh-interval = 5 minutes + // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] } - # Required: if the 'graph-requests' metric is enabled, and Dropwizard / HdrHistogram is used + # Required: if the 'graph-requests' metric is enabled, and Dropwizard or Micrometer is used. # Modifiable at runtime: no # Overridable in a profile: no graph-requests { - # The largest latency that we expect to record. - # - # This should be slightly higher than basic.graph.timeout (in theory, readings can't be higher - # than the timeout, but there might be a small overhead due to internal scheduling). - # - # This is used to scale internal data structures. If a higher recording is encountered at - # runtime, it is discarded and a warning is logged. highest-latency = 12 seconds - - # The number of significant decimal digits to which internal structures will maintain - # value resolution and separation (for example, 3 means that recordings up to 1 second - # will be recorded with a resolution of 1 millisecond or better). - # - # This must be between 0 and 5. If the value is out of range, it defaults to 3 and a - # warning is logged. + lowest-latency = 1 millisecond significant-digits = 3 - - # The interval at which percentile data is refreshed. - # - # The driver records latency data in a "live" histogram, and serves results from a cached - # snapshot. Each time the snapshot gets older than the interval, the two are switched. - # Note that this switch happens upon fetching the metrics, so if you never fetch the - # recording interval might grow higher (that shouldn't be an issue in a production - # environment because you would typically have a metrics reporter that exports to a - # monitoring tool at a regular interval). - # - # In practice, this means that if you set this to 5 minutes, you're looking at data from a - # 5-minute interval in the past, that is at most 5 minutes old. If you fetch the metrics - # at a faster pace, you will observe the same data for 5 minutes until the interval - # expires. - # - # Note that this does not apply to the total count and rates (those are updated in real - # time). refresh-interval = 5 minutes + // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] } } # The node-level metrics (all disabled by default). @@ -1797,24 +1760,28 @@ datastax-java-driver { # See cql-requests in the `session` section # - # Required: if the 'cql-messages' metric is enabled, and Dropwizard / HdrHistogram is used + # Required: if the 'cql-messages' metric is enabled, and Dropwizard or Micrometer is used. # Modifiable at runtime: no # Overridable in a profile: no cql-messages { highest-latency = 3 seconds + lowest-latency = 1 millisecond significant-digits = 3 refresh-interval = 5 minutes + // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] } # See graph-requests in the `session` section # - # Required: if the 'graph-messages' metric is enabled, and Dropwizard / HdrHistogram is used + # Required: if the 'graph-messages' metric is enabled, and Dropwizard or Micrometer is used. # Modifiable at runtime: no # Overridable in a profile: no graph-messages { highest-latency = 3 seconds + lowest-latency = 1 millisecond significant-digits = 3 refresh-interval = 5 minutes + // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] } # The time after which the node level metrics will be evicted. diff --git a/manual/core/metrics/README.md b/manual/core/metrics/README.md index 46bfe7689bd..ab6eb8c7a9f 100644 --- a/manual/core/metrics/README.md +++ b/manual/core/metrics/README.md @@ -156,10 +156,11 @@ datastax-java-driver.advanced.metrics { If you specify a metric that doesn't exist, it will be ignored, and a warning will be logged. -Finally, if you are using Dropwizard and enabled any metric of timer type, such as `cql-requests`, -it is also possible to provide additional configuration to fine-tune the underlying histogram's -characteristics and precision, such as its highest expected latency, its number of significant -digits to use, and its refresh interval. Again, see the [reference configuration] for more details. +Finally, if you are using Dropwizard or Micrometer and enabled any metric of timer type, such as +`cql-requests`, it is also possible to provide additional configuration to fine-tune the underlying +histogram's characteristics and precision, such as its highest expected latency, its number of +significant digits to use, and its refresh interval. Again, see the [reference configuration] for +more details. ### Selecting a metric identifier style diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java index 89f6c03bff2..c30dcc121ab 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java @@ -130,7 +130,10 @@ protected DistributionSummary getOrCreateDistributionSummaryFor(MetricT metric) m -> { MetricId id = getMetricId(m); Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); - return DistributionSummary.builder(id.getName()).tags(tags).register(registry); + DistributionSummary.Builder builder = + DistributionSummary.builder(id.getName()).tags(tags); + builder = configureDistributionSummary(builder, metric, id); + return builder.register(registry); }); } @@ -141,7 +144,19 @@ protected Timer getOrCreateTimerFor(MetricT metric) { m -> { MetricId id = getMetricId(m); Iterable tags = MicrometerTags.toMicrometerTags(id.getTags()); - return Timer.builder(id.getName()).tags(tags).register(registry); + Timer.Builder builder = Timer.builder(id.getName()).tags(tags); + builder = configureTimer(builder, metric, id); + return builder.register(registry); }); } + + protected Timer.Builder configureTimer(Timer.Builder builder, MetricT metric, MetricId id) { + return builder.publishPercentileHistogram(); + } + + @SuppressWarnings("unused") + protected DistributionSummary.Builder configureDistributionSummary( + DistributionSummary.Builder builder, MetricT metric, MetricId id) { + return builder.publishPercentileHistogram(); + } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java index a0c4cbd05a6..0f5dada2bf3 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java @@ -15,7 +15,9 @@ */ package com.datastax.oss.driver.internal.metrics.micrometer; +import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.api.core.metrics.DseNodeMetric; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; @@ -24,6 +26,8 @@ import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; +import java.time.Duration; import java.util.Set; import net.jcip.annotations.ThreadSafe; @@ -88,4 +92,40 @@ protected void startMetricsExpirationTimeout() { protected void cancelMetricsExpirationTimeout() { super.cancelMetricsExpirationTimeout(); } + + @Override + protected Timer.Builder configureTimer(Timer.Builder builder, NodeMetric metric, MetricId id) { + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + if (metric == DefaultNodeMetric.CQL_MESSAGES) { + return builder + .publishPercentileHistogram() + .minimumExpectedValue( + profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST)) + .maximumExpectedValue( + profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST)) + .serviceLevelObjectives( + profile.isDefined(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_SLO) + ? profile + .getDurationList(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_SLO) + .toArray(new Duration[0]) + : null) + .percentilePrecision( + profile.getInt(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS)); + } else if (metric == DseNodeMetric.GRAPH_MESSAGES) { + return builder + .publishPercentileHistogram() + .minimumExpectedValue( + profile.getDuration(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_LOWEST)) + .maximumExpectedValue( + profile.getDuration(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_HIGHEST)) + .serviceLevelObjectives( + profile.isDefined(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_SLO) + ? profile + .getDurationList(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_SLO) + .toArray(new Duration[0]) + : null) + .percentilePrecision(profile.getInt(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_DIGITS)); + } + return super.configureTimer(builder, metric, id); + } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java index 93106ea77a9..bb361b85f22 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java @@ -15,7 +15,9 @@ */ package com.datastax.oss.driver.internal.metrics.micrometer; +import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.api.core.metrics.DseSessionMetric; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.metrics.SessionMetric; @@ -23,6 +25,8 @@ import com.datastax.oss.driver.internal.core.metrics.MetricId; import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; +import java.time.Duration; import java.util.Set; import net.jcip.annotations.ThreadSafe; @@ -55,4 +59,84 @@ public MicrometerSessionMetricUpdater( protected MetricId getMetricId(SessionMetric metric) { return context.getMetricIdGenerator().sessionMetricId(metric); } + + @Override + protected Timer.Builder configureTimer(Timer.Builder builder, SessionMetric metric, MetricId id) { + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + if (metric == DefaultSessionMetric.CQL_REQUESTS) { + return builder + .publishPercentileHistogram() + .minimumExpectedValue( + profile.getDuration(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_LOWEST)) + .maximumExpectedValue( + profile.getDuration(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_HIGHEST)) + .serviceLevelObjectives( + profile.isDefined(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_SLO) + ? profile + .getDurationList(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_SLO) + .toArray(new Duration[0]) + : null) + .percentilePrecision( + profile.isDefined(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS) + ? profile.getInt(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS) + : null); + } else if (metric == DefaultSessionMetric.THROTTLING_DELAY) { + return builder + .publishPercentileHistogram() + .minimumExpectedValue( + profile.getDuration(DefaultDriverOption.METRICS_SESSION_THROTTLING_LOWEST)) + .maximumExpectedValue( + profile.getDuration(DefaultDriverOption.METRICS_SESSION_THROTTLING_HIGHEST)) + .serviceLevelObjectives( + profile.isDefined(DefaultDriverOption.METRICS_SESSION_THROTTLING_SLO) + ? profile + .getDurationList(DefaultDriverOption.METRICS_SESSION_THROTTLING_SLO) + .toArray(new Duration[0]) + : null) + .percentilePrecision( + profile.isDefined(DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS) + ? profile.getInt(DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS) + : null); + } else if (metric == DseSessionMetric.CONTINUOUS_CQL_REQUESTS) { + return builder + .publishPercentileHistogram() + .minimumExpectedValue( + profile.getDuration( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST)) + .maximumExpectedValue( + profile.getDuration( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_HIGHEST)) + .serviceLevelObjectives( + profile.isDefined(DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO) + ? profile + .getDurationList( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO) + .toArray(new Duration[0]) + : null) + .percentilePrecision( + profile.isDefined( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS) + ? profile.getInt( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS) + : null); + } else if (metric == DseSessionMetric.GRAPH_REQUESTS) { + return builder + .publishPercentileHistogram() + .minimumExpectedValue( + profile.getDuration(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_LOWEST)) + .maximumExpectedValue( + profile.getDuration(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST)) + .serviceLevelObjectives( + profile.isDefined(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_SLO) + ? profile + .getDurationList(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_SLO) + .toArray(new Duration[0]) + : null) + .percentilePrecision( + profile.isDefined(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS) + ? profile.getInt(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS) + : null); + } + return super.configureTimer(builder, metric, id); + } } diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java index badea84e6db..a874344fef0 100644 --- a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java @@ -17,34 +17,47 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import ch.qos.logback.classic.Level; +import com.datastax.dse.driver.api.core.config.DseDriverOption; +import com.datastax.dse.driver.api.core.metrics.DseNodeMetric; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.config.DriverOption; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.NodeMetric; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; +import com.datastax.oss.driver.internal.core.metrics.DefaultMetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; import com.datastax.oss.driver.internal.core.util.LoggerTest; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.distribution.HistogramSnapshot; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import java.time.Duration; +import java.util.Arrays; import java.util.Collections; import java.util.Set; -import java.util.function.Supplier; +import java.util.concurrent.TimeUnit; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(DataProviderRunner.class) public class MicrometerNodeMetricUpdaterTest { + private static final MetricId METRIC_ID = new DefaultMetricId("irrelevant", ImmutableMap.of()); + @Test public void should_log_warning_when_provided_eviction_time_setting_is_too_low() { // given @@ -54,6 +67,7 @@ public void should_log_warning_when_provided_eviction_time_setting_is_too_low() InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); DriverConfig config = mock(DriverConfig.class); + MetricIdGenerator generator = mock(MetricIdGenerator.class); Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); Duration expireAfter = AbstractMetricUpdater.MIN_EXPIRE_AFTER.minusMinutes(1); @@ -61,27 +75,13 @@ public void should_log_warning_when_provided_eviction_time_setting_is_too_low() when(context.getSessionName()).thenReturn("prefix"); when(context.getConfig()).thenReturn(config); when(config.getDefaultProfile()).thenReturn(profile); + when(context.getMetricIdGenerator()).thenReturn(generator); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) .thenReturn(expireAfter); + when(generator.nodeMetricId(node, DefaultNodeMetric.CQL_MESSAGES)).thenReturn(METRIC_ID); MicrometerNodeMetricUpdater updater = - new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()) { - @Override - protected void initializeGauge( - NodeMetric metric, DriverExecutionProfile profile, Supplier supplier) { - // do nothing - } - - @Override - protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { - // do nothing - } - - @Override - protected void initializeTimer(NodeMetric metric, DriverExecutionProfile profile) { - // do nothing - } - }; + new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()); // then assertThat(updater.getExpireAfter()).isEqualTo(AbstractMetricUpdater.MIN_EXPIRE_AFTER); @@ -107,33 +107,20 @@ public void should_not_log_warning_when_provided_eviction_time_setting_is_accept InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); DriverConfig config = mock(DriverConfig.class); + MetricIdGenerator generator = mock(MetricIdGenerator.class); Set enabledMetrics = Collections.singleton(DefaultNodeMetric.CQL_MESSAGES); // when when(context.getSessionName()).thenReturn("prefix"); when(context.getConfig()).thenReturn(config); when(config.getDefaultProfile()).thenReturn(profile); + when(context.getMetricIdGenerator()).thenReturn(generator); when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) .thenReturn(expireAfter); + when(generator.nodeMetricId(node, DefaultNodeMetric.CQL_MESSAGES)).thenReturn(METRIC_ID); MicrometerNodeMetricUpdater updater = - new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()) { - @Override - protected void initializeGauge( - NodeMetric metric, DriverExecutionProfile profile, Supplier supplier) { - // do nothing - } - - @Override - protected void initializeCounter(NodeMetric metric, DriverExecutionProfile profile) { - // do nothing - } - - @Override - protected void initializeTimer(NodeMetric metric, DriverExecutionProfile profile) { - // do nothing - } - }; + new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()); // then assertThat(updater.getExpireAfter()).isEqualTo(expireAfter); @@ -147,4 +134,71 @@ public static Object[][] acceptableEvictionTimes() { {AbstractMetricUpdater.MIN_EXPIRE_AFTER.plusMinutes(1)} }; } + + @Test + @UseDataProvider(value = "timerMetrics") + public void should_create_timer( + NodeMetric metric, + DriverOption lowest, + DriverOption highest, + DriverOption digits, + DriverOption sla) { + // given + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + MetricIdGenerator generator = mock(MetricIdGenerator.class); + Set enabledMetrics = Collections.singleton(metric); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(context.getMetricIdGenerator()).thenReturn(generator); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(Duration.ofHours(1)); + when(profile.getDuration(lowest)).thenReturn(Duration.ofMillis(10)); + when(profile.getDuration(highest)).thenReturn(Duration.ofSeconds(1)); + when(profile.getInt(digits)).thenReturn(5); + when(profile.isDefined(sla)).thenReturn(true); + when(profile.getDurationList(sla)) + .thenReturn(Arrays.asList(Duration.ofMillis(100), Duration.ofMillis(500))); + when(generator.nodeMetricId(node, metric)).thenReturn(METRIC_ID); + + SimpleMeterRegistry registry = spy(new SimpleMeterRegistry()); + MicrometerNodeMetricUpdater updater = + new MicrometerNodeMetricUpdater(node, context, enabledMetrics, registry); + + for (int i = 0; i < 10; i++) { + updater.updateTimer(metric, null, 100, TimeUnit.MILLISECONDS); + } + + // then + Timer timer = registry.find(METRIC_ID.getName()).timer(); + assertThat(timer).isNotNull(); + assertThat(timer.count()).isEqualTo(10); + HistogramSnapshot snapshot = timer.takeSnapshot(); + assertThat(snapshot.histogramCounts()).hasSize(2); + } + + @DataProvider + public static Object[][] timerMetrics() { + return new Object[][] { + { + DefaultNodeMetric.CQL_MESSAGES, + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST, + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST, + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS, + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_SLO, + }, + { + DseNodeMetric.GRAPH_MESSAGES, + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_LOWEST, + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_HIGHEST, + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_DIGITS, + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_SLO, + }, + }; + } } diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java new file mode 100644 index 00000000000..09b3e44bac4 --- /dev/null +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java @@ -0,0 +1,134 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.metrics.micrometer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.datastax.dse.driver.api.core.config.DseDriverOption; +import com.datastax.dse.driver.api.core.metrics.DseSessionMetric; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.config.DriverOption; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.core.metrics.SessionMetric; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metrics.DefaultMetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricId; +import com.datastax.oss.driver.internal.core.metrics.MetricIdGenerator; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.distribution.HistogramSnapshot; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import java.time.Duration; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class MicrometerSessionMetricUpdaterTest { + + private static final MetricId METRIC_ID = new DefaultMetricId("irrelevant", ImmutableMap.of()); + + @Test + @UseDataProvider(value = "timerMetrics") + public void should_create_timer( + SessionMetric metric, + DriverOption lowest, + DriverOption highest, + DriverOption digits, + DriverOption sla) { + // given + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + MetricIdGenerator generator = mock(MetricIdGenerator.class); + Set enabledMetrics = Collections.singleton(metric); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(context.getMetricIdGenerator()).thenReturn(generator); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(Duration.ofHours(1)); + when(profile.getDuration(lowest)).thenReturn(Duration.ofMillis(10)); + when(profile.getDuration(highest)).thenReturn(Duration.ofSeconds(1)); + when(profile.getInt(digits)).thenReturn(5); + when(profile.isDefined(sla)).thenReturn(true); + when(profile.getDurationList(sla)) + .thenReturn(Arrays.asList(Duration.ofMillis(100), Duration.ofMillis(500))); + when(generator.sessionMetricId(metric)).thenReturn(METRIC_ID); + + SimpleMeterRegistry registry = spy(new SimpleMeterRegistry()); + MicrometerSessionMetricUpdater updater = + new MicrometerSessionMetricUpdater(context, enabledMetrics, registry); + + for (int i = 0; i < 10; i++) { + updater.updateTimer(metric, null, 100, TimeUnit.MILLISECONDS); + } + + // then + Timer timer = registry.find(METRIC_ID.getName()).timer(); + assertThat(timer).isNotNull(); + assertThat(timer.count()).isEqualTo(10); + HistogramSnapshot snapshot = timer.takeSnapshot(); + assertThat(snapshot.histogramCounts()).hasSize(2); + } + + @DataProvider + public static Object[][] timerMetrics() { + return new Object[][] { + { + DefaultSessionMetric.CQL_REQUESTS, + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_LOWEST, + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_HIGHEST, + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS, + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_SLO, + }, + { + DseSessionMetric.GRAPH_REQUESTS, + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_LOWEST, + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS, + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_SLO, + }, + { + DseSessionMetric.CONTINUOUS_CQL_REQUESTS, + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST, + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_HIGHEST, + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS, + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO, + }, + { + DefaultSessionMetric.THROTTLING_DELAY, + DefaultDriverOption.METRICS_SESSION_THROTTLING_LOWEST, + DefaultDriverOption.METRICS_SESSION_THROTTLING_HIGHEST, + DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS, + DefaultDriverOption.METRICS_SESSION_THROTTLING_SLO, + }, + }; + } +} From 9b42e3894cc5cb797f707114c8f487a4a7c3dde7 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 14:37:17 +0100 Subject: [PATCH 089/395] Upgrade native-protocol to 1.5.0 --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 6aaae045061..cd1abf49230 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -71,7 +71,7 @@ com.datastax.oss native-protocol - 1.4.13-SNAPSHOT + 1.5.0 com.datastax.oss From a6e1deebc731c5fc21fd0c80289ea8017486192d Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 15:25:51 +0100 Subject: [PATCH 090/395] Fix failing test in MicrometerNodeMetricUpdaterTest --- .../micrometer/MicrometerNodeMetricUpdaterTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java index a874344fef0..fbdfb7b2355 100644 --- a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java @@ -79,6 +79,11 @@ public void should_log_warning_when_provided_eviction_time_setting_is_too_low() when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) .thenReturn(expireAfter); when(generator.nodeMetricId(node, DefaultNodeMetric.CQL_MESSAGES)).thenReturn(METRIC_ID); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST)) + .thenReturn(Duration.ofSeconds(10)); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST)) + .thenReturn(Duration.ofMillis(1)); + when(profile.getInt(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS)).thenReturn(5); MicrometerNodeMetricUpdater updater = new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()); @@ -118,6 +123,11 @@ public void should_not_log_warning_when_provided_eviction_time_setting_is_accept when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) .thenReturn(expireAfter); when(generator.nodeMetricId(node, DefaultNodeMetric.CQL_MESSAGES)).thenReturn(METRIC_ID); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST)) + .thenReturn(Duration.ofSeconds(10)); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST)) + .thenReturn(Duration.ofMillis(1)); + when(profile.getInt(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS)).thenReturn(5); MicrometerNodeMetricUpdater updater = new MicrometerNodeMetricUpdater(node, context, enabledMetrics, new SimpleMeterRegistry()); From adbdb93727a15f6f110d6cb60bfabc65ed8deecb Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 15:30:32 +0100 Subject: [PATCH 091/395] Update version in docs --- README.md | 4 +- changelog/README.md | 2 +- manual/case_sensitivity/README.md | 10 +-- manual/core/README.md | 26 +++---- manual/core/address_resolution/README.md | 2 +- manual/core/async/README.md | 2 +- manual/core/authentication/README.md | 16 ++-- manual/core/bom/README.md | 4 +- manual/core/configuration/README.md | 20 ++--- manual/core/control_connection/README.md | 2 +- manual/core/custom_codecs/README.md | 74 +++++++++---------- manual/core/detachable_types/README.md | 14 ++-- manual/core/dse/geotypes/README.md | 6 +- manual/core/dse/graph/README.md | 4 +- manual/core/dse/graph/fluent/README.md | 4 +- .../core/dse/graph/fluent/explicit/README.md | 12 +-- manual/core/dse/graph/results/README.md | 6 +- manual/core/dse/graph/script/README.md | 6 +- manual/core/idempotence/README.md | 4 +- manual/core/load_balancing/README.md | 10 +-- manual/core/metadata/README.md | 6 +- manual/core/metadata/node/README.md | 28 +++---- manual/core/metadata/schema/README.md | 20 ++--- manual/core/metadata/token/README.md | 4 +- manual/core/native_protocol/README.md | 6 +- manual/core/non_blocking/README.md | 44 +++++------ manual/core/paging/README.md | 12 +-- manual/core/performance/README.md | 10 +-- manual/core/pooling/README.md | 2 +- manual/core/query_timestamps/README.md | 4 +- manual/core/reactive/README.md | 24 +++--- manual/core/reconnection/README.md | 8 +- manual/core/request_tracker/README.md | 4 +- manual/core/retries/README.md | 36 ++++----- manual/core/speculative_execution/README.md | 2 +- manual/core/ssl/README.md | 6 +- manual/core/statements/README.md | 8 +- manual/core/statements/batch/README.md | 6 +- .../statements/per_query_keyspace/README.md | 2 +- manual/core/statements/prepared/README.md | 8 +- manual/core/statements/simple/README.md | 6 +- manual/core/temporal_types/README.md | 8 +- manual/core/throttling/README.md | 6 +- manual/core/tracing/README.md | 12 +-- manual/core/tuples/README.md | 4 +- manual/core/udts/README.md | 4 +- manual/developer/common/concurrency/README.md | 4 +- manual/mapper/config/kotlin/README.md | 2 +- manual/mapper/config/record/README.md | 2 +- manual/mapper/config/scala/README.md | 2 +- manual/mapper/daos/README.md | 8 +- manual/mapper/daos/custom_types/README.md | 10 +-- manual/mapper/daos/delete/README.md | 18 ++--- manual/mapper/daos/getentity/README.md | 18 ++--- manual/mapper/daos/increment/README.md | 12 +-- manual/mapper/daos/insert/README.md | 14 ++-- manual/mapper/daos/null_saving/README.md | 10 +-- manual/mapper/daos/query/README.md | 24 +++--- manual/mapper/daos/queryprovider/README.md | 16 ++-- manual/mapper/daos/select/README.md | 28 +++---- manual/mapper/daos/setentity/README.md | 10 +-- .../daos/statement_attributes/README.md | 2 +- manual/mapper/daos/update/README.md | 12 +-- manual/mapper/entities/README.md | 36 ++++----- manual/mapper/mapper/README.md | 10 +-- manual/osgi/README.md | 6 +- manual/query_builder/README.md | 10 +-- manual/query_builder/condition/README.md | 2 +- manual/query_builder/delete/README.md | 4 +- manual/query_builder/insert/README.md | 2 +- manual/query_builder/relation/README.md | 4 +- manual/query_builder/schema/README.md | 2 +- .../query_builder/schema/aggregate/README.md | 2 +- .../query_builder/schema/function/README.md | 2 +- manual/query_builder/schema/index/README.md | 2 +- .../query_builder/schema/keyspace/README.md | 2 +- .../schema/materialized_view/README.md | 4 +- manual/query_builder/schema/table/README.md | 6 +- manual/query_builder/schema/type/README.md | 2 +- manual/query_builder/select/README.md | 4 +- manual/query_builder/term/README.md | 4 +- manual/query_builder/truncate/README.md | 2 +- manual/query_builder/update/README.md | 4 +- upgrade_guide/README.md | 38 +++++----- 84 files changed, 424 insertions(+), 424 deletions(-) diff --git a/README.md b/README.md index 5b7c323ec85..5a137ac947a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.10.0](https://github.com/datastax/java-driver/tree/4.10.0).* +[4.11.0](https://github.com/datastax/java-driver/tree/4.11.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol @@ -82,7 +82,7 @@ See the [upgrade guide](upgrade_guide/) for details. * [Changelog] * [FAQ] -[API docs]: https://docs.datastax.com/en/drivers/java/4.10 +[API docs]: https://docs.datastax.com/en/drivers/java/4.11 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [@dsJavaDriver]: https://twitter.com/dsJavaDriver diff --git a/changelog/README.md b/changelog/README.md index 74a96b61d02..342336ae918 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,7 +2,7 @@ -### 4.11.0 (in progress) +### 4.11.0 - [improvement] JAVA-2930: Allow Micrometer to record histograms for timers - [improvement] JAVA-2914: Transform node filter into a more flexible node distance evaluator diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index 576ee41823d..4138ae42d89 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -106,11 +106,11 @@ For "consuming" methods, string overloads are also provided for convenience, for * in other cases, the string is always assumed to be in CQL form, and converted on the fly with `CqlIdentifier.fromCql`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html -[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html +[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/AccessibleByName.html ### Good practices diff --git a/manual/core/README.md b/manual/core/README.md index 7ff1fc3ab0e..6a316245c50 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -314,18 +314,18 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { } ``` -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html -[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html#builder-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/TupleValue.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html -[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- -[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html#builder-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/TupleValue.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html +[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- +[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index b3b0ff0dd17..61954f38c43 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -124,7 +124,7 @@ Cassandra node: domain name of the target instance. Then it performs a forward DNS lookup of the domain name; the EC2 DNS does the private/public switch automatically based on location). -[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html +[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html [cassandra.yaml]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html [rpc_address]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html?scroll=configCassandra_yaml__rpc_address diff --git a/manual/core/async/README.md b/manual/core/async/README.md index d3d936a2758..aeaaa53e5ce 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -207,4 +207,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 90181f3b98e..8b3a2a61099 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -215,12 +215,12 @@ session.execute(statement); [SASL]: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer -[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/auth/AuthProvider.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html -[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html -[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html -[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html -[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- -[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- -[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- +[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/auth/AuthProvider.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html +[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html +[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html +[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- +[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- +[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- [reference.conf]: ../configuration/reference/ \ No newline at end of file diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index cc896b138a1..690ed1ce3cc 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.10.0 + 4.11.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.10.0 + 4.11.0 diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index 8d8b11e1065..55e7bf6d91c 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -520,16 +520,16 @@ config.getDefaultProfile().getString(MyCustomOption.ADMIN_EMAIL); config.getDefaultProfile().getInt(MyCustomOption.AWESOMENESS_FACTOR); ``` -[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfig.html -[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html -[DriverOption]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverOption.html -[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html -[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- -[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- -[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- -[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- +[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfig.html +[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html +[DriverOption]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverOption.html +[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html +[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- +[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- +[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- +[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- [Typesafe Config]: https://github.com/typesafehub/config [config standard behavior]: https://github.com/typesafehub/config#standard-behavior diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index 77977089641..a1d9a345cee 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -23,4 +23,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index 53d2a785d02..b90ea31ad10 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -660,13 +660,13 @@ private static String formatRow(Row row) { } ``` -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html -[format()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- -[parse()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- -[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html -[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html +[format()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- +[parse()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- +[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html +[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- [Enums]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html [Enum.name()]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#name-- @@ -680,36 +680,36 @@ private static String formatRow(Row row) { [java.time.LocalDateTime]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html [java.time.ZoneId]: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html -[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html -[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY -[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY -[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY -[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY -[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY -[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY -[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY -[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY -[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC -[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- -[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM -[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC -[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC -[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC -[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED -[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- -[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- -[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- -[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- - -[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB -[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP +[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html +[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY +[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY +[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY +[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY +[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY +[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY +[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY +[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY +[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC +[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- +[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM +[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC +[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC +[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC +[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED +[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- +[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- +[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- +[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- + +[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB +[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index f81f376831c..737dd1b41c9 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -137,13 +137,13 @@ Even then, the defaults used by detached objects might be good enough for you: Otherwise, just make sure you reattach objects any time you deserialize them or create them from scratch. -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT -[DataType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/DataType.html -[Detachable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/detach/Detachable.html -[Session]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html -[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html -[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT +[DataType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/DataType.html +[Detachable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/detach/Detachable.html +[Session]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html +[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html +[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html [Java serialization]: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html [protocol specifications]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index a7c676e8cdf..f6329a2fd5a 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -166,9 +166,9 @@ All geospatial types interoperate with three standard formats: [ESRI]: https://github.com/Esri/geometry-api-java -[LineString]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/data/geometry/LineString.html -[Point]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/data/geometry/Point.html -[Polygon]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/data/geometry/Polygon.html +[LineString]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/data/geometry/LineString.html +[Point]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/data/geometry/Point.html +[Polygon]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/data/geometry/Polygon.html [Well-known text]: https://en.wikipedia.org/wiki/Well-known_text [Well-known binary]: https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index 1bf8d7825ba..d18b1959c93 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -74,8 +74,8 @@ fluent API returns Apache TinkerPop™ types directly. [Apache TinkerPop™]: http://tinkerpop.apache.org/ -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html -[GraphSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/GraphSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html +[GraphSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/GraphSession.html [DSE developer guide]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphTOC.html [Gremlin]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dseGraphAbout.html#dseGraphAbout__what-is-cql diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index 2d907231e58..090ccc248fb 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -109,8 +109,8 @@ All the DSE predicates are available on the driver side: .values("name"); ``` -[Search]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/predicates/Search.html -[Geo]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/predicates/Geo.html +[Search]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/predicates/Search.html +[Geo]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/predicates/Geo.html [Apache TinkerPop™]: http://tinkerpop.apache.org/ [TinkerPop DSL]: http://tinkerpop.apache.org/docs/current/reference/#dsl diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index 5ba18bc6891..533a257d218 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -105,9 +105,9 @@ added in a future version. See also the [parent page](../) for topics common to all fluent traversals. -[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html -[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html -[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- -[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- +[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html +[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html +[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- +[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index e40f29d7f9a..7c9356b19b6 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -137,8 +137,8 @@ If a type doesn't have a corresponding `asXxx()` method, use the variant that ta UUID uuid = graphNode.as(UUID.class); ``` -[GraphNode]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/GraphNode.html -[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/GraphResultSet.html -[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html +[GraphNode]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/GraphNode.html +[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/GraphResultSet.html +[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html [DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index 2869ce22a4b..f26ab58bdf4 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -101,6 +101,6 @@ Note however that some types of queries can only be performed through the script * configuration; * DSE graph schema queries. -[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html -[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html +[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index 505ad2a40be..1bb97d92c64 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -60,5 +60,5 @@ assert bs.isIdempotent(); The query builder tries to infer idempotence automatically; refer to [its manual](../../query_builder/idempotence/) for more details. -[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- -[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- +[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- +[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index cb9dde4196c..fdac96702fe 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -426,12 +426,12 @@ Then it uses the "closest" distance for any given node. For example: * policy1 changes its suggestion to IGNORED. node1 is set to REMOTE; * policy1 changes its suggestion to REMOTE. node1 stays at REMOTE. -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html -[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html +[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html [BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java -[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- -[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- -[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- +[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- +[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index 51b7c4621ea..8b5557dd994 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -56,6 +56,6 @@ new keyspace in the schema metadata before the token metadata was updated. Schema and node state events are debounced. This allows you to control how often the metadata gets refreshed. See the [Performance](../performance/#debouncing) page for more details. -[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- -[Metadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- +[Metadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html +[Node]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 31503c10be4..715b26df732 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -112,17 +112,17 @@ beyond the scope of this document; if you're interested, study the `TopologyMoni the source code. -[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- -[Node]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html -[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- -[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- -[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- -[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- -[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- -[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- -[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- -[NodeState]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/NodeState.html -[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html -[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file +[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- +[Node]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html +[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- +[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- +[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- +[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- +[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- +[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- +[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- +[NodeState]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/NodeState.html +[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html +[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html +[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index fc02e8a8cdc..4fb70ac326c 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -307,16 +307,16 @@ unavailable for the excluded keyspaces. If you issue schema-altering requests from the driver (e.g. `session.execute("CREATE TABLE ..")`), take a look at the [Performance](../../performance/#schema-updates) page for a few tips. -[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html -[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html -[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- -[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- -[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- -[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html -[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html -[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html +[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html +[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html +[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- +[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- +[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- +[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html +[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html +[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html [JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 [java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index 8c98f389cef..e3dc6d903c3 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -169,5 +169,5 @@ on [schema metadata](../schema/). If schema metadata is disabled or filtered, to also be unavailable for the excluded keyspaces. -[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 616b04beeda..e2ed651de6d 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -135,6 +135,6 @@ If you want to see the details of mixed cluster negotiation, enable `DEBUG` leve [protocol spec]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources [driver3]: https://docs.datastax.com/en/developer/java-driver/3.10/manual/native_protocol/ -[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- -[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- -[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- +[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- +[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- +[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 8ddbcfd8069..efb068912b2 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -49,22 +49,22 @@ For example, calling any synchronous method declared in [`SyncCqlSession`], such will block until the result is available. These methods should never be used in non-blocking applications. -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` -[`execute`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all safe for use in non-blocking applications; the statement execution and asynchronous result delivery is guaranteed to never block. -[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html -[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the returned publisher will never block when subscribed to, until the final results are delivered to the subscriber. -[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- There is one exception though: continuous paging queries (a feature specific to DSE) have a special execution model which uses internal locks for coordination. Although such locks are only held for @@ -77,10 +77,10 @@ reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactiv though, continuous paging is extremely efficient and can safely be used in most non-blocking contexts, unless they require strict lock-freedom. -[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html -[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html -[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- -[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- #### Driver lock-free guarantees per session lifecycle phases @@ -110,8 +110,8 @@ Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` should be avoided in non-blocking applications. -[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- -[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- Once the session is initialized, however, the driver is guaranteed to be non-blocking during the session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. @@ -121,8 +121,8 @@ during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseab asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is shut down and lock-freedom enforcement is disabled. -[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html -[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- #### Driver lock-free guarantees for specific components @@ -131,7 +131,7 @@ Certain driver components are not implemented in lock-free algorithms. For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It should not be used if strict lock-freedom is enforced. -[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html The same is valid for both built-in [request throttlers]: @@ -143,7 +143,7 @@ use locks internally, and depending on how many requests are being executed in p contention on these locks can be high: in short, if your application enforces strict lock-freedom, then these components should not be used. -[request throttlers]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html +[request throttlers]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html Other components may be lock-free, *except* for their first invocation. This is the case of the following items: @@ -151,8 +151,8 @@ following items: * All built-in implementations of [`TimestampGenerator`], upon instantiation; * The utility method [`Uuids.timeBased()`]. -[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/time/TimestampGenerator.html -[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- Both components need to access native libraries when they get initialized and this may involve hitting the local filesystem, thus causing the initialization to become a blocking call. @@ -172,7 +172,7 @@ One component, the codec registry, can block when its [`register`] method is cal therefore advised that codecs should be registered during application startup exclusively. See the [custom codecs](../custom_codecs) section for more details about registering codecs. -[`register`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[`register`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- Finally, a few internal components also use locks, but only during session initialization; once the session is ready, they are either discarded, or don't use locks anymore for the rest of the @@ -213,7 +213,7 @@ lock-freedom enforcement tools could report calls to that method, but it was imp these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a non-blocking call and random UUIDs can now be safely generated in non-blocking applications. -[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- [JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 #### Driver lock-free guarantees when reloading the configuration @@ -228,8 +228,8 @@ detectors. If that is the case, it is advised to disable hot-reloading by settin `datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on [configuration](../configuration) for more information. -[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- #### Driver lock-free guarantees when connecting to DSE diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index ffae1dfb6fb..288127679a0 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -253,12 +253,12 @@ protocol page size and the logical page size to the same value. The [driver examples] include two complete web service implementations demonstrating forward-only and offset paging. -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- -[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- -[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/paging/OffsetPager.html -[PagingState]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/PagingState.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- +[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- +[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/paging/OffsetPager.html +[PagingState]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/PagingState.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index 691b4735aea..6f6cfb9f2fb 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -345,8 +345,8 @@ possible to reuse the same event loop group for I/O, admin tasks, and even your (the driver's internal code is fully asynchronous so it will never block any thread). The timer is the only one that will have to stay on a separate thread. -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html -[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- -[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html +[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index 8fb17c02f8b..e6ba907b95f 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -170,5 +170,5 @@ you experience the issue, here's what to look out for: Try adding more connections per node. Thanks to the driver's hot-reload mechanism, you can do that at runtime and see the effects immediately. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html [CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index a3264c1f0e1..c98d1030392 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -187,9 +187,9 @@ Here is the order of precedence of all the methods described so far: 3. otherwise, if the timestamp generator assigned a timestamp, use it; 4. otherwise, let the server assign the timestamp. -[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/time/TimestampGenerator.html [gettimeofday]: http://man7.org/linux/man-pages/man2/settimeofday.2.html [JNR]: https://github.com/jnr/jnr-posix [Lightweight transactions]: https://docs.datastax.com/en/dse/6.0/cql/cql/cql_using/useInsertLWT.html -[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- +[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index 57b3a98cebb..c8485c982bd 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -367,18 +367,18 @@ Note that the driver already has a [built-in retry mechanism] that can transpare queries; the above example should be seen as a demonstration of application-level retries, when a more fine-grained control of what should be retried, and how, is required. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html -[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html -[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html -[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- -[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- -[wasApplied]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- -[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- -[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- -[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html +[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html +[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html +[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- +[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- +[wasApplied]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- +[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- +[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- +[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- [built-in retry mechanism]: ../retries/ [request throttling]: ../throttling/ diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index 08a1e30f4c9..36b2d55b832 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -84,7 +84,7 @@ Note that the session is not accessible until it is fully ready: the `CqlSession call — or the future returned by `buildAsync()` — will not complete until the connection was established. -[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/context/DriverContext.html -[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html +[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index 1d52fbceb26..e959c09dfd7 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -117,5 +117,5 @@ all FROM users WHERE user_id=? [v0=42] com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined column name all ``` -[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/tracker/RequestTracker.html +[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index fbcd8e92720..df8ac5b9003 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -231,21 +231,21 @@ configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html -[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/DriverTimeoutException.html -[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html -[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/HeartbeatException.html -[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html -[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html -[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html -[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html -[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html -[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryDecision.html -[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html -[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryVerdict.html -[ServerError]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/ServerError.html -[TruncateException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/TruncateException.html -[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html -[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html -[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html +[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/DriverTimeoutException.html +[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html +[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/HeartbeatException.html +[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html +[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html +[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html +[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html +[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html +[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryDecision.html +[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html +[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[ServerError]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ServerError.html +[TruncateException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/TruncateException.html +[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html +[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html +[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index 698ac2f42a4..f5ba057d431 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -250,4 +250,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index cdbc5ca817c..bac3786c624 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -204,6 +204,6 @@ the box, but with a bit of custom development it is fairly easy to add. See [dsClientToNode]: https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html [pickle]: http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html [JSSE system properties]: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization -[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- -[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- -[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html +[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- +[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- +[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index 90dec7a960d..2e1dd1aa75f 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -59,7 +59,7 @@ the [configuration](../configuration/). Namely, these are: idempotent flag, quer consistency levels and page size. We recommended the configuration approach whenever possible (you can create execution profiles to capture common combinations of those options). -[Statement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html -[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/StatementBuilder.html -[execute]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- -[executeAsync]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[Statement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html +[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/StatementBuilder.html +[execute]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[executeAsync]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index b1cb7c70967..df917e33af5 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -61,8 +61,8 @@ In addition, simple statements with named parameters are currently not supported due to a [protocol limitation][CASSANDRA-10246] that will be fixed in a future version). If you try to execute such a batch, an `IllegalArgumentException` is thrown. -[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BatchStatement.html -[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- -[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BatchStatement.html +[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- [batch_dse]: http://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/useBatch.html [CASSANDRA-10246]: https://issues.apache.org/jira/browse/CASSANDRA-10246 diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index 66e9d451387..152816071d2 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -124,6 +124,6 @@ SimpleStatement statement = At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we'll probably deprecate `setRoutingKeyspace()`. -[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index e74813d8e6d..afb24ac38ed 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -330,10 +330,10 @@ With Cassandra 4 and [native protocol](../../native_protocol/) v5, this issue is new version with the response; the driver updates its local cache transparently, and the client can observe the new columns in the result set. -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [CASSANDRA-10786]: https://issues.apache.org/jira/browse/CASSANDRA-10786 [CASSANDRA-10813]: https://issues.apache.org/jira/browse/CASSANDRA-10813 [guava eviction]: https://github.com/google/guava/wiki/CachesExplained#reference-based-eviction -[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- -[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- +[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- +[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index deff971fea9..e614885039a 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -182,6 +182,6 @@ session.execute( Or you could also use [prepared statements](../prepared/), which don't have this limitation since parameter types are known in advance. -[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SimpleStatement.html -[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- -[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- +[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SimpleStatement.html +[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- +[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index a9985099fd7..e30f8fca947 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -146,7 +146,7 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]" ``` -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index 6e779811aa0..3b5c025032f 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -145,6 +145,6 @@ datastax-java-driver { If you enable `throttling.delay`, make sure to also check the associated extra options to correctly size the underlying histograms (`metrics.session.throttling.delay.*`). -[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/RequestThrottlingException.html -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/RequestThrottlingException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index 3708988ad39..07d4416efba 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -113,9 +113,9 @@ for (TraceEvent event : trace.getEvents()) { If you call `getQueryTrace()` for a statement that didn't have tracing enabled, an exception is thrown. -[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html -[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/QueryTrace.html -[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- -[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- -[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- -[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html +[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/QueryTrace.html +[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- +[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- +[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- +[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index 2de2788c87a..1662aa3beb7 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -139,5 +139,5 @@ BoundStatement bs = [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html -[TupleType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/TupleType.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/TupleValue.html +[TupleType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/TupleType.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/TupleValue.html diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index 6cadf225623..8fdd72050a2 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -135,5 +135,5 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index 545eda62533..2ab2ab7db35 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -101,8 +101,8 @@ public interface ExecutionInfo { When a public API method is blocking, this is generally clearly stated in its javadocs. -[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index 1ff4fa80910..58e104513de 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -106,4 +106,4 @@ before compilation: [build.gradle]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/build.gradle [UserDao.kt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/src/main/kotlin/com/datastax/examples/mapper/killrvideo/user/UserDao.kt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index de7e3159816..d296439870f 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -27,7 +27,7 @@ You need to build with Java 14, and pass the `--enable-preview` flag to both the runtime JVM. See [pom.xml] in the example. -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html [DataStax-Examples/object-mapper-jvm/record]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/record [pom.xml]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/record/pom.xml diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index b925895c80c..f5d2e120637 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -54,4 +54,4 @@ mapper builder. [DataStax-Examples/object-mapper-jvm/scala]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/scala [build.sbt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/scala/build.sbt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index 091f669f269..6bbd1b9f35a 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -148,8 +148,8 @@ In this case, any annotations declared in `Dao1` would be chosen over `Dao2`. To control how the hierarchy is scanned, annotate interfaces with [@HierarchyScanStrategy]. -[@Dao]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html [Entity Inheritance]: ../entities/#inheritance diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index 705549502de..6b8a6707b48 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -236,8 +236,8 @@ flag: With this configuration, if a DAO method declares a non built-in return type, it will be surfaced as a compiler error. -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/MapperContext.html -[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html -[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/MapperContext.html +[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html +[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index 00831156973..1526079f611 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -151,15 +151,15 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@Delete]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Delete.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@Delete]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Delete.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index 6eff3b1e88b..207f84e136d 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -82,15 +82,15 @@ If the return type doesn't match the parameter type (for example [PagingIterable [AsyncResultSet]), the mapper processor will issue a compile-time error. -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[GettableByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/GettableByName.html -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[GettableByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/GettableByName.html +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html [Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index ede46a8a629..834bdb752f1 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -75,12 +75,12 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[@Increment]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Increment.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Increment]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Increment.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/CqlName.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index 0daf347c5b3..f7bf250b304 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -108,13 +108,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Insert]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Insert]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index 265f2b5a278..bf754441703 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -93,10 +93,10 @@ public interface UserDao extends InventoryDao { } ``` -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[MapperException]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/MapperException.html -[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET -[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[MapperException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/MapperException.html +[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET +[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL [CASSANDRA-7304]: https://issues.apache.org/jira/browse/CASSANDRA-7304 diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index 81ac435b9cd..b95b118c48f 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -113,18 +113,18 @@ Then: query succeeds or not depends on whether the session that the mapper was built with has a [default keyspace]. -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Query]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Query.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[Row]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/Row.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Query]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Query.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index 79423b674c3..e1e71bcc608 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -137,11 +137,11 @@ Here is the full implementation: the desired [PagingIterable][PagingIterable]. -[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html -[providerClass]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- -[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- -[providerMethod]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/MapperContext.html -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/EntityHelper.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html +[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html +[providerClass]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- +[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- +[providerMethod]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/MapperContext.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/EntityHelper.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index 1b00ae17438..3cb6cc168c5 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -155,20 +155,20 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html -[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- -[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- -[groupBy()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- -[limit()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- -[orderBy()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- -[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html +[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- +[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- +[groupBy()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- +[limit()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- +[orderBy()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- +[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index f1f5646265b..54925fac574 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -63,8 +63,8 @@ BoundStatement bind(Product product, BoundStatement statement); If you use a void method with [BoundStatement], the mapper processor will issue a compile-time warning. -[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html -[SettableByName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/SettableByName.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/data/UdtValue.html +[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html +[SettableByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/SettableByName.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index be9c2a2a23a..1793c8ac806 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -60,4 +60,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 22c974ff894..44fcdec02c6 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -143,13 +143,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Update]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Update.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Update]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Update.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html [Boolean]: https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Boolean.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/ResultSet.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index 27039d76d51..35b457f9bb9 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -555,22 +555,22 @@ the same level. To control how the class hierarchy is scanned, annotate classes with [@HierarchyScanStrategy]. -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/CqlName.html -[@Dao]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@Entity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Entity.html -[NameConverter]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html -[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html -[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Computed]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Computed.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Select.html -[@Insert]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[@Update]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Update.html -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[@Query]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Query.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@Entity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Entity.html +[NameConverter]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html +[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html +[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Computed]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Computed.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html +[@Insert]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[@Update]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Update.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[@Query]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Query.html [aliases]: http://cassandra.apache.org/doc/latest/cql/dml.html?#aliases -[@Transient]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Transient.html -[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@Transient]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Transient.html +[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 8d6ee979a75..bebb2a62133 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -230,8 +230,8 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) You can also permanently disable validation of an individual entity by annotating it with `@SchemaHint(targetElement = NONE)`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html -[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html -[@Mapper]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/mapper/annotations/Mapper.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html +[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html +[@Mapper]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Mapper.html diff --git a/manual/osgi/README.md b/manual/osgi/README.md index 65b1efdb85a..be8430c31e7 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -138,7 +138,7 @@ starting the driver: [driver configuration]: ../core/configuration [OSGi]:https://www.osgi.org [JNR]: https://github.com/jnr/jnr-posix -[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- [JAVA-1127]:https://datastax-oss.atlassian.net/browse/JAVA-1127 -[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- -[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- +[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- +[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index ab7c39ffb1a..f4f1c12db73 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -212,8 +212,8 @@ For a complete tour of the API, browse the child pages in this manual: * [Terms](term/) * [Idempotence](idempotence/) -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/CqlIdentifier.html -[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html -[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html +[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html +[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index f4d406da249..8a58139085e 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -132,4 +132,4 @@ It is mutually exclusive with column conditions: if you previously specified col the statement, they will be ignored; conversely, adding a column condition cancels a previous IF EXISTS clause. -[Condition]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/condition/Condition.html +[Condition]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/condition/Condition.html diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index c349f6c8c44..36f0400c43a 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -141,5 +141,5 @@ deleteFrom("user") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index ae17f467843..3442ed55bab 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -114,4 +114,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index 8b6862e4fed..ba55a2c38b8 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -201,5 +201,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Relation]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/relation/Relation.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Relation]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/relation/Relation.html diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index 140b1cf430f..38fc701d798 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -44,4 +44,4 @@ element type: * [function](function/) * [aggregate](aggregate/) -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index b2d005495a6..78de7419719 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -76,4 +76,4 @@ dropAggregate("average").ifExists(); // DROP AGGREGATE IF EXISTS average ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index 7a782dcd6d6..5cf564f99eb 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -92,4 +92,4 @@ dropFunction("log").ifExists(); // DROP FUNCTION IF EXISTS log ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index 0c2603ef0fe..183f4e35fec 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -99,4 +99,4 @@ dropIndex("my_idx").ifExists(); // DROP INDEX IF EXISTS my_idx ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index 9347b3bbb56..643a1354ac7 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -83,6 +83,6 @@ dropKeyspace("cycling").ifExists(); // DROP KEYSPACE IF EXISTS cycling ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index 609395d2b6e..20617636769 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -85,5 +85,5 @@ dropTable("cyclist_by_age").ifExists(); // DROP MATERIALIZED VIEW IF EXISTS cyclist_by_age ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index d743f584002..b7f923d90cc 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -107,6 +107,6 @@ dropTable("cyclist_name").ifExists(); // DROP TABLE IF EXISTS cyclist_name ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html -[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html +[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index cd23078f1eb..f08f3305bcc 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -88,4 +88,4 @@ dropTable("address").ifExists(); // DROP TYPE IF EXISTS address ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index 1b71ea8434c..9ed26281765 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -391,5 +391,5 @@ selectFrom("user").all().allowFiltering(); // SELECT * FROM user ALLOW FILTERING ``` -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index eb95162e3d3..ca650d5d196 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -105,5 +105,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index b1f87d276e9..b513b6a52ab 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -17,4 +17,4 @@ Truncate truncate2 = truncate(CqlIdentifier.fromCql("mytable")); Note that, at this stage, the query is ready to build. After creating a TRUNCATE query it does not take any values. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index 2c75f869220..2069bb54541 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -251,5 +251,5 @@ update("foo") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Assignment]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/querybuilder/update/Assignment.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Assignment]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/update/Assignment.html diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index bf40f0fce47..0f5d46a9ca8 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -68,7 +68,7 @@ Finally, the `datastax-java-driver.basic.load-balancing-policy.filter.class` con has been deprecated; it should be replaced with a node distance evaluator class defined by the `datastax-java-driver.basic.load-balancing-policy.evaluator.class` option instead. -### 4.10.0 +### 4.11.0 #### Cross-datacenter failover @@ -87,26 +87,26 @@ interface that allows custom retry policies to customize the request before it i For this reason, the following methods in the `RetryPolicy` interface were added; they all return a `RetryVerdict` instance: -1. [`onReadTimeoutVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeoutVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) -2. [`onWriteTimeoutVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeoutVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) -3. [`onUnavailableVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onUnavailableVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-int-) -4. [`onRequestAbortedVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAbortedVerdict-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) -5. [`onErrorResponseVerdict`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponseVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) +1. [`onReadTimeoutVerdict`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeoutVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) +2. [`onWriteTimeoutVerdict`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeoutVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) +3. [`onUnavailableVerdict`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onUnavailableVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-int-) +4. [`onRequestAbortedVerdict`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAbortedVerdict-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) +5. [`onErrorResponseVerdict`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponseVerdict-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) The following methods were deprecated and will be removed in the next major version: -1. [`onReadTimeout`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) -2. [`onWriteTimeout`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) -3. [`onUnavailable`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onUnavailable-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-int-) -4. [`onRequestAborted`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAborted-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) -5. [`onErrorResponse`](https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponse-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) +1. [`onReadTimeout`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onReadTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-boolean-int-) +2. [`onWriteTimeout`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onWriteTimeout-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-com.datastax.oss.driver.api.core.servererrors.WriteType-int-int-int-) +3. [`onUnavailable`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onUnavailable-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.ConsistencyLevel-int-int-int-) +4. [`onRequestAborted`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onRequestAborted-com.datastax.oss.driver.api.core.session.Request-java.lang.Throwable-int-) +5. [`onErrorResponse`](https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html#onErrorResponse-com.datastax.oss.driver.api.core.session.Request-com.datastax.oss.driver.api.core.servererrors.CoordinatorException-int-) Driver 4.10.0 also re-introduced a retry policy whose behavior is equivalent to the `DowngradingConsistencyRetryPolicy` from driver 3.x. See this -[FAQ entry](https://docs.datastax.com/en/developer/java-driver/4.10/faq/#where-is-downgrading-consistency-retry-policy) +[FAQ entry](https://docs.datastax.com/en/developer/java-driver/4.11/faq/#where-is-downgrading-consistency-retry-policy) for more information. -[`RetryVerdict`]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[`RetryVerdict`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryVerdict.html #### Enhancements to the `Uuids` utility class @@ -128,9 +128,9 @@ This release also introduces two new methods for random UUID generation: 2. [Uuids.random(SplittableRandom)]: similar to `Uuids.random()` but uses a `java.util.SplittableRandom` instead. -[Uuids.random()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- -[Uuids.random(Random)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.Random- -[Uuids.random(SplittableRandom)]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.SplittableRandom- +[Uuids.random()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[Uuids.random(Random)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.Random- +[Uuids.random(SplittableRandom)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-java.util.SplittableRandom- #### System and DSE keyspaces automatically excluded from metadata and token map computation @@ -152,8 +152,8 @@ empty replicas and token ranges for them. If you need the driver to keep computi token map for these keyspaces, you now must modify the following configuration option: `datastax-java-driver.advanced.metadata.schema.refreshed-keyspaces`. -[Metadata.getKeyspaces()]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/metadata/TokenMap.html +[Metadata.getKeyspaces()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/TokenMap.html #### DSE Graph dependencies are now optional @@ -284,7 +284,7 @@ you can obtain in most web environments by calling `Thread.getContextClassLoader See the javadocs of [SessionBuilder.withClassLoader] for more information. -[SessionBuilder.withClassLoader]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[SessionBuilder.withClassLoader]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- ### 4.1.0 From 667bc97f6012e522ced1aba7b0b156f4e60194c0 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 15:44:02 +0100 Subject: [PATCH 092/395] Various dependency upgrades --- manual/core/integration/README.md | 7 ++++--- pom.xml | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 4927089f98c..6fab5af9003 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -543,6 +543,7 @@ Here are the recommended TinkerPop versions for each driver version: + @@ -640,6 +641,6 @@ The remaining core driver dependencies are the only ones that are truly mandator [guava]: https://github.com/google/guava/issues/2721 [annotation processing]: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#sthref65 -[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- -[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[Uuids]: https://docs.datastax.com/en/drivers/java/4.10/com/datastax/oss/driver/api/core/uuid/Uuids.html +[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- +[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[Uuids]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html diff --git a/pom.xml b/pom.xml index eb6ab69f887..9a570206c18 100644 --- a/pom.xml +++ b/pom.xml @@ -46,27 +46,27 @@ UTF-81.4.12.1.12 - 4.1.16 - 4.1.51.Final + 4.1.18 + 4.1.60.Final1.2.1 - 3.4.9 + 3.4.101.7.261.0.3 - 20201115 - 2.12.0 - 2.12.0 + 20210307 + 2.12.2 + 2.12.21.9.121.1.7.31.7.1 - 3.18.1 + 3.19.01.3 - 4.13.1 + 4.13.21.2.36.0.06.0.3 @@ -77,7 +77,7 @@ 2.5.02.1.11.1.4 - 2.2.20 + 2.2.24.0.32.0.0-M192.22.2 @@ -132,7 +132,7 @@ com.github.jnr jnr-posix - 3.1.2 + 3.1.5 io.dropwizard.metrics @@ -411,22 +411,22 @@ io.micrometer micrometer-core - 1.6.1 + 1.6.5 org.eclipse.microprofile.metrics microprofile-metrics-api - 2.3 + 2.3.3 io.smallrye smallrye-metrics - 2.4.4 + 2.4.6 io.projectreactor reactor-bom - 2020.0.2 + 2020.0.5 pom import From 9a273f053cd55bd60d133b5d91e2e05f7f2e4d52 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 15:52:14 +0100 Subject: [PATCH 093/395] [maven-release-plugin] prepare release 4.11.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index cd1abf49230..0877a5590e8 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-core-shaded - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-mapper-processor - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-mapper-runtime - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-query-builder - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-test-infra - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-metrics-micrometer - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss java-driver-metrics-microprofile - 4.11.0-SNAPSHOT + 4.11.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index dd07c3c8be8..1926d3db213 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 5e545545541..1d0b5360d53 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 65de3f5bbb2..f9f9e615bc9 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index a8aa460b95d..1451b27437a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.0-SNAPSHOT + 4.11.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 5dbcaf6996c..c781b425074 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 5de6def1d9d..7f0b8592082 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index f65a8d9f584..4ddc1f66919 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 5593610f010..5e2d62fb7f5 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 454562e3ed2..5978c80be5e 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 1fb3438eff1..29d36d0b798 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 9a570206c18..df1bf41bf81 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.11.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 5e0e4cf0a89..01ba1b19102 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 4bd0d80bfe2..3094b1145b7 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0-SNAPSHOT + 4.11.0 java-driver-test-infra bundle From 0f7ba2703790b45941baddc2c04c2aeb8c8701c7 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 15:52:23 +0100 Subject: [PATCH 094/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 0877a5590e8..f7cf0094d7a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.11.0 + 4.11.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 1926d3db213..c220da6dc2c 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 1d0b5360d53..221b7966a02 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index f9f9e615bc9..8e67f2862c6 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 1451b27437a..5e4abb3347b 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.0 + 4.11.1-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index c781b425074..677e1421c3c 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 7f0b8592082..da37e82a52f 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 4ddc1f66919..476c480862c 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 5e2d62fb7f5..683b67dd2ca 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 5978c80be5e..e21a2379025 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 29d36d0b798..1d4412be248 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index df1bf41bf81..248b4ab5cfb 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.11.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 01ba1b19102..cd5ae434f65 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 3094b1145b7..034d2c35049 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.0 + 4.11.1-SNAPSHOT java-driver-test-infra bundle From bb0a42b6b91d826f1430b4b92307f2f9b9e68f13 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 17:13:18 +0100 Subject: [PATCH 095/395] Fix wrong release version in upgrade guide --- upgrade_guide/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 0f5d46a9ca8..6ada0de2a13 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -68,7 +68,7 @@ Finally, the `datastax-java-driver.basic.load-balancing-policy.filter.class` con has been deprecated; it should be replaced with a node distance evaluator class defined by the `datastax-java-driver.basic.load-balancing-policy.evaluator.class` option instead. -### 4.11.0 +### 4.10.0 #### Cross-datacenter failover From eea59c6d0be60420ce10cde7be0e4be8f7e5453f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 24 Mar 2021 17:28:59 +0100 Subject: [PATCH 096/395] Improve metric name description --- manual/core/metrics/README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/manual/core/metrics/README.md b/manual/core/metrics/README.md index ab6eb8c7a9f..65a93eb1fbf 100644 --- a/manual/core/metrics/README.md +++ b/manual/core/metrics/README.md @@ -131,16 +131,6 @@ There are two categories of driver metrics: For example, `pool.open-connections` measures the number of connections open to this particular node. -Metric names are path-like, dot-separated strings. The driver prefixes them with the name of the -session (see `session-name` in the configuration), and in the case of node-level metrics, `nodes` -followed by a textual representation of the node's address. For example: - -``` -s0.connected-nodes => 2 -s0.nodes.127_0_0_1:9042.pool.open-connections => 2 -s0.nodes.127_0_0_2:9042.pool.open-connections => 1 -``` - To find out which metrics are available, see the [reference configuration]. It contains a commented-out line for each metric, with detailed explanations on its intended usage. @@ -171,10 +161,20 @@ The `advanced.metrics.id-generator.class` option is used to customize how the dr metric identifiers. The driver ships with two built-in implementations: - `DefaultMetricIdGenerator`: generates identifiers composed solely of (unique) metric names; it - does not generate tags. It is mostly suitable for use with metrics libraries that do not support - tags, like Dropwizard. -- `TaggingMetricIdGenerator`: generates identifiers composed of name and tags. It is mostly suitable - for use with metrics libraries that support tags, like Micrometer or MicroProfile Metrics. + does not generate tags. All metric names start with the name of the session (see `session-name` in + the configuration), and in the case of node-level metrics, this is followed by `.nodes.`, followed + by a textual representation of the node's address. All names end with the metric distinctive name. + See below for examples. This generator is mostly suitable for use with metrics libraries that do + not support tags, like Dropwizard. + +- `TaggingMetricIdGenerator`: generates identifiers composed of a name and one or two tags. + Session-level metric names start with the `session.` prefix followed by the metric distinctive + name; node-level metric names start with the `nodes.` prefix followed by the metric distinctive + name. Session-level tags will include a `session` tag whose value is the session name (see + `session-name` in the configuration); node-level tags will include the same `session` tag, and + also a `node` tag whose value is the node's address. See below for examples. This generator is + mostly suitable for use with metrics libraries that support tags, like Micrometer or MicroProfile + Metrics. For example, here is how each one of them generates identifiers for the session metric "bytes-sent", assuming that the session is named "s0": From b7e384ea2500c1d0ef9cc882604128e6a486b2da Mon Sep 17 00:00:00 2001 From: Dmitry Sysolyatin Date: Wed, 28 Apr 2021 10:59:55 +0300 Subject: [PATCH 097/395] JAVA-2934: Handle empty non-final pages in ReactiveResultSetSubscription (#1544) --- changelog/README.md | 4 +++ .../ReactiveResultSetSubscription.java | 5 +--- .../ReactiveResultSetSubscriptionTest.java | 30 +++++++++++++++++++ .../core/cql/reactive/TestSubscriber.java | 12 +++++++- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 342336ae918..1b58dacb630 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,10 @@ +### 4.12.0 (in progress) + +- [bug] JAVA-2934: Handle empty non-final pages in ReactiveResultSetSubscription + ### 4.11.0 - [improvement] JAVA-2930: Allow Micrometer to record histograms for timers diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscription.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscription.java index 160e71296be..15afd55c06d 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscription.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscription.java @@ -277,13 +277,10 @@ private Object tryNext() { if (pages.poll() == null) { throw new AssertionError("Queue is empty, this should not happen"); } - current = pages.peek(); // if the next page is readily available, // serve its first row now, no need to wait // for the next drain. - if (current != null && current.hasMoreRows()) { - return current.nextRow(); - } + return tryNext(); } } // No items available right now. diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscriptionTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscriptionTest.java index 9a57f9e03fb..1f6664e1662 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscriptionTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/ReactiveResultSetSubscriptionTest.java @@ -145,4 +145,34 @@ public void should_report_error_on_intermediary_page() { assertThat(wasAppliedSubscriber.getElements()).hasSize(1).containsExactly(true); assertThat(wasAppliedSubscriber.getError()).isNull(); } + + @Test + public void should_handle_empty_non_final_pages() { + CompletableFuture future1 = new CompletableFuture<>(); + CompletableFuture future2 = new CompletableFuture<>(); + CompletableFuture future3 = new CompletableFuture<>(); + MockAsyncResultSet page1 = new MockAsyncResultSet(10, future2); + MockAsyncResultSet page2 = new MockAsyncResultSet(0, future3); + MockAsyncResultSet page3 = new MockAsyncResultSet(10, null); + TestSubscriber mainSubscriber = new TestSubscriber<>(1); + TestSubscriber colDefsSubscriber = new TestSubscriber<>(); + TestSubscriber execInfosSubscriber = new TestSubscriber<>(); + TestSubscriber wasAppliedSubscriber = new TestSubscriber<>(); + ReactiveResultSetSubscription subscription = + new ReactiveResultSetSubscription<>( + mainSubscriber, colDefsSubscriber, execInfosSubscriber, wasAppliedSubscriber); + mainSubscriber.onSubscribe(subscription); + subscription.start(() -> future1); + future1.complete(page1); + future2.complete(page2); + // emulate backpressure + subscription.request(1); + future3.complete(page3); + subscription.request(Long.MAX_VALUE); + mainSubscriber.awaitTermination(); + assertThat(mainSubscriber.getError()).isNull(); + List expected = new ArrayList<>(page1.currentPage()); + expected.addAll(page3.currentPage()); + assertThat(mainSubscriber.getElements()).hasSize(20).extracting("row").isEqualTo(expected); + } } diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java index 607bf57aac5..143dff3486d 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java @@ -31,16 +31,25 @@ public class TestSubscriber implements Subscriber { private final List elements = new ArrayList<>(); private final CountDownLatch latch = new CountDownLatch(1); + private final long demand; private Subscription subscription; private Throwable error; + public TestSubscriber() { + this.demand = Long.MAX_VALUE; + } + + public TestSubscriber(long demand) { + this.demand = demand; + } + @Override public void onSubscribe(Subscription s) { if (subscription != null) { fail("already subscribed"); } subscription = s; - s.request(Long.MAX_VALUE); + subscription.request(demand); } @Override @@ -71,5 +80,6 @@ public List getElements() { public void awaitTermination() { Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES); + if (latch.getCount() > 0) fail("subscriber not terminated"); } } From 9f4939c58b901a02ca6c435de43757e5c7e4e3ab Mon Sep 17 00:00:00 2001 From: Erik Merkle Date: Wed, 28 Apr 2021 03:27:38 -0500 Subject: [PATCH 098/395] JAVA-2396: Support Protocol V6 (#1546) Co-authored-by: Alexandre Dutra --- changelog/README.md | 3 ++- .../oss/driver/internal/core/context/DefaultDriverContext.java | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 1b58dacb630..87a37b6c4c1 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,8 +2,9 @@ -### 4.12.0 (in progress) +### 4.11.1 +- [bug] JAVA-2936: Support Protocol V6 - [bug] JAVA-2934: Handle empty non-final pages in ReactiveResultSetSubscription ### 4.11.0 diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index 64925699a64..fd217f9c6c8 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -91,6 +91,7 @@ import com.datastax.oss.protocol.internal.PrimitiveCodec; import com.datastax.oss.protocol.internal.ProtocolV3ClientCodecs; import com.datastax.oss.protocol.internal.ProtocolV5ClientCodecs; +import com.datastax.oss.protocol.internal.ProtocolV6ClientCodecs; import com.datastax.oss.protocol.internal.SegmentCodec; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -435,6 +436,7 @@ protected FrameCodec buildFrameCodec() { new ProtocolV3ClientCodecs(), new ProtocolV4ClientCodecsForDse(), new ProtocolV5ClientCodecs(), + new ProtocolV6ClientCodecs(), new DseProtocolV1ClientCodecs(), new DseProtocolV2ClientCodecs()); } From 7dca8e49881576019bd04c6005e59b7380910589 Mon Sep 17 00:00:00 2001 From: Kelvin Long Date: Sat, 24 Apr 2021 04:12:20 +0800 Subject: [PATCH 099/395] JAVA-2910: Add a configuration option to support strong values for prepared statements cache Co-authored-by: Alexandre Dutra --- changelog/README.md | 3 +- .../api/core/config/DefaultDriverOption.java | 7 ++ .../api/core/config/TypedDriverOption.java | 3 + .../internal/core/session/PoolManager.java | 11 ++- core/src/main/resources/reference.conf | 12 ++++ .../core/session/PoolManagerTest.java | 68 +++++++++++++++++++ 6 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/session/PoolManagerTest.java diff --git a/changelog/README.md b/changelog/README.md index 87a37b6c4c1..d64928b9350 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,8 +2,9 @@ -### 4.11.1 +### 4.11.1 (in progress) +- [bug] JAVA-2910: Add a configuration option to support strong values for prepared statements cache - [bug] JAVA-2936: Support Protocol V6 - [bug] JAVA-2934: Handle empty non-final pages in ReactiveResultSetSubscription diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 8a916705b1b..3d2fde238e9 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -902,6 +902,13 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: List of {@link java.time.Duration Duration} */ METRICS_NODE_CQL_MESSAGES_SLO("advanced.metrics.node.cql-messages.slo"), + + /** + * Whether the prepared statements cache use weak values. + * + *

    Value-type: boolean + */ + PREPARED_CACHE_WEAK_VALUES("advanced.prepared-statements.prepared-cache.weak-values"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index 25d6ac97136..044a7b71de6 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -521,6 +521,9 @@ public String toString() { /** The request timeout when repreparing. */ public static final TypedDriverOption REPREPARE_TIMEOUT = new TypedDriverOption<>(DefaultDriverOption.REPREPARE_TIMEOUT, GenericType.DURATION); + /** Whether the prepared statements cache use weak values. */ + public static final TypedDriverOption PREPARED_CACHE_WEAK_VALUES = + new TypedDriverOption<>(DefaultDriverOption.PREPARED_CACHE_WEAK_VALUES, GenericType.BOOLEAN); /** The number of threads in the I/O group. */ public static final TypedDriverOption NETTY_IO_SIZE = new TypedDriverOption<>(DefaultDriverOption.NETTY_IO_SIZE, GenericType.INTEGER); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java index 68f3519cf52..7580553b0c7 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/PoolManager.java @@ -82,8 +82,7 @@ public class PoolManager implements AsyncAutoCloseable { // (e.g. DefaultPreparedStatement) which are handled at the protocol level (e.g. // CqlPrepareAsyncProcessor). We keep the two separate to avoid introducing a dependency from the // session to a particular processor implementation. - private final ConcurrentMap repreparePayloads = - new MapMaker().weakValues().makeMap(); + private final ConcurrentMap repreparePayloads; private final String logPrefix; private final EventExecutor adminExecutor; @@ -95,6 +94,14 @@ public PoolManager(InternalDriverContext context) { this.adminExecutor = context.getNettyOptions().adminEventExecutorGroup().next(); this.config = context.getConfig().getDefaultProfile(); this.singleThreaded = new SingleThreaded(context); + + if (config.getBoolean(DefaultDriverOption.PREPARED_CACHE_WEAK_VALUES, true)) { + LOG.debug("[{}] Prepared statements cache configured to use weak values", logPrefix); + this.repreparePayloads = new MapMaker().weakValues().makeMap(); + } else { + LOG.debug("[{}] Prepared statements cache configured to use strong values", logPrefix); + this.repreparePayloads = new MapMaker().makeMap(); + } } public CompletionStage init(CqlIdentifier keyspace) { diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 0d56febf841..ab5a33a028d 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -2161,6 +2161,18 @@ datastax-java-driver { # Overridable in a profile: no timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} } + + # How to build the cache of prepared statements. + prepared-cache { + # Whether to use weak references for the prepared statements cache values. + # + # If this option is absent, weak references will be used. + # + # Required: no + # Modifiable at runtime: no + # Overridable in a profile: no + // weak-values = true + } } # Options related to the Netty event loop groups used internally by the driver. diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/PoolManagerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/PoolManagerTest.java new file mode 100644 index 00000000000..f99824d9a24 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/PoolManagerTest.java @@ -0,0 +1,68 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.session; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.internal.core.context.EventBus; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.context.NettyOptions; +import io.netty.channel.DefaultEventLoopGroup; +import java.util.concurrent.ConcurrentHashMap; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class PoolManagerTest { + @Mock private InternalDriverContext context; + @Mock private NettyOptions nettyOptions; + @Mock private DriverConfig config; + @Mock private DriverExecutionProfile defaultProfile; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + DefaultEventLoopGroup adminEventLoopGroup = new DefaultEventLoopGroup(1); + when(nettyOptions.adminEventExecutorGroup()).thenReturn(adminEventLoopGroup); + when(context.getNettyOptions()).thenReturn(nettyOptions); + when(context.getEventBus()).thenReturn(new EventBus("test")); + when(config.getDefaultProfile()).thenReturn(defaultProfile); + when(context.getConfig()).thenReturn(config); + } + + @Test + public void should_use_weak_values_if_config_is_true_or_undefined() { + when(defaultProfile.getBoolean(DefaultDriverOption.PREPARED_CACHE_WEAK_VALUES, true)) + .thenReturn(true); + // As weak values map class is MapMakerInternalMap + assertThat(new PoolManager(context).getRepreparePayloads()) + .isNotInstanceOf(ConcurrentHashMap.class); + } + + @Test + public void should_not_use_weak_values_if_config_is_false() { + when(defaultProfile.getBoolean(DefaultDriverOption.PREPARED_CACHE_WEAK_VALUES, true)) + .thenReturn(false); + assertThat(new PoolManager(context).getRepreparePayloads()) + .isInstanceOf(ConcurrentHashMap.class); + } +} From 5f7b7fa389f97652ab8b5dc283d3ec46b734d8d8 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 28 Apr 2021 11:21:50 +0200 Subject: [PATCH 100/395] Fix ProtocolVersionInitialNegotiationIT for C* 4.0-rc1 --- .../ProtocolVersionInitialNegotiationIT.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java index 366e9fe5669..8ba8986b35b 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java @@ -66,8 +66,8 @@ public void should_downgrade_to_v3_dse() { @CassandraRequirement( min = "2.2", - max = "4.0", - description = "Only C* in [2.2,4.0[ has V4 as its highest version") + max = "4.0-rc1", + description = "Only C* in [2.2,4.0-rc1[ has V4 as its highest version") @Test public void should_downgrade_to_v4_oss() { Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); @@ -77,6 +77,18 @@ public void should_downgrade_to_v4_oss() { } } + @CassandraRequirement( + min = "4.0-rc1", + description = "Only C* in [4.0-rc1,*[ has V5 as its highest version") + @Test + public void should_downgrade_to_v5_oss() { + Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + try (CqlSession session = SessionUtils.newSession(ccm)) { + assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(5); + session.execute("select * from system.local"); + } + } + @DseRequirement( min = "5.0", max = "5.1", @@ -142,8 +154,8 @@ public void should_fail_if_provided_v4_is_not_supported_dse() { @CassandraRequirement( min = "2.1", - max = "4.0", - description = "Only C* in [2.1,4.0[ has V5 unsupported or supported as beta") + max = "4.0-rc1", + description = "Only C* in [2.1,4.0-rc1[ has V5 unsupported or supported as beta") @Test public void should_fail_if_provided_v5_is_not_supported_oss() { Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); From a3c8f45cd7e6739079bf0ed620ca6f5781f94a33 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 28 Apr 2021 11:28:23 +0200 Subject: [PATCH 101/395] Prepare changelog for 4.11.1 release --- changelog/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index d64928b9350..503c5e4f5f2 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,7 +2,7 @@ -### 4.11.1 (in progress) +### 4.11.1 - [bug] JAVA-2910: Add a configuration option to support strong values for prepared statements cache - [bug] JAVA-2936: Support Protocol V6 From f0c77ef67b23a8e99f318fb167bc568189fad054 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 28 Apr 2021 11:41:03 +0200 Subject: [PATCH 102/395] [maven-release-plugin] prepare release 4.11.1 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index f7cf0094d7a..b3d42573a99 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-core-shaded - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-mapper-processor - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-mapper-runtime - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-query-builder - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-test-infra - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-metrics-micrometer - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss java-driver-metrics-microprofile - 4.11.1-SNAPSHOT + 4.11.1 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index c220da6dc2c..7ae90273abd 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 221b7966a02..c74d2bda296 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 8e67f2862c6..ef08210816d 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 5e4abb3347b..f89fcffa4b3 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.1-SNAPSHOT + 4.11.1 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 677e1421c3c..8864d98b0a9 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index da37e82a52f..65df4b6d6d9 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 476c480862c..1f82eb873ed 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 683b67dd2ca..86b41e3db61 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index e21a2379025..9c5111c4c1c 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 1d4412be248..3fb14bc1d95 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 248b4ab5cfb..02d57ec0979 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.11.1 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index cd5ae434f65..4e4d96bc8c9 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 034d2c35049..9cf35c4f38a 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1-SNAPSHOT + 4.11.1 java-driver-test-infra bundle From 6c51faab0fce702c250cf7bbc652484fdfc16f6e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 28 Apr 2021 11:41:13 +0200 Subject: [PATCH 103/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index b3d42573a99..970e0cbcd26 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.11.1 + 4.11.2-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 7ae90273abd..7e204b6726c 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index c74d2bda296..44aeda012e4 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index ef08210816d..73891ec302b 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index f89fcffa4b3..08ee8f717e0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.1 + 4.11.2-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 8864d98b0a9..87c80951e14 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 65df4b6d6d9..99f35eb1986 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 1f82eb873ed..f8e8bcd6c06 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 86b41e3db61..d5072187884 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 9c5111c4c1c..169d04622e7 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 3fb14bc1d95..58820c4ba3d 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 02d57ec0979..a306b90a655 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.11.1 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 4e4d96bc8c9..8eac5a3ffbd 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 9cf35c4f38a..5cf30a2048b 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.1 + 4.11.2-SNAPSHOT java-driver-test-infra bundle From 990c7c6ef5d18ed41c2d91e2fc6797dca5394e70 Mon Sep 17 00:00:00 2001 From: Francisco Bento da Silva Neto Date: Thu, 29 Apr 2021 14:58:32 -0300 Subject: [PATCH 104/395] JAVA-2938: OverloadedException message is misleading --- changelog/README.md | 4 ++++ .../driver/api/core/servererrors/OverloadedException.java | 8 ++++++-- .../oss/driver/internal/core/cql/Conversions.java | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 503c5e4f5f2..5e3c2819a51 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,10 @@ +### 4.11.2 (in progress) + +- [bug] JAVA-2938: OverloadedException message is misleading + ### 4.11.1 - [bug] JAVA-2910: Add a configuration option to support strong values for prepared statements cache diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/OverloadedException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/OverloadedException.java index 4b7b4bb6d9a..300f54a35d5 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/OverloadedException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/OverloadedException.java @@ -27,7 +27,7 @@ /** * Thrown when the coordinator reported itself as being overloaded. * - *

    This exception is processed by {@link RetryPolicy#onErrorResponse(Request, + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, * CoordinatorException, int)}, which will decide if it is rethrown directly to the client or if the * request should be retried. If all other tried nodes also fail, this exception will appear in the * {@link AllNodesFailedException} thrown to the client. @@ -35,7 +35,11 @@ public class OverloadedException extends QueryExecutionException { public OverloadedException(@NonNull Node coordinator) { - super(coordinator, String.format("%s is bootstrapping", coordinator), null, false); + super(coordinator, String.format("%s is overloaded", coordinator), null, false); + } + + public OverloadedException(@NonNull Node coordinator, @NonNull String message) { + super(coordinator, String.format("%s is overloaded: %s", coordinator, message), null, false); } private OverloadedException( diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java index 242bf673a7a..1031ca01bd2 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java @@ -462,7 +462,7 @@ public static CoordinatorException toThrowable( unavailable.required, unavailable.alive); case ProtocolConstants.ErrorCode.OVERLOADED: - return new OverloadedException(node); + return new OverloadedException(node, errorMessage.message); case ProtocolConstants.ErrorCode.IS_BOOTSTRAPPING: return new BootstrappingException(node); case ProtocolConstants.ErrorCode.TRUNCATE_ERROR: From 4d29623df9d3d71a382000bf922daa028914e530 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 18 May 2021 15:59:51 +0200 Subject: [PATCH 105/395] Protect against misbehaving listeners during session init --- .../internal/core/session/DefaultSession.java | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java index b12c287ca60..b134ff027b5 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java @@ -484,9 +484,36 @@ private void notifyListeners() { t); } } - context.getNodeStateListener().onSessionReady(DefaultSession.this); - schemaListenerNotifier.onSessionReady(DefaultSession.this); - context.getRequestTracker().onSessionReady(DefaultSession.this); + try { + context.getNodeStateListener().onSessionReady(DefaultSession.this); + } catch (Throwable t) { + Loggers.warnWithException( + LOG, + "[{}] Error while notifying {} of session ready", + logPrefix, + context.getNodeStateListener(), + t); + } + try { + schemaListenerNotifier.onSessionReady(DefaultSession.this); + } catch (Throwable t) { + Loggers.warnWithException( + LOG, + "[{}] Error while notifying {} of session ready", + logPrefix, + schemaListenerNotifier, + t); + } + try { + context.getRequestTracker().onSessionReady(DefaultSession.this); + } catch (Throwable t) { + Loggers.warnWithException( + LOG, + "[{}] Error while notifying {} of session ready", + logPrefix, + context.getRequestTracker(), + t); + } } private void onNodeStateChanged(NodeStateEvent event) { From feabdf70ac16bee38fbb1a35e99a4c12197f2768 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 18 May 2021 15:59:11 +0200 Subject: [PATCH 106/395] JAVA-2943: Prevent session leak with wrong keyspace name --- changelog/README.md | 1 + .../internal/core/session/DefaultSession.java | 81 ++++++++++--------- .../oss/driver/core/SessionLeakIT.java | 28 +++++++ 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 5e3c2819a51..b8f7bddc996 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2943: Prevent session leak with wrong keyspace name - [bug] JAVA-2938: OverloadedException message is misleading ### 4.11.1 diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java index b134ff027b5..9c04f98466e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java @@ -384,16 +384,30 @@ private void init(CqlIdentifier keyspace) { .getTopologyMonitor() .init() .thenCompose(v -> metadataManager.refreshNodes()) - .thenAccept(v -> afterInitialNodeListRefresh(keyspace)) - .exceptionally( - error -> { - initFuture.completeExceptionally(error); - RunOrSchedule.on(adminExecutor, this::close); - return null; + .thenCompose(v -> checkProtocolVersion()) + .thenCompose(v -> initialSchemaRefresh()) + .thenCompose(v -> initializePools(keyspace)) + .whenComplete( + (v, error) -> { + if (error == null) { + LOG.debug("[{}] Initialization complete, ready", logPrefix); + notifyListeners(); + initFuture.complete(DefaultSession.this); + } else { + LOG.debug("[{}] Initialization failed, force closing", logPrefix, error); + forceCloseAsync() + .whenComplete( + (v1, error1) -> { + if (error1 != null) { + error.addSuppressed(error1); + } + initFuture.completeExceptionally(error); + }); + } }); } - private void afterInitialNodeListRefresh(CqlIdentifier keyspace) { + private CompletionStage checkProtocolVersion() { try { boolean protocolWasForced = context.getConfig().getDefaultProfile().isDefined(DefaultDriverOption.PROTOCOL_VERSION); @@ -426,48 +440,39 @@ private void afterInitialNodeListRefresh(CqlIdentifier keyspace) { bestVersion); } } - metadataManager + return CompletableFuture.completedFuture(null); + } catch (Throwable throwable) { + return CompletableFutures.failedFuture(throwable); + } + } + + private CompletionStage initialSchemaRefresh() { + try { + return metadataManager .refreshSchema(null, false, true) - .whenComplete( - (metadata, error) -> { - if (error != null) { - Loggers.warnWithException( - LOG, - "[{}] Unexpected error while refreshing schema during initialization, " - + "keeping previous version", - logPrefix, - error); - } - afterInitialSchemaRefresh(keyspace); + .exceptionally( + error -> { + Loggers.warnWithException( + LOG, + "[{}] Unexpected error while refreshing schema during initialization, " + + "proceeding without schema metadata", + logPrefix, + error); + return null; }); } catch (Throwable throwable) { - initFuture.completeExceptionally(throwable); + return CompletableFutures.failedFuture(throwable); } } - private void afterInitialSchemaRefresh(CqlIdentifier keyspace) { + private CompletionStage initializePools(CqlIdentifier keyspace) { try { nodeStateManager.markInitialized(); context.getLoadBalancingPolicyWrapper().init(); context.getConfigLoader().onDriverInit(context); - LOG.debug("[{}] Initialization complete, ready", logPrefix); - poolManager - .init(keyspace) - .whenComplete( - (v, error) -> { - if (error != null) { - initFuture.completeExceptionally(error); - } else { - notifyListeners(); - initFuture.complete(DefaultSession.this); - } - }); + return poolManager.init(keyspace); } catch (Throwable throwable) { - forceCloseAsync() - .whenComplete( - (v, error) -> { - initFuture.completeExceptionally(throwable); - }); + return CompletableFutures.failedFuture(throwable); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/SessionLeakIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/SessionLeakIT.java index ef8bf329174..fe70cebbc96 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/SessionLeakIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/SessionLeakIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -25,7 +26,9 @@ import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; +import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.InvalidKeyspaceException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.session.Session; @@ -34,6 +37,7 @@ import com.datastax.oss.driver.categories.IsolatedTests; import com.datastax.oss.driver.internal.core.session.DefaultSession; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import com.datastax.oss.simulacron.common.stubbing.PrimeDsl; import java.util.HashSet; import java.util.Set; import org.junit.Before; @@ -103,4 +107,28 @@ public void should_warn_when_session_count_exceeds_threshold() { verify(appender, never()).doAppend(any()); session.close(); } + + @Test + public void should_never_warn_when_session_init_fails() { + SIMULACRON_RULE + .cluster() + .prime(PrimeDsl.when("USE \"non_existent_keyspace\"").then(PrimeDsl.invalid("irrelevant"))); + int threshold = 4; + // Set the config option explicitly, in case it gets overridden in the test application.conf: + DriverConfigLoader configLoader = + DriverConfigLoader.programmaticBuilder() + .withInt(DefaultDriverOption.SESSION_LEAK_THRESHOLD, threshold) + .build(); + // Go over the threshold, no warnings expected + for (int i = 0; i < threshold + 1; i++) { + try (Session session = + SessionUtils.newSession( + SIMULACRON_RULE, CqlIdentifier.fromCql("non_existent_keyspace"), configLoader)) { + fail("Session %s should have failed to initialize", session.getName()); + } catch (InvalidKeyspaceException e) { + assertThat(e.getMessage()).isEqualTo("Invalid keyspace non_existent_keyspace"); + } + } + verify(appender, never()).doAppend(any()); + } } From e2f46f4820e515551fc7d7f06517a31ebe420a89 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 24 May 2021 15:50:52 +0200 Subject: [PATCH 107/395] JAVA-2941: Cannot add a single static column with the alter table API (#1549) --- changelog/README.md | 1 + .../schema/DefaultAlterTable.java | 54 +++++++++---------- .../querybuilder/schema/AlterTableTest.java | 6 +++ 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index b8f7bddc996..ab4d09914c1 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2941: Cannot add a single static column with the alter table API - [bug] JAVA-2943: Prevent session leak with wrong keyspace name - [bug] JAVA-2938: OverloadedException message is misleading diff --git a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/DefaultAlterTable.java b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/DefaultAlterTable.java index d575ced177b..ae2171373c6 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/DefaultAlterTable.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/DefaultAlterTable.java @@ -46,8 +46,8 @@ public class DefaultAlterTable private final CqlIdentifier keyspace; private final CqlIdentifier tableName; - private final ImmutableMap columnsToAddInOrder; - private final ImmutableSet columnsToAdd; + private final ImmutableMap allColumnsToAddInOrder; + private final ImmutableSet columnsToAddRegular; private final ImmutableSet columnsToAddStatic; private final ImmutableSet columnsToDrop; private final ImmutableMap columnsToRename; @@ -79,8 +79,8 @@ public DefaultAlterTable( @Nullable CqlIdentifier keyspace, @NonNull CqlIdentifier tableName, boolean dropCompactStorage, - @NonNull ImmutableMap columnsToAddInOrder, - @NonNull ImmutableSet columnsToAdd, + @NonNull ImmutableMap allColumnsToAddInOrder, + @NonNull ImmutableSet columnsToAddRegular, @NonNull ImmutableSet columnsToAddStatic, @NonNull ImmutableSet columnsToDrop, @NonNull ImmutableMap columnsToRename, @@ -90,8 +90,8 @@ public DefaultAlterTable( this.keyspace = keyspace; this.tableName = tableName; this.dropCompactStorage = dropCompactStorage; - this.columnsToAddInOrder = columnsToAddInOrder; - this.columnsToAdd = columnsToAdd; + this.allColumnsToAddInOrder = allColumnsToAddInOrder; + this.columnsToAddRegular = columnsToAddRegular; this.columnsToAddStatic = columnsToAddStatic; this.columnsToDrop = columnsToDrop; this.columnsToRename = columnsToRename; @@ -108,8 +108,8 @@ public AlterTableAddColumnEnd addColumn( keyspace, tableName, dropCompactStorage, - ImmutableCollections.append(columnsToAddInOrder, columnName, dataType), - appendSet(columnsToAdd, columnName), + ImmutableCollections.append(allColumnsToAddInOrder, columnName, dataType), + appendSet(columnsToAddRegular, columnName), columnsToAddStatic, columnsToDrop, columnsToRename, @@ -126,8 +126,8 @@ public AlterTableAddColumnEnd addStaticColumn( keyspace, tableName, dropCompactStorage, - ImmutableCollections.append(columnsToAddInOrder, columnName, dataType), - columnsToAdd, + ImmutableCollections.append(allColumnsToAddInOrder, columnName, dataType), + columnsToAddRegular, appendSet(columnsToAddStatic, columnName), columnsToDrop, columnsToRename, @@ -143,8 +143,8 @@ public BuildableQuery dropCompactStorage() { keyspace, tableName, true, - columnsToAddInOrder, - columnsToAdd, + allColumnsToAddInOrder, + columnsToAddRegular, columnsToAddStatic, columnsToDrop, columnsToRename, @@ -166,8 +166,8 @@ public AlterTableDropColumnEnd dropColumns(@NonNull CqlIdentifier... columnNames keyspace, tableName, dropCompactStorage, - columnsToAddInOrder, - columnsToAdd, + allColumnsToAddInOrder, + columnsToAddRegular, columnsToAddStatic, builder.build(), columnsToRename, @@ -184,8 +184,8 @@ public AlterTableRenameColumnEnd renameColumn( keyspace, tableName, dropCompactStorage, - columnsToAddInOrder, - columnsToAdd, + allColumnsToAddInOrder, + columnsToAddRegular, columnsToAddStatic, columnsToDrop, ImmutableCollections.append(columnsToRename, from, to), @@ -201,8 +201,8 @@ public BuildableQuery alterColumn(@NonNull CqlIdentifier columnName, @NonNull Da keyspace, tableName, dropCompactStorage, - columnsToAddInOrder, - columnsToAdd, + allColumnsToAddInOrder, + columnsToAddRegular, columnsToAddStatic, columnsToDrop, columnsToRename, @@ -218,8 +218,8 @@ public AlterTableWithOptionsEnd withOption(@NonNull String name, @NonNull Object keyspace, tableName, dropCompactStorage, - columnsToAddInOrder, - columnsToAdd, + allColumnsToAddInOrder, + columnsToAddRegular, columnsToAddStatic, columnsToDrop, columnsToRename, @@ -242,13 +242,13 @@ public String asCql() { .append(" TYPE ") .append(columnToAlterType.asCql(true, true)) .toString(); - } else if (!columnsToAdd.isEmpty()) { + } else if (!allColumnsToAddInOrder.isEmpty()) { builder.append(" ADD "); - if (columnsToAdd.size() > 1) { + if (allColumnsToAddInOrder.size() > 1) { builder.append('('); } boolean first = true; - for (Map.Entry column : columnsToAddInOrder.entrySet()) { + for (Map.Entry column : allColumnsToAddInOrder.entrySet()) { if (first) { first = false; } else { @@ -263,7 +263,7 @@ public String asCql() { builder.append(" STATIC"); } } - if (columnsToAdd.size() > 1) { + if (allColumnsToAddInOrder.size() > 1) { builder.append(')'); } return builder.toString(); @@ -324,13 +324,13 @@ public CqlIdentifier getTable() { } @NonNull - public ImmutableMap getColumnsToAddInOrder() { - return columnsToAddInOrder; + public ImmutableMap getAllColumnsToAddInOrder() { + return allColumnsToAddInOrder; } @NonNull public ImmutableSet getColumnsToAddRegular() { - return columnsToAdd; + return columnsToAddRegular; } @NonNull diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java index 16db985ba9c..8a353095ead 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java @@ -40,6 +40,12 @@ public void should_generate_alter_table_with_add_single_column() { .hasCql("ALTER TABLE foo.bar ADD x text"); } + @Test + public void should_generate_alter_table_with_add_single_column_static() { + assertThat(alterTable("foo", "bar").addStaticColumn("x", DataTypes.TEXT)) + .hasCql("ALTER TABLE foo.bar ADD x text STATIC"); + } + @Test public void should_generate_alter_table_with_add_three_columns() { assertThat( From c6b6b7365cb27317bc85da8bc71e2ffda029bdfb Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 18 May 2021 18:34:38 +0200 Subject: [PATCH 108/395] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective --- changelog/README.md | 1 + .../internal/core/graph/GraphConversions.java | 8 +++-- .../core/graph/GraphRequestHandlerTest.java | 32 +++++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index ab4d09914c1..8c50e896ce2 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective - [bug] JAVA-2941: Cannot add a single static column with the alter table API - [bug] JAVA-2943: Prevent session leak with wrong keyspace name - [bug] JAVA-2938: OverloadedException message is misleading diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java index 53f8e98b0ee..e7b5af29ecd 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphConversions.java @@ -179,9 +179,13 @@ static Message createMessageFromGraphStatement( } } + ConsistencyLevel consistency = statement.getConsistencyLevel(); int consistencyLevel = - DefaultConsistencyLevel.valueOf(config.getString(DefaultDriverOption.REQUEST_CONSISTENCY)) - .getProtocolCode(); + (consistency == null) + ? context + .getConsistencyLevelRegistry() + .nameToCode(config.getString(DefaultDriverOption.REQUEST_CONSISTENCY)) + : consistency.getProtocolCode(); long timestamp = statement.getTimestamp(); if (timestamp == Statement.NO_DEFAULT_TIMESTAMP) { diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandlerTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandlerTest.java index aed0eb4ade4..2e27dc79cd3 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandlerTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandlerTest.java @@ -137,7 +137,7 @@ public void should_create_query_message_from_fluent_statement(GraphProtocol grap throws IOException { // initialization GraphRequestHandlerTestHarness harness = GraphRequestHandlerTestHarness.builder().build(); - GraphTraversal traversalTest = + GraphTraversal traversalTest = DseGraph.g.V().has("person", "name", "marko").has("p1", 1L).has("p2", Uuids.random()); GraphStatement graphStatement = FluentGraphStatement.newInstance(traversalTest); @@ -171,6 +171,7 @@ public void should_create_query_message_from_batch_statement(GraphProtocol graph throws IOException { // initialization GraphRequestHandlerTestHarness harness = GraphRequestHandlerTestHarness.builder().build(); + @SuppressWarnings("rawtypes") List traversalsTest = ImmutableList.of( // randomly testing some complex data types. Complete suite of data types test is in @@ -424,7 +425,7 @@ public void should_return_results_for_statements(GraphProtocol graphProtocol, Ve Mockito.spy(new GraphRequestAsyncProcessor(harness.getContext(), graphSupportChecker)); when(p.getGraphBinaryModule()).thenReturn(module); - GraphStatement graphStatement = + GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery").setExecutionProfileName("test-graph"); GraphResultSet grs = new GraphRequestSyncProcessor(p) @@ -487,7 +488,7 @@ public void should_invoke_request_tracker_and_update_metrics( RequestTracker requestTracker = mock(RequestTracker.class); when(harness.getContext().getRequestTracker()).thenReturn(requestTracker); - GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery"); + GraphStatement graphStatement = ScriptGraphStatement.newInstance("mockQuery"); node1Behavior.setResponseSuccess(defaultDseFrameOf(singleGraphRow(graphProtocol, module))); @@ -549,6 +550,31 @@ public void should_invoke_request_tracker_and_update_metrics( verifyNoMoreInteractions(harness.getSession().getMetricUpdater()); } + @Test + public void should_honor_statement_consistency_level() { + // initialization + GraphRequestHandlerTestHarness harness = GraphRequestHandlerTestHarness.builder().build(); + ScriptGraphStatement graphStatement = + ScriptGraphStatement.builder("mockScript") + .setConsistencyLevel(DefaultConsistencyLevel.THREE) + .build(); + + GraphBinaryModule module = createGraphBinaryModule(harness.getContext()); + + // when + DriverExecutionProfile executionProfile = + Conversions.resolveExecutionProfile(graphStatement, harness.getContext()); + + Message m = + GraphConversions.createMessageFromGraphStatement( + graphStatement, GRAPH_BINARY_1_0, executionProfile, harness.getContext(), module); + + // checks + assertThat(m).isInstanceOf(Query.class); + Query q = ((Query) m); + assertThat(q.options.consistency).isEqualTo(DefaultConsistencyLevel.THREE.getProtocolCode()); + } + @DataProvider public static Object[][] dseVersionsWithDefaultGraphProtocol() { // Default GraphSON sub protocol version differs based on DSE version, so test with a version From 761dc9045922f2524e413eadb6f9580944859457 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 18 May 2021 18:35:02 +0200 Subject: [PATCH 109/395] Make field ScriptGraphStatementBuilder.queryParams final --- .../dse/driver/api/core/graph/ScriptGraphStatementBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/dse/driver/api/core/graph/ScriptGraphStatementBuilder.java b/core/src/main/java/com/datastax/dse/driver/api/core/graph/ScriptGraphStatementBuilder.java index 9a8d0d262eb..768264426ec 100644 --- a/core/src/main/java/com/datastax/dse/driver/api/core/graph/ScriptGraphStatementBuilder.java +++ b/core/src/main/java/com/datastax/dse/driver/api/core/graph/ScriptGraphStatementBuilder.java @@ -34,7 +34,7 @@ public class ScriptGraphStatementBuilder private String script; private Boolean isSystemQuery; - private Map queryParams; + private final Map queryParams; public ScriptGraphStatementBuilder() { this.queryParams = Maps.newHashMap(); From 0e80c2573726c676296d78bacd4cabd825e47d88 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 24 May 2021 16:50:50 +0200 Subject: [PATCH 110/395] Fix typo in javadocs of MetricIdGenerator --- .../oss/driver/internal/core/metrics/MetricIdGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java index 7cfd39bf37b..176101034ae 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java @@ -41,7 +41,7 @@ public interface MetricIdGenerator { @NonNull MetricId sessionMetricId(@NonNull SessionMetric metric); - /** Generates a {@link MetricId} for the given {@link Node and }{@link NodeMetric}. */ + /** Generates a {@link MetricId} for the given {@link Node} and {@link NodeMetric}. */ @NonNull MetricId nodeMetricId(@NonNull Node node, @NonNull NodeMetric metric); } From 2e25a49ca2647e8fefdda084edd379e8018d9dcf Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 24 May 2021 17:00:42 +0200 Subject: [PATCH 111/395] Set version to 4.12.0-SNAPSHOT --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 2 +- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 970e0cbcd26..f50076bb957 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 7e204b6726c..414d305fb2a 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 44aeda012e4..5da7d297d88 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 73891ec302b..cfd4596ddb4 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 08ee8f717e0..cf67d0aa406 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 87c80951e14..d30a6cd9abe 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 99f35eb1986..53f2c874759 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index f8e8bcd6c06..1890231c202 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index d5072187884..3f54eeb3959 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 169d04622e7..48782b475c9 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 58820c4ba3d..c88c033d4d6 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index a306b90a655..b6602f484a3 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 8eac5a3ffbd..7fc68474e2c 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 5cf30a2048b..f1000d40618 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.12.0-SNAPSHOT java-driver-test-infra bundle From c5595555dccefb93b7db6854d57af18da9fed1af Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 24 May 2021 16:50:50 +0200 Subject: [PATCH 112/395] Fix typo in javadocs of MetricIdGenerator --- .../oss/driver/internal/core/metrics/MetricIdGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java index 7cfd39bf37b..176101034ae 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricIdGenerator.java @@ -41,7 +41,7 @@ public interface MetricIdGenerator { @NonNull MetricId sessionMetricId(@NonNull SessionMetric metric); - /** Generates a {@link MetricId} for the given {@link Node and }{@link NodeMetric}. */ + /** Generates a {@link MetricId} for the given {@link Node} and {@link NodeMetric}. */ @NonNull MetricId nodeMetricId(@NonNull Node node, @NonNull NodeMetric metric); } From 52f355039969a6ec1996088aedaad39a2eae465a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 24 May 2021 19:59:37 +0200 Subject: [PATCH 113/395] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader --- changelog/README.md | 1 + .../internal/mapper/DefaultMapperContext.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 8c50e896ce2..f08c735c369 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader - [bug] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective - [bug] JAVA-2941: Cannot add a single static column with the alter table API - [bug] JAVA-2943: Prevent session leak with wrong keyspace name diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java index 9ba08d8c65d..4db909488e8 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java @@ -24,12 +24,12 @@ import com.datastax.oss.driver.api.mapper.entity.naming.NameConverter; import com.datastax.oss.driver.api.mapper.result.MapperResultProducer; import com.datastax.oss.driver.api.mapper.result.MapperResultProducerService; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.lang.reflect.InvocationTargetException; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; @@ -38,9 +38,7 @@ public class DefaultMapperContext implements MapperContext { - private static final List RESULT_PRODUCERS = getResultProducers(); - - private static final ConcurrentMap, MapperResultProducer> RESULT_PRODUCER_CACHE = + private final ConcurrentMap, MapperResultProducer> resultProducerCache = new ConcurrentHashMap<>(); private final CqlSession session; @@ -50,6 +48,7 @@ public class DefaultMapperContext implements MapperContext { private final DriverExecutionProfile executionProfile; private final ConcurrentMap, NameConverter> nameConverterCache; private final Map customState; + private final ImmutableList resultProducers; public DefaultMapperContext( @NonNull CqlSession session, @@ -86,6 +85,8 @@ private DefaultMapperContext( this.customState = customState; this.executionProfileName = executionProfileName; this.executionProfile = executionProfile; + this.resultProducers = + locateResultProducers(((InternalDriverContext) session.getContext()).getClassLoader()); } public DefaultMapperContext withDaoParameters( @@ -154,10 +155,10 @@ public Map getCustomState() { @NonNull @Override public MapperResultProducer getResultProducer(@NonNull GenericType resultToProduce) { - return RESULT_PRODUCER_CACHE.computeIfAbsent( + return resultProducerCache.computeIfAbsent( resultToProduce, k -> { - for (MapperResultProducer resultProducer : RESULT_PRODUCERS) { + for (MapperResultProducer resultProducer : resultProducers) { if (resultProducer.canProduce(k)) { return resultProducer; } @@ -185,10 +186,11 @@ private static NameConverter buildNameConverter(Class c } } - private static List getResultProducers() { + private static ImmutableList locateResultProducers( + ClassLoader classLoader) { ImmutableList.Builder result = ImmutableList.builder(); ServiceLoader loader = - ServiceLoader.load(MapperResultProducerService.class); + ServiceLoader.load(MapperResultProducerService.class, classLoader); loader.iterator().forEachRemaining(provider -> result.addAll(provider.getProducers())); return result.build(); } From dfb816e5f7476cd0417ca0741b4326c43b6d832f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 25 May 2021 16:56:36 +0200 Subject: [PATCH 114/395] Add debug logging and exception handling to DefaultMapperContext.locateResultProducers --- .../internal/mapper/DefaultMapperContext.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java index 4db909488e8..92555495098 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DefaultMapperContext.java @@ -32,12 +32,17 @@ import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.Objects; +import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DefaultMapperContext implements MapperContext { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultMapperContext.class); + private final ConcurrentMap, MapperResultProducer> resultProducerCache = new ConcurrentHashMap<>(); @@ -188,10 +193,20 @@ private static NameConverter buildNameConverter(Class c private static ImmutableList locateResultProducers( ClassLoader classLoader) { - ImmutableList.Builder result = ImmutableList.builder(); - ServiceLoader loader = - ServiceLoader.load(MapperResultProducerService.class, classLoader); - loader.iterator().forEachRemaining(provider -> result.addAll(provider.getProducers())); - return result.build(); + LOGGER.debug( + "Locating result producers with CL = {}, MapperResultProducerService CL = {}", + classLoader, + MapperResultProducerService.class.getClassLoader()); + ImmutableList.Builder builder = ImmutableList.builder(); + try { + ServiceLoader loader = + ServiceLoader.load(MapperResultProducerService.class, classLoader); + loader.iterator().forEachRemaining(provider -> builder.addAll(provider.getProducers())); + } catch (Exception | ServiceConfigurationError e) { + LOGGER.error("Failed to locate result producers", e); + } + ImmutableList producers = builder.build(); + LOGGER.debug("Located {} result producers: {}", producers.size(), producers); + return producers; } } From 58e79503de9a2e8b13464cb38a53c424b6ba2ccf Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 25 May 2021 18:57:55 +0200 Subject: [PATCH 115/395] Disable CloudIT --- .../java/com/datastax/oss/driver/api/core/cloud/CloudIT.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/api/core/cloud/CloudIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/api/core/cloud/CloudIT.java index 7fbcd631e86..7874c4719d8 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/api/core/cloud/CloudIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/api/core/cloud/CloudIT.java @@ -51,11 +51,13 @@ import java.util.List; import javax.net.ssl.SSLContext; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @Category(IsolatedTests.class) +@Ignore("Disabled because it is causing trouble in Jenkins CI") public class CloudIT { private static final String BUNDLE_URL_PATH = "/certs/bundles/creds.zip"; From d23ddafdcd84145f7cb622b6351bad8b345469ea Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 5 Jun 2021 12:07:10 +0200 Subject: [PATCH 116/395] Fix failing compression tests for protocol v5 --- .../core/compression/DirectCompressionIT.java | 13 ++++++++++++- .../driver/core/compression/HeapCompressionIT.java | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java index ef2d9803369..4f4ff89db47 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.offset; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.cql.ExecutionInfo; @@ -30,6 +31,7 @@ import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; import java.time.Duration; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -69,6 +71,10 @@ public static void setup() { */ @Test public void should_execute_queries_with_snappy_compression() throws Exception { + Assume.assumeTrue( + "Snappy is not supported in OSS C* 4.0+ with protocol v5", + CCM_RULE.getDseVersion().isPresent() + || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0); createAndCheckCluster("snappy"); } @@ -112,7 +118,12 @@ private void createAndCheckCluster(String compressorOption) { // We are testing with small responses, so the compressed payload is not even guaranteed to be // smaller. assertThat(executionInfo.getResponseSizeInBytes()).isGreaterThan(0); - assertThat(executionInfo.getCompressedResponseSizeInBytes()).isGreaterThan(0); + if (session.getContext().getProtocolVersion().getCode() == 5) { + // in protocol v5, compression is done at segment level + assertThat(executionInfo.getCompressedResponseSizeInBytes()).isEqualTo(-1); + } else { + assertThat(executionInfo.getCompressedResponseSizeInBytes()).isGreaterThan(0); + } } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java index 64b890fd7f6..85692edc481 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.offset; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.cql.ExecutionInfo; @@ -30,6 +31,7 @@ import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.IsolatedTests; import java.time.Duration; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -73,6 +75,10 @@ public static void setup() { */ @Test public void should_execute_queries_with_snappy_compression() throws Exception { + Assume.assumeTrue( + "Snappy is not supported in OSS C* 4.0+ with protocol v5", + CCM_RULE.getDseVersion().isPresent() + || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0); createAndCheckCluster("snappy"); } @@ -115,7 +121,12 @@ private void createAndCheckCluster(String compressorOption) { // We are testing with small responses, so the compressed payload is not even guaranteed to be // smaller. assertThat(executionInfo.getResponseSizeInBytes()).isGreaterThan(0); - assertThat(executionInfo.getCompressedResponseSizeInBytes()).isGreaterThan(0); + if (session.getContext().getProtocolVersion().getCode() == 5) { + // in protocol v5, compression is done at segment level + assertThat(executionInfo.getCompressedResponseSizeInBytes()).isEqualTo(-1); + } else { + assertThat(executionInfo.getCompressedResponseSizeInBytes()).isGreaterThan(0); + } } } } From ad833714aae298e7a38c65ec3e32100e4961b9c4 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 5 Jun 2021 12:07:34 +0200 Subject: [PATCH 117/395] Remove call to deprecated RetryPolicy method --- .../datastax/oss/driver/core/connection/FrameLengthIT.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java index c4f39711687..3c42bd8f630 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/FrameLengthIT.java @@ -29,7 +29,7 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import com.datastax.oss.driver.api.core.cql.SimpleStatement; -import com.datastax.oss.driver.api.core.retry.RetryDecision; +import com.datastax.oss.driver.api.core.retry.RetryVerdict; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.testinfra.loadbalancing.SortingLoadBalancingPolicy; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -122,10 +122,9 @@ public AlwaysRetryAbortedPolicy(DriverContext context, String profileName) { } @Override - @Deprecated - public RetryDecision onRequestAborted( + public RetryVerdict onRequestAbortedVerdict( @NonNull Request request, @NonNull Throwable error, int retryCount) { - return RetryDecision.RETRY_NEXT; + return RetryVerdict.RETRY_NEXT; } } } From edb2dc277b07887200374301b637f9a31ac0346e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 5 Jun 2021 12:52:41 +0200 Subject: [PATCH 118/395] Fix failing test for C* 4.0 --- .../oss/driver/core/cql/QueryTraceIT.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java index 567a1263310..8c12e7154fc 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java @@ -22,6 +22,7 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.cql.ExecutionInfo; import com.datastax.oss.driver.api.core.cql.QueryTrace; +import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; @@ -86,7 +87,20 @@ public void should_fetch_trace_when_tracing_enabled() { assertThat(queryTrace.getRequestType()).isEqualTo("Execute CQL3 query"); assertThat(queryTrace.getDurationMicros()).isPositive(); assertThat(queryTrace.getCoordinatorAddress().getAddress()).isEqualTo(nodeAddress); - assertThat(queryTrace.getCoordinatorAddress().getPort()).isEqualTo(expectPorts ? 7000 : 0); + if (expectPorts) { + Row row = + SESSION_RULE + .session() + .execute( + "SELECT coordinator_port FROM system_traces.sessions WHERE session_id = " + + queryTrace.getTracingId()) + .one(); + assertThat(row).isNotNull(); + int expectedPort = row.getInt(0); + assertThat(queryTrace.getCoordinatorAddress().getPort()).isEqualTo(expectedPort); + } else { + assertThat(queryTrace.getCoordinatorAddress().getPort()).isEqualTo(0); + } assertThat(queryTrace.getParameters()) .containsEntry("consistency_level", "LOCAL_ONE") .containsEntry("page_size", "5000") @@ -98,6 +112,20 @@ public void should_fetch_trace_when_tracing_enabled() { InetSocketAddress sourceAddress0 = queryTrace.getEvents().get(0).getSourceAddress(); assertThat(sourceAddress0).isNotNull(); assertThat(sourceAddress0.getAddress()).isEqualTo(nodeAddress); - assertThat(sourceAddress0.getPort()).isEqualTo(expectPorts ? 7000 : 0); + if (expectPorts) { + Row row = + SESSION_RULE + .session() + .execute( + "SELECT source_port FROM system_traces.events WHERE session_id = " + + queryTrace.getTracingId() + + " LIMIT 1") + .one(); + assertThat(row).isNotNull(); + int expectedPort = row.getInt(0); + assertThat(sourceAddress0.getPort()).isEqualTo(expectedPort); + } else { + assertThat(sourceAddress0.getPort()).isEqualTo(0); + } } } From 464d3d23ee0fef8285d48a7b9865f7d076e12842 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 5 Jun 2021 13:53:18 +0200 Subject: [PATCH 119/395] Fix failing test for C* 4.0 --- .../com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java index f524de74fad..9794cf27435 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.osgi; import com.datastax.oss.driver.api.osgi.service.MailboxService; +import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.internal.osgi.checks.DefaultServiceChecks; import com.datastax.oss.driver.internal.osgi.support.BundleOptions; import com.datastax.oss.driver.internal.osgi.support.CcmExamReactorFactory; @@ -30,6 +31,7 @@ @RunWith(CcmPaxExam.class) @ExamReactorStrategy(CcmExamReactorFactory.class) +@CassandraRequirement(max = "3.99") public class OsgiSnappyIT { @Inject MailboxService service; From b87c6f5afa15965de8b257758ff5e788bc46d9c1 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 26 May 2021 13:46:39 +0200 Subject: [PATCH 120/395] Fix unreliable TTL tests --- .../java/com/datastax/oss/driver/mapper/UpdateIT.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java index 00df838b2a8..dd6993ee40d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java @@ -158,6 +158,7 @@ public void should_update_entity_with_timestamp() { "SELECT WRITETIME(description) FROM product WHERE id = ?", FLAMETHROWER.getId())) .one(); + assertThat(row).isNotNull(); long writeTime = row.getLong(0); assertThat(writeTime).isEqualTo(timestamp); } @@ -176,6 +177,7 @@ public void should_update_entity_with_timestamp_literal() { "SELECT WRITETIME(description) FROM product WHERE id = ?", FLAMETHROWER.getId())) .one(); + assertThat(row).isNotNull(); long writeTime = row.getLong(0); assertThat(writeTime).isEqualTo(1000L); } @@ -194,8 +196,9 @@ public void should_update_entity_with_ttl() { SimpleStatement.newInstance( "SELECT TTL(description) FROM product WHERE id = ?", FLAMETHROWER.getId())) .one(); + assertThat(row).isNotNull(); int writeTime = row.getInt(0); - assertThat(writeTime).isEqualTo(ttl); + assertThat(writeTime).isBetween(ttl - 10, ttl); } @Test @@ -211,8 +214,9 @@ public void should_update_entity_with_ttl_literal() { SimpleStatement.newInstance( "SELECT TTL(description) FROM product WHERE id = ?", FLAMETHROWER.getId())) .one(); + assertThat(row).isNotNull(); int writeTime = row.getInt(0); - assertThat(writeTime).isEqualTo(1000); + assertThat(writeTime).isBetween(990, 1000); } @Test @@ -231,6 +235,7 @@ public void should_update_entity_with_timestamp_asynchronously() { "SELECT WRITETIME(description) FROM product WHERE id = ?", FLAMETHROWER.getId())) .one(); + assertThat(row).isNotNull(); long writeTime = row.getLong(0); assertThat(writeTime).isEqualTo(timestamp); } From 9a34929bc2306eeb4e8727d9ff934cb81c61ab27 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 26 May 2021 15:00:37 +0200 Subject: [PATCH 121/395] Remove DSE 6.8.0 from list of available CCM backends --- Jenkinsfile | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 95eb2aa20b0..35d31bfcb4a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -220,8 +220,7 @@ pipeline { 'dse-5.1', // Legacy DataStax Enterprise 'dse-6.0', // Previous DataStax Enterprise 'dse-6.7', // Previous DataStax Enterprise - 'dse-6.8.0', // Current DataStax Enterprise - 'dse-6.8', // Development DataStax Enterprise + 'dse-6.8', // Current DataStax Enterprise 'ALL'], description: '''Apache Cassandra® and DataStax Enterprise server version to use for adhoc BUILD-AND-EXECUTE-TESTS builds

    Driver versionTinkerPop version
    4.11.03.4.10
    4.10.03.4.9
    4.9.03.4.8
    4.8.03.4.5
    @@ -271,13 +270,9 @@ pipeline { - - - - - +
    dse-6.7 DataStax Enterprise v6.7.x
    dse-6.8.0DataStax Enterprise v6.8.0
    dse-6.8DataStax Enterprise v6.8.x (CURRENTLY UNDER DEVELOPMENT)DataStax Enterprise v6.8.x
    ''') choice( @@ -403,7 +398,7 @@ pipeline { name 'SERVER_VERSION' values '3.11', // Latest stable Apache CassandraⓇ '4.0', // Development Apache CassandraⓇ - 'dse-6.8.0' // Current DataStax Enterprise + 'dse-6.8' // Current DataStax Enterprise } } @@ -521,8 +516,7 @@ pipeline { 'dse-5.1', // Legacy DataStax Enterprise 'dse-6.0', // Previous DataStax Enterprise 'dse-6.7', // Previous DataStax Enterprise - 'dse-6.8.0', // Current DataStax Enterprise - 'dse-6.8' // Development DataStax Enterprise + 'dse-6.8' // Current DataStax Enterprise } } when { From 1d5b12ec5d3c3f7ccb163ff04f38450bb097f290 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Wed, 26 May 2021 15:17:26 +0200 Subject: [PATCH 122/395] Simplify nightly and weekend jobs --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 35d31bfcb4a..f922d9f7c5f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -358,11 +358,11 @@ pipeline { # Every weeknight (Monday - Friday) around 2:00 AM ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0 and DSE 6.7 H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7;CI_SCHEDULE_JABBA_VERSION=1.8 - ### JDK11 tests against 3.11, 4.0, DSE 6.7 and DSE 6.8.0 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.7 dse-6.8.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 + ### JDK11 tests against 3.11, 4.0 and DSE 6.8 + H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 # Every weekend (Sunday) around 12:00 PM noon - ### JDK14 tests against 3.11, 4.0, DSE 6.7, DSE 6.8.0 and DSE 6.8.X - H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.7 dse-6.8.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 + ### JDK14 tests against 3.11, 4.0, DSE 6.7 and DSE 6.8 + H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.7 dse-6.8 ;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 """ : "") } From a54326fb48a4970fe61c98df99baaaab29a25a42 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 7 Jun 2021 11:52:26 +0200 Subject: [PATCH 123/395] Truncate generated Instants at millis --- .../dse/driver/api/core/graph/CoreGraphDataTypeITBase.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java index 333110096a7..5273367ace0 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphDataTypeITBase.java @@ -44,6 +44,7 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Map; import org.junit.Test; @@ -83,7 +84,7 @@ public void should_create_and_retrieve_correct_data_with_types() { .put("Text", "test") .put("Time", LocalTime.now(ZoneId.systemDefault())) .put("Timeuuid", Uuids.timeBased()) - .put("Timestamp", Instant.now()) + .put("Timestamp", Instant.now().truncatedTo(ChronoUnit.MILLIS)) .put("Uuid", java.util.UUID.randomUUID()) .put("Varint", BigInteger.valueOf(3234)) .put("Blob", ByteBuffer.wrap(new byte[] {1, 2, 3})) From 67eb54e06e7089adf0e7d089699ca4fcd788fd53 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 7 Jun 2021 11:52:40 +0200 Subject: [PATCH 124/395] Fix failing BlockHound tests for Java 13+ --- integration-tests/pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 87c80951e14..8097819fde0 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -254,6 +254,7 @@ false ${project.build.directory}/failsafe-reports/failsafe-summary-isolated.xml ${skipIsolatedITs} + ${blockhound.argline} @@ -316,4 +317,16 @@ + + + jdk 13+ + + [13,) + + + + -XX:+AllowRedefinitionToAddDeleteMethods + + +
    From f3334e2630a82c69bcdb8b171d631e834154e5e9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 7 Jun 2021 11:53:15 +0200 Subject: [PATCH 125/395] Revisit Nightly and Weekend schedules --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f922d9f7c5f..cc8e0afc7da 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -356,13 +356,13 @@ pipeline { // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) parameterizedCron(branchPatternCron.matcher(env.BRANCH_NAME).matches() ? """ # Every weeknight (Monday - Friday) around 2:00 AM - ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0 and DSE 6.7 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7;CI_SCHEDULE_JABBA_VERSION=1.8 + ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0, DSE 6.7 and DSE 6.8 + H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7 dse-6.8;CI_SCHEDULE_JABBA_VERSION=1.8 ### JDK11 tests against 3.11, 4.0 and DSE 6.8 H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 # Every weekend (Sunday) around 12:00 PM noon - ### JDK14 tests against 3.11, 4.0, DSE 6.7 and DSE 6.8 - H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.7 dse-6.8 ;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 + ### JDK14 tests against 3.11, 4.0 and DSE 6.8 + H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 """ : "") } From f082768cf7bcb032bfa83d7a6da4ee21d97c3afb Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:00:36 +0200 Subject: [PATCH 126/395] Remove unused method --- .../com/datastax/oss/driver/api/testinfra/ccm/CcmRule.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmRule.java index eb12b6969e2..a5169c0aef8 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmRule.java @@ -97,10 +97,6 @@ public void evaluate() { return super.apply(base, description); } - public void reloadCore(int node, String keyspace, String table, boolean reindex) { - ccmBridge.reloadCore(node, keyspace, table, reindex); - } - public static CcmRule getInstance() { return INSTANCE; } From f20d22664bf0e22ac6c80a1847420267e2f7f697 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:00:57 +0200 Subject: [PATCH 127/395] Make field final --- .../oss/driver/api/testinfra/ccm/CustomCcmRule.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java index 1e502238e99..4ea1b3843f3 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java @@ -28,7 +28,7 @@ */ public class CustomCcmRule extends BaseCcmRule { - private static AtomicReference current = new AtomicReference<>(); + private static final AtomicReference CURRENT = new AtomicReference<>(); CustomCcmRule(CcmBridge ccmBridge) { super(ccmBridge); @@ -36,9 +36,9 @@ public class CustomCcmRule extends BaseCcmRule { @Override protected void before() { - if (current.get() == null && current.compareAndSet(null, this)) { + if (CURRENT.get() == null && CURRENT.compareAndSet(null, this)) { super.before(); - } else if (current.get() != this) { + } else if (CURRENT.get() != this) { throw new IllegalStateException( "Attempting to use a Ccm rule while another is in use. This is disallowed"); } @@ -47,7 +47,7 @@ protected void before() { @Override protected void after() { super.after(); - current.compareAndSet(this, null); + CURRENT.compareAndSet(this, null); } public CcmBridge getCcmBridge() { From 89a80c14cd08ab5cbc5e83481678c18cadbc1c0f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:07:59 +0200 Subject: [PATCH 128/395] Add a log prefix to Debouncer --- .../core/metadata/MetadataManager.java | 1 + .../core/metadata/NodeStateManager.java | 1 + .../core/util/concurrent/Debouncer.java | 34 ++++++++++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java index 594c37430d4..0f28d354c46 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java @@ -314,6 +314,7 @@ private class SingleThreaded { private SingleThreaded(InternalDriverContext context, DriverExecutionProfile config) { this.schemaRefreshDebouncer = new Debouncer<>( + logPrefix + "|metadata debouncer", adminExecutor, this::coalesceSchemaRequests, this::startSchemaRequest, diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java index dab95b58a3e..1412168d4f8 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java @@ -103,6 +103,7 @@ private SingleThreaded(InternalDriverContext context) { DriverExecutionProfile config = context.getConfig().getDefaultProfile(); this.topologyEventDebouncer = new Debouncer<>( + logPrefix + "|topology debouncer", adminExecutor, this::coalesceTopologyEvents, this::flushTopologyEvents, diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/Debouncer.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/Debouncer.java index ded770a3d48..3e9cd4a0085 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/Debouncer.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/Debouncer.java @@ -44,6 +44,7 @@ public class Debouncer { private static final Logger LOG = LoggerFactory.getLogger(Debouncer.class); + private final String logPrefix; private final EventExecutor adminExecutor; private final Consumer onFlush; private final Duration window; @@ -69,6 +70,27 @@ public Debouncer( Consumer onFlush, Duration window, long maxEvents) { + this("debouncer", adminExecutor, coalescer, onFlush, window, maxEvents); + } + + /** + * Creates a new instance. + * + * @param logPrefix the log prefix to use in log messages. + * @param adminExecutor the executor that will be used to schedule all tasks. + * @param coalescer how to transform a batch of events into a result. + * @param onFlush what to do with a result. + * @param window the time window. + * @param maxEvents the maximum number of accumulated events before a flush is forced. + */ + public Debouncer( + String logPrefix, + EventExecutor adminExecutor, + Function, CoalescedT> coalescer, + Consumer onFlush, + Duration window, + long maxEvents) { + this.logPrefix = logPrefix; this.coalescer = coalescer; Preconditions.checkArgument(maxEvents >= 1, "maxEvents should be at least 1"); this.adminExecutor = adminExecutor; @@ -85,7 +107,8 @@ public void receive(IncomingT element) { } if (window.isZero() || maxEvents == 1) { LOG.debug( - "Received {}, flushing immediately (window = {}, maxEvents = {})", + "[{}] Received {}, flushing immediately (window = {}, maxEvents = {})", + logPrefix, element, window, maxEvents); @@ -94,12 +117,13 @@ public void receive(IncomingT element) { currentBatch.add(element); if (currentBatch.size() == maxEvents) { LOG.debug( - "Received {}, flushing immediately (because {} accumulated events)", + "[{}] Received {}, flushing immediately (because {} accumulated events)", + logPrefix, element, maxEvents); flushNow(); } else { - LOG.debug("Received {}, scheduling next flush in {}", element, window); + LOG.debug("[{}] Received {}, scheduling next flush in {}", logPrefix, element, window); scheduleFlush(); } } @@ -107,7 +131,7 @@ public void receive(IncomingT element) { public void flushNow() { assert adminExecutor.inEventLoop(); - LOG.debug("Flushing now"); + LOG.debug("[{}] Flushing now", logPrefix); cancelNextFlush(); if (!currentBatch.isEmpty()) { onFlush.accept(coalescer.apply(currentBatch)); @@ -127,7 +151,7 @@ private void cancelNextFlush() { if (nextFlush != null && !nextFlush.isDone()) { boolean cancelled = nextFlush.cancel(true); if (cancelled) { - LOG.debug("Cancelled existing scheduled flush"); + LOG.debug("[{}] Cancelled existing scheduled flush", logPrefix); } } } From 48f56552d8cb46375b21cafe5c59822b5b9c941f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:27:26 +0200 Subject: [PATCH 129/395] Add exception for the removal of CcmRule::reloadCore --- test-infra/revapi.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test-infra/revapi.json b/test-infra/revapi.json index cf79d3b87f6..3cfbc8b5337 100644 --- a/test-infra/revapi.json +++ b/test-infra/revapi.json @@ -166,6 +166,11 @@ "old": "missing-class com.datastax.oss.simulacron.server.Server", "new": "missing-class com.datastax.oss.simulacron.server.Server", "justification": "Dependency was made optional" + }, + { + "code": "java.method.removed", + "old": "method void com.datastax.oss.driver.api.testinfra.ccm.CcmRule::reloadCore(int, java.lang.String, java.lang.String, boolean)", + "justification": "Modifying the state of a globally shared CCM instance is dangerous" } ] } From cc037c7614b2ae1a59dc66cbb12f232d97db5616 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:36:32 +0200 Subject: [PATCH 130/395] Switch SchemaChangesIT to serial tests --- .../driver/core/metadata/SchemaChangesIT.java | 167 ++++++++---------- 1 file changed, 78 insertions(+), 89 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java index 77861a5c57f..d45176ca825 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java @@ -25,14 +25,12 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.testinfra.CassandraRequirement; -import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; -import com.datastax.oss.driver.categories.ParallelizableTests; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import java.time.Duration; @@ -42,22 +40,19 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; -import org.assertj.core.api.Assertions; import org.junit.Before; -import org.junit.Rule; +import org.junit.ClassRule; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@Category(ParallelizableTests.class) public class SchemaChangesIT { - private CcmRule ccmRule = CcmRule.getInstance(); + private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().build(); // A client that we only use to set up the tests - private SessionRule adminSessionRule = - SessionRule.builder(ccmRule) + private static final SessionRule ADMIN_SESSION_RULE = + SessionRule.builder(CCM_RULE) .withConfigLoader( SessionUtils.configLoaderBuilder() .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofSeconds(30)) @@ -65,15 +60,16 @@ public class SchemaChangesIT { .build()) .build(); - @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(adminSessionRule); + @ClassRule + public static TestRule chain = RuleChain.outerRule(CCM_RULE).around(ADMIN_SESSION_RULE); @Before public void setup() { // Always drop and re-create the keyspace to start from a clean state - adminSessionRule + ADMIN_SESSION_RULE .session() - .execute(String.format("DROP KEYSPACE %s", adminSessionRule.keyspace())); - SessionUtils.createKeyspace(adminSessionRule.session(), adminSessionRule.keyspace()); + .execute(String.format("DROP KEYSPACE %s", ADMIN_SESSION_RULE.keyspace())); + SessionUtils.createKeyspace(ADMIN_SESSION_RULE.session(), ADMIN_SESSION_RULE.keyspace()); } @Test @@ -87,9 +83,9 @@ public void should_handle_keyspace_creation() { newKeyspaceId), metadata -> metadata.getKeyspace(newKeyspaceId), keyspace -> { - Assertions.assertThat(keyspace.getName()).isEqualTo(newKeyspaceId); - Assertions.assertThat(keyspace.isDurableWrites()).isTrue(); - Assertions.assertThat(keyspace.getReplication()) + assertThat(keyspace.getName()).isEqualTo(newKeyspaceId); + assertThat(keyspace.isDurableWrites()).isTrue(); + assertThat(keyspace.getReplication()) .hasSize(2) .containsEntry("class", "org.apache.cassandra.locator.SimpleStrategy") .containsEntry("replication_factor", "1"); @@ -128,7 +124,7 @@ public void should_handle_keyspace_update() { + "AND durable_writes = 'false'", newKeyspaceId.asCql(true)), metadata -> metadata.getKeyspace(newKeyspaceId), - newKeyspace -> Assertions.assertThat(newKeyspace.isDurableWrites()).isFalse(), + newKeyspace -> assertThat(newKeyspace.isDurableWrites()).isFalse(), (listener, oldKeyspace, newKeyspace) -> verify(listener).onKeyspaceUpdated(newKeyspace, oldKeyspace), newKeyspaceId); @@ -141,22 +137,20 @@ public void should_handle_table_creation() { "CREATE TABLE foo(k int primary key)", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .orElseThrow(IllegalStateException::new) .getTable(CqlIdentifier.fromInternal("foo")), table -> { - Assertions.assertThat(table.getKeyspace()).isEqualTo(adminSessionRule.keyspace()); - Assertions.assertThat(table.getName().asInternal()).isEqualTo("foo"); - Assertions.assertThat(table.getColumns()) - .containsOnlyKeys(CqlIdentifier.fromInternal("k")); - Assertions.assertThat(table.getColumn(CqlIdentifier.fromInternal("k"))) + assertThat(table.getKeyspace()).isEqualTo(ADMIN_SESSION_RULE.keyspace()); + assertThat(table.getName().asInternal()).isEqualTo("foo"); + assertThat(table.getColumns()).containsOnlyKeys(CqlIdentifier.fromInternal("k")); + assertThat(table.getColumn(CqlIdentifier.fromInternal("k"))) .hasValueSatisfying( k -> { - Assertions.assertThat(k.getType()).isEqualTo(DataTypes.INT); - Assertions.assertThat(table.getPartitionKey()) - .containsExactly(k); + assertThat(k.getType()).isEqualTo(DataTypes.INT); + assertThat(table.getPartitionKey()).containsExactly(k); }); - Assertions.assertThat(table.getClusteringColumns()).isEmpty(); + assertThat(table.getClusteringColumns()).isEmpty(); }, (listener, table) -> verify(listener).onTableCreated(table)); } @@ -168,7 +162,7 @@ public void should_handle_table_drop() { "DROP TABLE foo", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getTable(CqlIdentifier.fromInternal("foo"))), (listener, oldTable) -> verify(listener).onTableDropped(oldTable)); } @@ -180,10 +174,9 @@ public void should_handle_table_update() { "ALTER TABLE foo ADD v int", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getTable(CqlIdentifier.fromInternal("foo"))), - newTable -> - Assertions.assertThat(newTable.getColumn(CqlIdentifier.fromInternal("v"))).isPresent(), + newTable -> assertThat(newTable.getColumn(CqlIdentifier.fromInternal("v"))).isPresent(), (listener, oldTable, newTable) -> verify(listener).onTableUpdated(newTable, oldTable)); } @@ -194,14 +187,13 @@ public void should_handle_type_creation() { "CREATE TYPE t(i int)", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getUserDefinedType(CqlIdentifier.fromInternal("t"))), type -> { - Assertions.assertThat(type.getKeyspace()).isEqualTo(adminSessionRule.keyspace()); - Assertions.assertThat(type.getName().asInternal()).isEqualTo("t"); - Assertions.assertThat(type.getFieldNames()) - .containsExactly(CqlIdentifier.fromInternal("i")); - Assertions.assertThat(type.getFieldTypes()).containsExactly(DataTypes.INT); + assertThat(type.getKeyspace()).isEqualTo(ADMIN_SESSION_RULE.keyspace()); + assertThat(type.getName().asInternal()).isEqualTo("t"); + assertThat(type.getFieldNames()).containsExactly(CqlIdentifier.fromInternal("i")); + assertThat(type.getFieldTypes()).containsExactly(DataTypes.INT); }, (listener, type) -> verify(listener).onUserDefinedTypeCreated(type)); } @@ -213,7 +205,7 @@ public void should_handle_type_drop() { "DROP TYPE t", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getUserDefinedType(CqlIdentifier.fromInternal("t"))), (listener, oldType) -> verify(listener).onUserDefinedTypeDropped(oldType)); } @@ -225,10 +217,10 @@ public void should_handle_type_update() { "ALTER TYPE t ADD j int", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getUserDefinedType(CqlIdentifier.fromInternal("t"))), newType -> - Assertions.assertThat(newType.getFieldNames()) + assertThat(newType.getFieldNames()) .containsExactly(CqlIdentifier.fromInternal("i"), CqlIdentifier.fromInternal("j")), (listener, oldType, newType) -> verify(listener).onUserDefinedTypeUpdated(newType, oldType)); @@ -246,16 +238,16 @@ public void should_handle_view_creation() { + "WITH CLUSTERING ORDER BY (score DESC, user DESC)", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getView(CqlIdentifier.fromInternal("highscores"))), view -> { - Assertions.assertThat(view.getKeyspace()).isEqualTo(adminSessionRule.keyspace()); - Assertions.assertThat(view.getName().asInternal()).isEqualTo("highscores"); - Assertions.assertThat(view.getBaseTable().asInternal()).isEqualTo("scores"); - Assertions.assertThat(view.includesAllColumns()).isFalse(); - Assertions.assertThat(view.getWhereClause()) + assertThat(view.getKeyspace()).isEqualTo(ADMIN_SESSION_RULE.keyspace()); + assertThat(view.getName().asInternal()).isEqualTo("highscores"); + assertThat(view.getBaseTable().asInternal()).isEqualTo("scores"); + assertThat(view.includesAllColumns()).isFalse(); + assertThat(view.getWhereClause()) .hasValue("game IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL"); - Assertions.assertThat(view.getColumns()) + assertThat(view.getColumns()) .containsOnlyKeys( CqlIdentifier.fromInternal("game"), CqlIdentifier.fromInternal("score"), @@ -278,7 +270,7 @@ public void should_handle_view_drop() { "DROP MATERIALIZED VIEW highscores", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getView(CqlIdentifier.fromInternal("highscores"))), (listener, oldView) -> verify(listener).onViewDropped(oldView)); } @@ -297,10 +289,10 @@ public void should_handle_view_update() { "ALTER MATERIALIZED VIEW highscores WITH comment = 'The best score for each game'", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getView(CqlIdentifier.fromInternal("highscores"))), newView -> - Assertions.assertThat(newView.getOptions().get(CqlIdentifier.fromInternal("comment"))) + assertThat(newView.getOptions().get(CqlIdentifier.fromInternal("comment"))) .isEqualTo("The best score for each game"), (listener, oldView, newView) -> verify(listener).onViewUpdated(newView, oldView)); } @@ -314,17 +306,16 @@ public void should_handle_function_creation() { + "LANGUAGE java AS 'return i;'", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getFunction(CqlIdentifier.fromInternal("id"), DataTypes.INT)), function -> { - Assertions.assertThat(function.getKeyspace()).isEqualTo(adminSessionRule.keyspace()); - Assertions.assertThat(function.getSignature().getName().asInternal()).isEqualTo("id"); - Assertions.assertThat(function.getSignature().getParameterTypes()) - .containsExactly(DataTypes.INT); - Assertions.assertThat(function.getReturnType()).isEqualTo(DataTypes.INT); - Assertions.assertThat(function.getLanguage()).isEqualTo("java"); - Assertions.assertThat(function.isCalledOnNullInput()).isFalse(); - Assertions.assertThat(function.getBody()).isEqualTo("return i;"); + assertThat(function.getKeyspace()).isEqualTo(ADMIN_SESSION_RULE.keyspace()); + assertThat(function.getSignature().getName().asInternal()).isEqualTo("id"); + assertThat(function.getSignature().getParameterTypes()).containsExactly(DataTypes.INT); + assertThat(function.getReturnType()).isEqualTo(DataTypes.INT); + assertThat(function.getLanguage()).isEqualTo("java"); + assertThat(function.isCalledOnNullInput()).isFalse(); + assertThat(function.getBody()).isEqualTo("return i;"); }, (listener, function) -> verify(listener).onFunctionCreated(function)); } @@ -339,7 +330,7 @@ public void should_handle_function_drop() { "DROP FUNCTION id", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getFunction(CqlIdentifier.fromInternal("id"), DataTypes.INT)), (listener, oldFunction) -> verify(listener).onFunctionDropped(oldFunction)); } @@ -356,9 +347,9 @@ public void should_handle_function_update() { + "LANGUAGE java AS 'return j;'", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getFunction(CqlIdentifier.fromInternal("id"), DataTypes.INT)), - newFunction -> Assertions.assertThat(newFunction.getBody()).isEqualTo("return j;"), + newFunction -> assertThat(newFunction.getBody()).isEqualTo("return j;"), (listener, oldFunction, newFunction) -> verify(listener).onFunctionUpdated(newFunction, oldFunction)); } @@ -372,20 +363,18 @@ public void should_handle_aggregate_creation() { "CREATE AGGREGATE sum(int) SFUNC plus STYPE int INITCOND 0", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getAggregate(CqlIdentifier.fromInternal("sum"), DataTypes.INT)), aggregate -> { - Assertions.assertThat(aggregate.getKeyspace()).isEqualTo(adminSessionRule.keyspace()); - Assertions.assertThat(aggregate.getSignature().getName().asInternal()).isEqualTo("sum"); - Assertions.assertThat(aggregate.getSignature().getParameterTypes()) - .containsExactly(DataTypes.INT); - Assertions.assertThat(aggregate.getStateType()).isEqualTo(DataTypes.INT); - Assertions.assertThat(aggregate.getStateFuncSignature().getName().asInternal()) - .isEqualTo("plus"); - Assertions.assertThat(aggregate.getStateFuncSignature().getParameterTypes()) + assertThat(aggregate.getKeyspace()).isEqualTo(ADMIN_SESSION_RULE.keyspace()); + assertThat(aggregate.getSignature().getName().asInternal()).isEqualTo("sum"); + assertThat(aggregate.getSignature().getParameterTypes()).containsExactly(DataTypes.INT); + assertThat(aggregate.getStateType()).isEqualTo(DataTypes.INT); + assertThat(aggregate.getStateFuncSignature().getName().asInternal()).isEqualTo("plus"); + assertThat(aggregate.getStateFuncSignature().getParameterTypes()) .containsExactly(DataTypes.INT, DataTypes.INT); - Assertions.assertThat(aggregate.getFinalFuncSignature()).isEmpty(); - Assertions.assertThat(aggregate.getInitCond()).hasValue(0); + assertThat(aggregate.getFinalFuncSignature()).isEmpty(); + assertThat(aggregate.getInitCond()).hasValue(0); }, (listener, aggregate) -> verify(listener).onAggregateCreated(aggregate)); } @@ -401,7 +390,7 @@ public void should_handle_aggregate_drop() { "DROP AGGREGATE sum", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getAggregate(CqlIdentifier.fromInternal("sum"), DataTypes.INT)), (listener, oldAggregate) -> verify(listener).onAggregateDropped(oldAggregate)); } @@ -418,9 +407,9 @@ public void should_handle_aggregate_update() { "CREATE AGGREGATE sum(int) SFUNC plus STYPE int INITCOND 1", metadata -> metadata - .getKeyspace(adminSessionRule.keyspace()) + .getKeyspace(ADMIN_SESSION_RULE.keyspace()) .flatMap(ks -> ks.getAggregate(CqlIdentifier.fromInternal("sum"), DataTypes.INT)), - newAggregate -> Assertions.assertThat(newAggregate.getInitCond()).hasValue(1), + newAggregate -> assertThat(newAggregate.getInitCond()).hasValue(1), (listener, oldAggregate, newAggregate) -> verify(listener).onAggregateUpdated(newAggregate, oldAggregate)); } @@ -434,7 +423,7 @@ private void should_handle_creation( CqlIdentifier... keyspaces) { if (beforeStatement != null) { - adminSessionRule.session().execute(beforeStatement); + ADMIN_SESSION_RULE.session().execute(beforeStatement); } SchemaChangeListener listener1 = mock(SchemaChangeListener.class); @@ -456,9 +445,9 @@ private void should_handle_creation( try (CqlSession session1 = SessionUtils.newSession( - ccmRule, adminSessionRule.keyspace(), null, listener1, null, loader); + CCM_RULE, ADMIN_SESSION_RULE.keyspace(), null, listener1, null, loader); CqlSession session2 = - SessionUtils.newSession(ccmRule, null, null, listener2, null, loader)) { + SessionUtils.newSession(CCM_RULE, null, null, listener2, null, loader)) { session1.execute(createStatement); @@ -489,7 +478,7 @@ private void should_handle_drop( CqlIdentifier... keyspaces) { for (String statement : beforeStatements) { - adminSessionRule.session().execute(statement); + ADMIN_SESSION_RULE.session().execute(statement); } SchemaChangeListener listener1 = mock(SchemaChangeListener.class); @@ -507,9 +496,9 @@ private void should_handle_drop( try (CqlSession session1 = SessionUtils.newSession( - ccmRule, adminSessionRule.keyspace(), null, listener1, null, loader); + CCM_RULE, ADMIN_SESSION_RULE.keyspace(), null, listener1, null, loader); CqlSession session2 = - SessionUtils.newSession(ccmRule, null, null, listener2, null, loader)) { + SessionUtils.newSession(CCM_RULE, null, null, listener2, null, loader)) { T oldElement = extract.apply(session1.getMetadata()).orElseThrow(AssertionError::new); assertThat(oldElement).isNotNull(); @@ -539,7 +528,7 @@ private void should_handle_update( CqlIdentifier... keyspaces) { for (String statement : beforeStatements) { - adminSessionRule.session().execute(statement); + ADMIN_SESSION_RULE.session().execute(statement); } SchemaChangeListener listener1 = mock(SchemaChangeListener.class); @@ -556,9 +545,9 @@ private void should_handle_update( try (CqlSession session1 = SessionUtils.newSession( - ccmRule, adminSessionRule.keyspace(), null, listener1, null, loader); + CCM_RULE, ADMIN_SESSION_RULE.keyspace(), null, listener1, null, loader); CqlSession session2 = - SessionUtils.newSession(ccmRule, null, null, listener2, null, loader)) { + SessionUtils.newSession(CCM_RULE, null, null, listener2, null, loader)) { T oldElement = extract.apply(session1.getMetadata()).orElseThrow(AssertionError::new); assertThat(oldElement).isNotNull(); @@ -593,7 +582,7 @@ private void should_handle_update_via_drop_and_recreate( CqlIdentifier... keyspaces) { for (String statement : beforeStatements) { - adminSessionRule.session().execute(statement); + ADMIN_SESSION_RULE.session().execute(statement); } SchemaChangeListener listener1 = mock(SchemaChangeListener.class); @@ -609,9 +598,9 @@ private void should_handle_update_via_drop_and_recreate( .build(); try (CqlSession session1 = SessionUtils.newSession( - ccmRule, adminSessionRule.keyspace(), null, listener1, null, loader); + CCM_RULE, ADMIN_SESSION_RULE.keyspace(), null, listener1, null, loader); CqlSession session2 = - SessionUtils.newSession(ccmRule, null, null, listener2, null, loader)) { + SessionUtils.newSession(CCM_RULE, null, null, listener2, null, loader)) { T oldElement = extract.apply(session1.getMetadata()).orElseThrow(AssertionError::new); assertThat(oldElement).isNotNull(); From 4519c9f199be17f4af10c24b8440cd8c2befea9e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:47:41 +0200 Subject: [PATCH 131/395] Switch tests to parallel tests --- .../java/com/datastax/oss/driver/core/SerializationIT.java | 3 +++ .../core/retry/ConsistencyDowngradingRetryPolicyIT.java | 6 +++--- .../datastax/oss/driver/core/throttling/ThrottlingIT.java | 3 +++ .../datastax/oss/driver/core/tracker/RequestLoggerIT.java | 6 +++++- .../datastax/oss/driver/mapper/StatementAttributesIT.java | 3 +++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/SerializationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/SerializationIT.java index afaffc44a0b..f9bdff1b656 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/SerializationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/SerializationIT.java @@ -29,14 +29,17 @@ import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.SerializationHelper; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +@Category(ParallelizableTests.class) public class SerializationIT { private static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(1)); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java index 2a34a7cd639..a312d6162bf 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java @@ -60,6 +60,7 @@ import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.api.testinfra.simulacron.QueryCounter; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryPolicy; import com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryVerdict; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; @@ -83,12 +84,14 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.slf4j.LoggerFactory; import org.slf4j.helpers.MessageFormatter; @RunWith(DataProviderRunner.class) +@Category(ParallelizableTests.class) public class ConsistencyDowngradingRetryPolicyIT { @ClassRule @@ -130,7 +133,6 @@ public class ConsistencyDowngradingRetryPolicyIT { .setConsistencyLevel(DefaultConsistencyLevel.LOCAL_SERIAL) .build(); - @SuppressWarnings("deprecation") private final QueryCounter localQuorumCounter = QueryCounter.builder(SIMULACRON_RULE.cluster()) .withFilter( @@ -139,7 +141,6 @@ public class ConsistencyDowngradingRetryPolicyIT { && l.getConsistency().equals(ConsistencyLevel.LOCAL_QUORUM)) .build(); - @SuppressWarnings("deprecation") private final QueryCounter oneCounter = QueryCounter.builder(SIMULACRON_RULE.cluster()) .withFilter( @@ -147,7 +148,6 @@ public class ConsistencyDowngradingRetryPolicyIT { l.getQuery().equals(QUERY_STR) && l.getConsistency().equals(ConsistencyLevel.ONE)) .build(); - @SuppressWarnings("deprecation") private final QueryCounter localSerialCounter = QueryCounter.builder(SIMULACRON_RULE.cluster()) .withFilter( diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java index ef90cac4e2e..f9491676fba 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java @@ -24,13 +24,16 @@ import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import com.datastax.oss.simulacron.common.stubbing.PrimeDsl; import java.util.concurrent.TimeUnit; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.categories.Category; +@Category(ParallelizableTests.class) public class ThrottlingIT { private static final String QUERY = "select * from foo"; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java index 0c848fdb970..e67d0fdc462 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java @@ -40,6 +40,7 @@ import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.tracker.RequestLogger; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import com.datastax.oss.simulacron.common.codec.ConsistencyLevel; @@ -52,6 +53,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; import org.junit.runner.RunWith; @@ -64,6 +66,7 @@ import org.slf4j.LoggerFactory; @RunWith(MockitoJUnitRunner.class) +@Category(ParallelizableTests.class) public class RequestLoggerIT { private static final Pattern LOG_PREFIX_PER_REQUEST = Pattern.compile("\\[s\\d*\\|\\d*]"); @@ -80,7 +83,8 @@ public class RequestLoggerIT { private static final String QUERY = "SELECT release_version FROM system.local"; - private SimulacronRule simulacronRule = new SimulacronRule(ClusterSpec.builder().withNodes(3)); + private final SimulacronRule simulacronRule = + new SimulacronRule(ClusterSpec.builder().withNodes(3)); private final DriverConfigLoader requestLoader = SessionUtils.configLoaderBuilder() diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java index 46a10d465ad..6f957c8a36c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/StatementAttributesIT.java @@ -38,6 +38,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Update; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; +import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.protocol.internal.Message; import com.datastax.oss.protocol.internal.request.Execute; import com.datastax.oss.simulacron.common.cluster.ClusterQueryLogReport; @@ -56,9 +57,11 @@ import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +@Category(ParallelizableTests.class) public class StatementAttributesIT { private static final SimulacronRule SIMULACRON_RULE = From e1d637532eb0ef3e04af528e87ce605041afaf75 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:48:36 +0200 Subject: [PATCH 132/395] Remove unnecessary SuppressWarnings annotation --- .../oss/driver/core/retry/DefaultRetryPolicyIT.java | 1 - .../oss/driver/core/retry/PerProfileRetryPolicyIT.java | 1 - .../oss/driver/core/specex/SpeculativeExecutionIT.java | 3 +-- .../oss/driver/api/testinfra/simulacron/QueryCounter.java | 6 +++--- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/DefaultRetryPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/DefaultRetryPolicyIT.java index 8e496db350f..6474ee91a4c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/DefaultRetryPolicyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/DefaultRetryPolicyIT.java @@ -103,7 +103,6 @@ public class DefaultRetryPolicyIT { private Level oldLevel; private String logPrefix; - @SuppressWarnings("deprecation") private final QueryCounter counter = QueryCounter.builder(SIMULACRON_RULE.cluster()) .withFilter((l) -> l.getQuery().equals(queryStr)) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java index 2e7665dcc6f..e3dd15e2f0e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/PerProfileRetryPolicyIT.java @@ -82,7 +82,6 @@ public class PerProfileRetryPolicyIT { private static String QUERY_STRING = "select * from foo"; private static final SimpleStatement QUERY = SimpleStatement.newInstance(QUERY_STRING); - @SuppressWarnings("deprecation") private final QueryCounter counter = QueryCounter.builder(SIMULACRON_RULE.cluster()) .withFilter((l) -> l.getQuery().equals(QUERY_STRING)) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/specex/SpeculativeExecutionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/specex/SpeculativeExecutionIT.java index f1cae68f0b0..95d1c8e9cb9 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/specex/SpeculativeExecutionIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/specex/SpeculativeExecutionIT.java @@ -52,7 +52,7 @@ public class SpeculativeExecutionIT { // Note: it looks like shorter delays cause precision issues with Netty timers private static final long SPECULATIVE_DELAY = 1000; - private static String QUERY_STRING = "select * from foo"; + private static final String QUERY_STRING = "select * from foo"; private static final SimpleStatement QUERY = SimpleStatement.newInstance(QUERY_STRING); // Shared across all tests methods. @@ -60,7 +60,6 @@ public class SpeculativeExecutionIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(3)); - @SuppressWarnings("deprecation") private final QueryCounter counter = QueryCounter.builder(SIMULACRON_RULE.cluster()) .withFilter((l) -> l.getQuery().equals(QUERY_STRING)) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java index 5d305736da3..bad5a112431 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java @@ -112,11 +112,11 @@ public void assertNodeCounts(int... counts) { public static class QueryCounterBuilder { - @SuppressWarnings("deprecation") - private static Predicate DEFAULT_FILTER = (q) -> !q.getQuery().isEmpty(); + private static final Predicate DEFAULT_FILTER = (q) -> !q.getQuery().isEmpty(); + + private final BoundTopic topic; private Predicate queryLogFilter = DEFAULT_FILTER; - private BoundTopic topic; private NotificationMode notificationMode = NotificationMode.BEFORE_PROCESSING; private long beforeTimeout = 1; private TimeUnit beforeUnit = TimeUnit.SECONDS; From bb145ebb4174b8385dd65c2b1b5b8c04a67e3a3c Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 16:48:53 +0200 Subject: [PATCH 133/395] Address minor compiler warnings --- .../core/heartbeat/HeartbeatDisabledIT.java | 2 +- .../oss/driver/core/heartbeat/HeartbeatIT.java | 2 +- .../PerProfileLoadBalancingPolicyIT.java | 15 ++++++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatDisabledIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatDisabledIT.java index fd2f37d82af..f0afc0058c0 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatDisabledIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatDisabledIT.java @@ -44,7 +44,7 @@ public void should_not_send_heartbeat_when_disabled() throws InterruptedExceptio SessionUtils.configLoaderBuilder() .withDuration(DefaultDriverOption.HEARTBEAT_INTERVAL, Duration.ofSeconds(0)) .build(); - try (CqlSession session = SessionUtils.newSession(SIMULACRON_RULE, loader)) { + try (CqlSession ignored = SessionUtils.newSession(SIMULACRON_RULE, loader)) { AtomicInteger heartbeats = registerHeartbeatListener(); SECONDS.sleep(35); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatIT.java index 14a72a43fa1..1dbc055a5af 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/heartbeat/HeartbeatIT.java @@ -119,7 +119,7 @@ public void should_send_heartbeat_on_control_connection() { ProgrammaticDriverConfigLoaderBuilder loader = SessionUtils.configLoaderBuilder() .withInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE, 0); - try (CqlSession session = newSession(loader)) { + try (CqlSession ignored = newSession(loader)) { AtomicInteger heartbeats = countHeartbeatsOnControlConnection(); await() .pollInterval(500, TimeUnit.MILLISECONDS) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/PerProfileLoadBalancingPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/PerProfileLoadBalancingPolicyIT.java index 2ee5aca6aee..12d5c800d88 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/PerProfileLoadBalancingPolicyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/loadbalancing/PerProfileLoadBalancingPolicyIT.java @@ -33,6 +33,7 @@ import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import java.util.Objects; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -93,7 +94,7 @@ public static void setup() { for (Node node : SESSION_RULE.session().getMetadata().getNodes().values()) { // if node is in dc2 it should be ignored, otherwise (dc1, dc3) it should be local. NodeDistance expectedDistance = - node.getDatacenter().equals("dc2") ? NodeDistance.IGNORED : NodeDistance.LOCAL; + Objects.equals(node.getDatacenter(), "dc2") ? NodeDistance.IGNORED : NodeDistance.LOCAL; assertThat(node.getDistance()).isEqualTo(expectedDistance); } } @@ -101,10 +102,12 @@ public static void setup() { @Test public void should_use_policy_from_request_profile() { // Since profile1 uses dc3 as localDC, only those nodes should receive these queries. - Statement statement = QUERY.setExecutionProfileName("profile1"); + Statement statement = QUERY.setExecutionProfileName("profile1"); for (int i = 0; i < 10; i++) { ResultSet result = SESSION_RULE.session().execute(statement); - assertThat(result.getExecutionInfo().getCoordinator().getDatacenter()).isEqualTo("dc3"); + Node coordinator = result.getExecutionInfo().getCoordinator(); + assertThat(coordinator).isNotNull(); + assertThat(coordinator.getDatacenter()).isEqualTo("dc3"); } assertQueryInDc(0, 0); @@ -115,10 +118,12 @@ public void should_use_policy_from_request_profile() { @Test public void should_use_policy_from_config_when_not_configured_in_request_profile() { // Since profile2 does not define an lbp config, it should use default which uses dc1. - Statement statement = QUERY.setExecutionProfileName("profile2"); + Statement statement = QUERY.setExecutionProfileName("profile2"); for (int i = 0; i < 10; i++) { ResultSet result = SESSION_RULE.session().execute(statement); - assertThat(result.getExecutionInfo().getCoordinator().getDatacenter()).isEqualTo("dc1"); + Node coordinator = result.getExecutionInfo().getCoordinator(); + assertThat(coordinator).isNotNull(); + assertThat(coordinator.getDatacenter()).isEqualTo("dc1"); } assertQueryInDc(0, 5); From 7233016ee2125a5fd658e87993cb8ba7a969cd1a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 17:04:17 +0200 Subject: [PATCH 134/395] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method (#1553) --- changelog/README.md | 1 + .../internal/core/context/DefaultDriverContext.java | 11 +++++++++++ .../core/context/InternalDriverContext.java | 13 +++++++++++++ 3 files changed, 25 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index f08c735c369..9312b8e8749 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method - [bug] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader - [bug] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective - [bug] JAVA-2941: Cannot add a single static column with the alter table API diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index fd217f9c6c8..e09e5ee3b5c 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -225,6 +225,7 @@ public class DefaultDriverContext implements InternalDriverContext { private final SchemaChangeListener schemaChangeListenerFromBuilder; private final RequestTracker requestTrackerFromBuilder; private final Map localDatacentersFromBuilder; + private final Map> nodeFiltersFromBuilder; private final Map nodeDistanceEvaluatorsFromBuilder; private final ClassLoader classLoader; private final InetSocketAddress cloudProxyAddress; @@ -277,6 +278,9 @@ public DefaultDriverContext( "sslEngineFactory", () -> buildSslEngineFactory(programmaticArguments.getSslEngineFactory()), cycleDetector); + @SuppressWarnings("deprecation") + Map> nodeFilters = programmaticArguments.getNodeFilters(); + this.nodeFiltersFromBuilder = nodeFilters; this.nodeDistanceEvaluatorsFromBuilder = programmaticArguments.getNodeDistanceEvaluators(); this.classLoader = programmaticArguments.getClassLoader(); this.cloudProxyAddress = programmaticArguments.getCloudProxyAddress(); @@ -909,6 +913,13 @@ public String getLocalDatacenter(@NonNull String profileName) { return localDatacentersFromBuilder.get(profileName); } + @Nullable + @Override + @Deprecated + public Predicate getNodeFilter(@NonNull String profileName) { + return nodeFiltersFromBuilder.get(profileName); + } + @Nullable @Override public NodeDistanceEvaluator getNodeDistanceEvaluator(@NonNull String profileName) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java index 3e3f21d0e41..0997258c149 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.ProtocolVersionRegistry; @@ -49,6 +50,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; /** Extends the driver context with additional components that are not exposed by our public API. */ public interface InternalDriverContext extends DriverContext { @@ -136,6 +138,17 @@ public interface InternalDriverContext extends DriverContext { @Nullable String getLocalDatacenter(@NonNull String profileName); + /** + * This is the filter from {@link SessionBuilder#withNodeFilter(String, Predicate)}. If the filter + * for this profile was specified through the configuration instead, this method will return + * {@code null}. + * + * @deprecated Use {@link #getNodeDistanceEvaluator(String)} instead. + */ + @Nullable + @Deprecated + Predicate getNodeFilter(@NonNull String profileName); + /** * This is the node distance evaluator from {@link * SessionBuilder#withNodeDistanceEvaluator(String, NodeDistanceEvaluator)}. If the evaluator for From 38f698d5736f8979e7cc5a3a3802338b4617a9ae Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 17:04:59 +0200 Subject: [PATCH 135/395] JAVA-2947: Release buffer after decoding multi-slice frame (#1554) --- changelog/README.md | 1 + .../core/protocol/SegmentToFrameDecoder.java | 43 +++-- .../protocol/SegmentToFrameDecoderTest.java | 3 +- .../NettyResourceLeakDetectionIT.java | 177 ++++++++++++++++++ 4 files changed, 207 insertions(+), 17 deletions(-) create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java diff --git a/changelog/README.md b/changelog/README.md index f08c735c369..5620ac9f320 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2947: Release buffer after decoding multi-slice frame - [bug] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader - [bug] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective - [bug] JAVA-2941: Cannot add a single static column with the alter table API diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoder.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoder.java index 13564e47bff..66b8d0876c0 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoder.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoder.java @@ -69,14 +69,19 @@ protected void decode( private void decodeSelfContained(Segment segment, List out) { ByteBuf payload = segment.payload; int frameCount = 0; - do { - Frame frame = frameCodec.decode(payload); - LOG.trace( - "[{}] Decoded response frame {} from self-contained segment", logPrefix, frame.streamId); - out.add(frame); - frameCount += 1; - } while (payload.isReadable()); - payload.release(); + try { + do { + Frame frame = frameCodec.decode(payload); + LOG.trace( + "[{}] Decoded response frame {} from self-contained segment", + logPrefix, + frame.streamId); + out.add(frame); + frameCount += 1; + } while (payload.isReadable()); + } finally { + payload.release(); + } LOG.trace("[{}] Done processing self-contained segment ({} frames)", logPrefix, frameCount); } @@ -89,28 +94,34 @@ private void decodeSlice(Segment segment, ByteBufAllocator allocator, L } accumulatedSlices.add(slice); accumulatedLength += slice.readableBytes(); + int accumulatedSlicesSize = accumulatedSlices.size(); LOG.trace( "[{}] Decoded slice {}, {}/{} bytes", logPrefix, - accumulatedSlices.size(), + accumulatedSlicesSize, accumulatedLength, targetLength); assert accumulatedLength <= targetLength; if (accumulatedLength == targetLength) { // We've received enough data to reassemble the whole message - CompositeByteBuf encodedFrame = allocator.compositeBuffer(accumulatedSlices.size()); + CompositeByteBuf encodedFrame = allocator.compositeBuffer(accumulatedSlicesSize); encodedFrame.addComponents(true, accumulatedSlices); - Frame frame = frameCodec.decode(encodedFrame); + Frame frame; + try { + frame = frameCodec.decode(encodedFrame); + } finally { + encodedFrame.release(); + // Reset our state + targetLength = UNKNOWN_LENGTH; + accumulatedSlices.clear(); + accumulatedLength = 0; + } LOG.trace( "[{}] Decoded response frame {} from {} slices", logPrefix, frame.streamId, - accumulatedSlices.size()); + accumulatedSlicesSize); out.add(frame); - // Reset our state - targetLength = UNKNOWN_LENGTH; - accumulatedSlices.clear(); - accumulatedLength = 0; } } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoderTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoderTest.java index 2bb93f0901b..363beb1b4af 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoderTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/SegmentToFrameDecoderTest.java @@ -73,7 +73,8 @@ public void should_decode_sequence_of_slices() { encodeFrame(new AuthResponse(Bytes.fromHexString("0x" + Strings.repeat("aa", 1011)))); int sliceLength = 100; do { - ByteBuf payload = encodedFrame.readSlice(Math.min(sliceLength, encodedFrame.readableBytes())); + ByteBuf payload = + encodedFrame.readRetainedSlice(Math.min(sliceLength, encodedFrame.readableBytes())); channel.writeInbound(new Segment<>(payload, false)); } while (encodedFrame.isReadable()); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java new file mode 100644 index 00000000000..ada5ae9a61b --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java @@ -0,0 +1,177 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.connection; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.categories.IsolatedTests; +import com.datastax.oss.driver.shaded.guava.common.base.Strings; +import com.datastax.oss.protocol.internal.Segment; +import com.datastax.oss.protocol.internal.util.Bytes; +import io.netty.util.ResourceLeakDetector; +import io.netty.util.ResourceLeakDetector.Level; +import java.nio.ByteBuffer; +import java.util.List; +import org.junit.After; +import org.junit.Assume; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.LoggerFactory; + +@Category(IsolatedTests.class) +@RunWith(MockitoJUnitRunner.class) +public class NettyResourceLeakDetectionIT { + + static { + ResourceLeakDetector.setLevel(Level.PARANOID); + } + + private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().build(); + + private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); + + @ClassRule + public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); + + private static final ByteBuffer LARGE_PAYLOAD = + Bytes.fromHexString("0x" + Strings.repeat("ab", Segment.MAX_PAYLOAD_LENGTH + 100)); + + @Mock private Appender appender; + + @BeforeClass + public static void createTables() { + CqlSession session = SESSION_RULE.session(); + DriverExecutionProfile slowProfile = SessionUtils.slowProfile(session); + session.execute( + SimpleStatement.newInstance( + "CREATE TABLE IF NOT EXISTS leak_test_small (key int PRIMARY KEY, value int)") + .setExecutionProfile(slowProfile)); + session.execute( + SimpleStatement.newInstance( + "CREATE TABLE IF NOT EXISTS leak_test_large (key int PRIMARY KEY, value blob)") + .setExecutionProfile(slowProfile)); + } + + @Before + public void setupLogger() { + Logger logger = (Logger) LoggerFactory.getLogger(ResourceLeakDetector.class); + logger.setLevel(ch.qos.logback.classic.Level.ERROR); + logger.addAppender(appender); + } + + @After + public void resetLogger() { + Logger logger = (Logger) LoggerFactory.getLogger(ResourceLeakDetector.class); + logger.detachAppender(appender); + } + + @Test + public void should_not_leak_uncompressed() { + doLeakDetectionTest(SESSION_RULE.session()); + } + + @Test + public void should_not_leak_compressed_lz4() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_COMPRESSION, "lz4") + .build(); + try (CqlSession session = SessionUtils.newSession(CCM_RULE, SESSION_RULE.keyspace(), loader)) { + doLeakDetectionTest(session); + } + } + + @Test + public void should_not_leak_compressed_snappy() { + Assume.assumeTrue( + "Snappy is not supported in OSS C* 4.0+ with protocol v5", + CCM_RULE.getDseVersion().isPresent() + || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0); + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.PROTOCOL_COMPRESSION, "snappy") + .build(); + try (CqlSession session = SessionUtils.newSession(CCM_RULE, SESSION_RULE.keyspace(), loader)) { + doLeakDetectionTest(session); + } + } + + private void doLeakDetectionTest(CqlSession session) { + for (int i = 0; i < 10; i++) { + testSmallMessages(session); + verify(appender, never()).doAppend(any()); + System.gc(); + testLargeMessages(session); + verify(appender, never()).doAppend(any()); + System.gc(); + } + } + + private void testSmallMessages(CqlSession session) { + // trigger some activity using small requests and responses; in v5, these messages should fit in + // one single, self-contained segment + for (int i = 0; i < 1000; i++) { + session.execute("INSERT INTO leak_test_small (key, value) VALUES (?,?)", i, i); + } + List rows = session.execute("SELECT value FROM leak_test_small").all(); + assertThat(rows).hasSize(1000); + for (Row row : rows) { + assertThat(row).isNotNull(); + int actual = row.getInt(0); + assertThat(actual).isGreaterThanOrEqualTo(0).isLessThan(1000); + } + } + + private void testLargeMessages(CqlSession session) { + // trigger some activity using large requests and responses; in v5, these messages are likely to + // be split in multiple segments + for (int i = 0; i < 100; i++) { + session.execute( + "INSERT INTO leak_test_large (key, value) VALUES (?,?)", i, LARGE_PAYLOAD.duplicate()); + } + List rows = session.execute("SELECT value FROM leak_test_large").all(); + assertThat(rows).hasSize(100); + for (Row row : rows) { + assertThat(row).isNotNull(); + ByteBuffer actual = row.getByteBuffer(0); + assertThat(actual).isEqualTo(LARGE_PAYLOAD.duplicate()); + } + } +} From 890f901f3112006022e3115ea738828608b17413 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 17:13:19 +0200 Subject: [PATCH 136/395] Address errorprone error on QueryCounter --- .../oss/driver/api/testinfra/simulacron/QueryCounter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java index bad5a112431..1be6e219395 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/simulacron/QueryCounter.java @@ -112,6 +112,7 @@ public void assertNodeCounts(int... counts) { public static class QueryCounterBuilder { + @SuppressWarnings("UnnecessaryLambda") private static final Predicate DEFAULT_FILTER = (q) -> !q.getQuery().isEmpty(); private final BoundTopic topic; From 4ee99e0aec11187b24559812f54919dcbbed7a21 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 10 Jun 2021 17:04:17 +0200 Subject: [PATCH 137/395] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method (#1553) --- changelog/README.md | 1 + .../internal/core/context/DefaultDriverContext.java | 11 +++++++++++ .../core/context/InternalDriverContext.java | 13 +++++++++++++ 3 files changed, 25 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 5620ac9f320..52d34c9b02a 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method - [bug] JAVA-2947: Release buffer after decoding multi-slice frame - [bug] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader - [bug] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index fd217f9c6c8..e09e5ee3b5c 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -225,6 +225,7 @@ public class DefaultDriverContext implements InternalDriverContext { private final SchemaChangeListener schemaChangeListenerFromBuilder; private final RequestTracker requestTrackerFromBuilder; private final Map localDatacentersFromBuilder; + private final Map> nodeFiltersFromBuilder; private final Map nodeDistanceEvaluatorsFromBuilder; private final ClassLoader classLoader; private final InetSocketAddress cloudProxyAddress; @@ -277,6 +278,9 @@ public DefaultDriverContext( "sslEngineFactory", () -> buildSslEngineFactory(programmaticArguments.getSslEngineFactory()), cycleDetector); + @SuppressWarnings("deprecation") + Map> nodeFilters = programmaticArguments.getNodeFilters(); + this.nodeFiltersFromBuilder = nodeFilters; this.nodeDistanceEvaluatorsFromBuilder = programmaticArguments.getNodeDistanceEvaluators(); this.classLoader = programmaticArguments.getClassLoader(); this.cloudProxyAddress = programmaticArguments.getCloudProxyAddress(); @@ -909,6 +913,13 @@ public String getLocalDatacenter(@NonNull String profileName) { return localDatacentersFromBuilder.get(profileName); } + @Nullable + @Override + @Deprecated + public Predicate getNodeFilter(@NonNull String profileName) { + return nodeFiltersFromBuilder.get(profileName); + } + @Nullable @Override public NodeDistanceEvaluator getNodeDistanceEvaluator(@NonNull String profileName) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java index 3e3f21d0e41..0997258c149 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/InternalDriverContext.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.ProtocolVersionRegistry; @@ -49,6 +50,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; /** Extends the driver context with additional components that are not exposed by our public API. */ public interface InternalDriverContext extends DriverContext { @@ -136,6 +138,17 @@ public interface InternalDriverContext extends DriverContext { @Nullable String getLocalDatacenter(@NonNull String profileName); + /** + * This is the filter from {@link SessionBuilder#withNodeFilter(String, Predicate)}. If the filter + * for this profile was specified through the configuration instead, this method will return + * {@code null}. + * + * @deprecated Use {@link #getNodeDistanceEvaluator(String)} instead. + */ + @Nullable + @Deprecated + Predicate getNodeFilter(@NonNull String profileName); + /** * This is the node distance evaluator from {@link * SessionBuilder#withNodeDistanceEvaluator(String, NodeDistanceEvaluator)}. If the evaluator for From 6f115e72f419aafb265617b7ebf9f4553c43921f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 11 Jun 2021 15:10:49 +0200 Subject: [PATCH 138/395] Fix timeout issues --- .../cql/continuous/ContinuousPagingIT.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java index 92bfaa42e06..3ba00e4095b 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java @@ -43,6 +43,7 @@ import java.time.Duration; import java.util.Collections; import java.util.Iterator; +import java.util.Objects; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -183,7 +184,10 @@ public void simple_statement_paging_should_be_resilient_to_schema_change() { .getDefaultProfile() .withInt(DseDriverOption.CONTINUOUS_PAGING_MAX_ENQUEUED_PAGES, 1) .withInt(DseDriverOption.CONTINUOUS_PAGING_PAGE_SIZE, 1) - .withInt(DefaultDriverOption.REQUEST_TIMEOUT, 120000000); + .withDuration( + DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_FIRST_PAGE, Duration.ofSeconds(30)) + .withDuration( + DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_OTHER_PAGES, Duration.ofSeconds(30)); ContinuousResultSet result = session.executeContinuously(simple.setExecutionProfile(profile)); Iterator it = result.iterator(); // First row should have a non-null values. @@ -193,11 +197,7 @@ public void simple_statement_paging_should_be_resilient_to_schema_change() { // Make schema change to add b, its metadata should NOT be present in subsequent rows. CqlSession schemaChangeSession = SessionUtils.newSession( - ccmRule, - session.getKeyspace().orElseThrow(IllegalStateException::new), - SessionUtils.configLoaderBuilder() - .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofSeconds(30)) - .build()); + ccmRule, session.getKeyspace().orElseThrow(IllegalStateException::new)); SimpleStatement statement = SimpleStatement.newInstance("ALTER TABLE test_prepare add b int") .setExecutionProfile(sessionRule.slowProfile()); @@ -251,7 +251,11 @@ public void prepared_statement_paging_should_be_resilient_to_schema_change() { .getConfig() .getDefaultProfile() .withInt(DseDriverOption.CONTINUOUS_PAGING_MAX_ENQUEUED_PAGES, 1) - .withInt(DseDriverOption.CONTINUOUS_PAGING_PAGE_SIZE, 1); + .withInt(DseDriverOption.CONTINUOUS_PAGING_PAGE_SIZE, 1) + .withDuration( + DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_FIRST_PAGE, Duration.ofSeconds(30)) + .withDuration( + DseDriverOption.CONTINUOUS_PAGING_TIMEOUT_OTHER_PAGES, Duration.ofSeconds(30)); ContinuousResultSet result = session.executeContinuously(prepared.bind("foo").setExecutionProfile(profile)); Iterator it = result.iterator(); @@ -262,11 +266,7 @@ public void prepared_statement_paging_should_be_resilient_to_schema_change() { // Make schema change to drop v, its metadata should be present, values will be null. CqlSession schemaChangeSession = SessionUtils.newSession( - ccmRule, - session.getKeyspace().orElseThrow(IllegalStateException::new), - SessionUtils.configLoaderBuilder() - .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofSeconds(30)) - .build()); + ccmRule, session.getKeyspace().orElseThrow(IllegalStateException::new)); schemaChangeSession.execute("ALTER TABLE test_prep DROP v;"); while (it.hasNext()) { // Each row should have a value for k, v should still be present, but null since column was @@ -276,7 +276,7 @@ public void prepared_statement_paging_should_be_resilient_to_schema_change() { if (ccmRule .getDseVersion() .orElseThrow(IllegalStateException::new) - .compareTo(Version.parse("6.0.0")) + .compareTo(Objects.requireNonNull(Version.parse("6.0.0"))) >= 0) { // DSE 6 only, v should be null here since dropped. // Not reliable for 5.1 since we may have gotten page queued before schema changed. From 12f329ed78b2b96aa0d9d7a2ab23caa20b634a96 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 11 Jun 2021 15:23:34 +0200 Subject: [PATCH 139/395] Improve assertion messages --- .../cql/continuous/ContinuousPagingITBase.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java index a4c937d9311..c2bc7de9791 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java @@ -105,17 +105,21 @@ public static Object[][] pagingOptions() { protected void validateMetrics(CqlSession session) { Node node = session.getMetadata().getNodes().values().iterator().next(); - assertThat(session.getMetrics()).isPresent(); + assertThat(session.getMetrics()).as("assert session.getMetrics() present").isPresent(); Metrics metrics = session.getMetrics().get(); - assertThat(metrics.getNodeMetric(node, DefaultNodeMetric.CQL_MESSAGES)).isPresent(); + assertThat(metrics.getNodeMetric(node, DefaultNodeMetric.CQL_MESSAGES)) + .as("assert metrics.getNodeMetric(node, DefaultNodeMetric.CQL_MESSAGES) present") + .isPresent(); Timer messages = (Timer) metrics.getNodeMetric(node, DefaultNodeMetric.CQL_MESSAGES).get(); - assertThat(messages.getCount()).isGreaterThan(0); - assertThat(messages.getMeanRate()).isGreaterThan(0); - assertThat(metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS)).isPresent(); + assertThat(messages.getCount()).as("assert messages.getCount() >= 0").isGreaterThan(0); + assertThat(messages.getMeanRate()).as("assert messages.getMeanRate() >= 0").isGreaterThan(0); + assertThat(metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS)) + .as("assert metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS) present") + .isPresent(); Timer requests = (Timer) metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS).get(); - assertThat(requests.getCount()).isGreaterThan(0); - assertThat(requests.getMeanRate()).isGreaterThan(0); + assertThat(requests.getCount()).as("assert requests.getCount() >= 0").isGreaterThan(0); + assertThat(requests.getMeanRate()).as("assert requests.getMeanRate() >= 0").isGreaterThan(0); } public static class Options { From e70f0c9178ff8121891a6975c11998acc5bd7253 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 11 Jun 2021 15:24:08 +0200 Subject: [PATCH 140/395] Fix failing assumptions --- .../driver/core/metadata/SchemaChangesIT.java | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java index d45176ca825..12d817de091 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java @@ -16,19 +16,22 @@ package com.datastax.oss.driver.core.metadata; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThat; import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.metadata.Metadata; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; +import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule.Builder; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.google.common.collect.ImmutableList; @@ -48,7 +51,16 @@ public class SchemaChangesIT { - private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().build(); + static { + Builder builder = CustomCcmRule.builder(); + if (!CcmBridge.DSE_ENABLEMENT + && CcmBridge.VERSION.nextStable().compareTo(Version.V4_0_0) >= 0) { + builder.withCassandraConfiguration("enable_materialized_views", true); + } + CCM_RULE = builder.build(); + } + + private static final CustomCcmRule CCM_RULE; // A client that we only use to set up the tests private static final SessionRule ADMIN_SESSION_RULE = @@ -227,8 +239,9 @@ public void should_handle_type_update() { } @Test - @CassandraRequirement(min = "3.0") public void should_handle_view_creation() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V3_0_0) >= 0) + .isTrue(); should_handle_creation( "CREATE TABLE scores(user text, game text, score int, PRIMARY KEY (user, game))", "CREATE MATERIALIZED VIEW highscores " @@ -257,8 +270,9 @@ public void should_handle_view_creation() { } @Test - @CassandraRequirement(min = "3.0") public void should_handle_view_drop() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V3_0_0) >= 0) + .isTrue(); should_handle_drop( ImmutableList.of( "CREATE TABLE scores(user text, game text, score int, PRIMARY KEY (user, game))", @@ -276,8 +290,9 @@ public void should_handle_view_drop() { } @Test - @CassandraRequirement(min = "3.0") public void should_handle_view_update() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V3_0_0) >= 0) + .isTrue(); should_handle_update( ImmutableList.of( "CREATE TABLE scores(user text, game text, score int, PRIMARY KEY (user, game))", @@ -298,8 +313,9 @@ public void should_handle_view_update() { } @Test - @CassandraRequirement(min = "2.2") public void should_handle_function_creation() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V2_2_0) >= 0) + .isTrue(); should_handle_creation( null, "CREATE FUNCTION id(i int) RETURNS NULL ON NULL INPUT RETURNS int " @@ -321,8 +337,9 @@ public void should_handle_function_creation() { } @Test - @CassandraRequirement(min = "2.2") public void should_handle_function_drop() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V2_2_0) >= 0) + .isTrue(); should_handle_drop( ImmutableList.of( "CREATE FUNCTION id(i int) RETURNS NULL ON NULL INPUT RETURNS int " @@ -336,8 +353,9 @@ public void should_handle_function_drop() { } @Test - @CassandraRequirement(min = "2.2") public void should_handle_function_update() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V2_2_0) >= 0) + .isTrue(); should_handle_update_via_drop_and_recreate( ImmutableList.of( "CREATE FUNCTION id(i int) RETURNS NULL ON NULL INPUT RETURNS int " @@ -355,8 +373,9 @@ public void should_handle_function_update() { } @Test - @CassandraRequirement(min = "2.2") public void should_handle_aggregate_creation() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V2_2_0) >= 0) + .isTrue(); should_handle_creation( "CREATE FUNCTION plus(i int, j int) RETURNS NULL ON NULL INPUT RETURNS int " + "LANGUAGE java AS 'return i+j;'", @@ -380,8 +399,9 @@ public void should_handle_aggregate_creation() { } @Test - @CassandraRequirement(min = "2.2") public void should_handle_aggregate_drop() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V2_2_0) >= 0) + .isTrue(); should_handle_drop( ImmutableList.of( "CREATE FUNCTION plus(i int, j int) RETURNS NULL ON NULL INPUT RETURNS int " @@ -396,8 +416,9 @@ public void should_handle_aggregate_drop() { } @Test - @CassandraRequirement(min = "2.2") public void should_handle_aggregate_update() { + assumeThat(CCM_RULE.getCcmBridge().getCassandraVersion().compareTo(Version.V2_2_0) >= 0) + .isTrue(); should_handle_update_via_drop_and_recreate( ImmutableList.of( "CREATE FUNCTION plus(i int, j int) RETURNS NULL ON NULL INPUT RETURNS int " From da712c776ae48124e736299a5a5002806ec501b3 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 11 Jun 2021 15:24:25 +0200 Subject: [PATCH 141/395] Use slow profile for DDL statement --- .../test/java/com/datastax/oss/driver/mapper/UpdateIT.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java index dd6993ee40d..b531eaa6bd8 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java @@ -68,7 +68,9 @@ public static void setup() { session.execute( SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); } - session.execute("CREATE TABLE only_p_k(id uuid PRIMARY KEY)"); + session.execute( + SimpleStatement.newInstance("CREATE TABLE only_p_k(id uuid PRIMARY KEY)") + .setExecutionProfile(SESSION_RULE.slowProfile())); inventoryMapper = new UpdateIT_InventoryMapperBuilder(session).build(); dao = inventoryMapper.productDao(SESSION_RULE.keyspace()); From 869eb5581dd70cc6a93e7425d556770ee9b19ef4 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 11 Jun 2021 15:24:40 +0200 Subject: [PATCH 142/395] Move test to serial tests --- .../com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java index bd0191f359a..089c4d4fa53 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java @@ -20,7 +20,6 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.protocol.internal.request.Query; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; @@ -31,10 +30,8 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import org.junit.experimental.categories.Category; /** Test for JAVA-2654. */ -@Category(ParallelizableTests.class) public class PeersV2NodeRefreshIT { private static Server peersV2Server; From 4d7de91daacae82d9be0673e471dee0926703cc2 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 11 Jun 2021 17:23:32 +0200 Subject: [PATCH 143/395] Fix errorprone error --- .../com/datastax/oss/driver/core/metadata/SchemaChangesIT.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java index 12d817de091..fc6d1a84788 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java @@ -31,7 +31,6 @@ import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; -import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule.Builder; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.google.common.collect.ImmutableList; @@ -52,7 +51,7 @@ public class SchemaChangesIT { static { - Builder builder = CustomCcmRule.builder(); + CustomCcmRule.Builder builder = CustomCcmRule.builder(); if (!CcmBridge.DSE_ENABLEMENT && CcmBridge.VERSION.nextStable().compareTo(Version.V4_0_0) >= 0) { builder.withCassandraConfiguration("enable_materialized_views", true); From 8bdd81f70ab18aaa6360b376abd17b1c5c4b4e30 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 12 Jun 2021 19:07:57 +0200 Subject: [PATCH 144/395] JAVA-2944: Upgrade MicroProfile Metrics to 3.0 (#1551) --- changelog/README.md | 4 ++++ .../microprofile/MicroProfileMetricUpdater.java | 3 ++- pom.xml | 4 ++-- upgrade_guide/README.md | 15 +++++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 52d34c9b02a..07a35a9352e 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,10 @@ +### 4.12.0 (in progress) + +- [improvement] JAVA-2944: Upgrade MicroProfile Metrics to 3.0 + ### 4.11.2 (in progress) - [bug] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java index ea06e2bff47..3dcf0512702 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java @@ -20,6 +20,7 @@ import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.MetricId; import edu.umd.cs.findbugs.annotations.Nullable; +import java.time.Duration; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -75,7 +76,7 @@ public void markMeter(MetricT metric, @Nullable String profileName, long amount) public void updateTimer( MetricT metric, @Nullable String profileName, long duration, TimeUnit unit) { if (isEnabled(metric, profileName)) { - getOrCreateTimerFor(metric).update(duration, unit); + getOrCreateTimerFor(metric).update(Duration.ofNanos(unit.toNanos(duration))); } } diff --git a/pom.xml b/pom.xml index b6602f484a3..72e4194db9a 100644 --- a/pom.xml +++ b/pom.xml @@ -416,12 +416,12 @@ org.eclipse.microprofile.metrics microprofile-metrics-api - 2.3.3 + 3.0 io.smallrye smallrye-metrics - 2.4.6 + 3.0.3 io.projectreactor diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 6ada0de2a13..1b92cb972d6 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,20 @@ ## Upgrade guide +### 4.12.0 + +#### MicroProfile Metrics upgraded to 3.0 + +The MicroProfile Metrics library has been upgraded from version 2.4 to 3.0. Since this upgrade +involves backwards-incompatible binary changes, users of this library and of the +`java-driver-metrics-microprofile` module are required to take the appropriate action: + +* If your application is still using MicroProfile Metrics < 3.0, you can still upgrade the core + driver to 4.12, but you now must keep `java-driver-metrics-microprofile` in version 4.11 or lower, + as newer versions will not work. + +* If your application is using MicroProfile Metrics >= 3.0, then you must upgrade to driver 4.12 or + higher, as previous versions of `java-driver-metrics-microprofile` will not work. + ### 4.11.0 #### Native protocol V5 is now production-ready From 390a01cfd115f1dba237f1b8c44bef3b90b3fb17 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 12 Jun 2021 19:11:02 +0200 Subject: [PATCH 145/395] JAVA-2935: Make GetEntity and SetEntity methods resilient to incomplete data (#1556) --- changelog/README.md | 1 + .../api/core/cql/BoundStatementBuilder.java | 6 + .../user/CreateUserQueryProvider.java | 4 +- .../killrvideo/user/LoginQueryProvider.java | 2 +- .../video/CreateVideoQueryProvider.java | 2 +- .../oss/driver/mapper/GetEntityIT.java | 111 ++++++++- .../mapper/GuavaFutureProducerService.java | 2 +- .../oss/driver/mapper/ImmutableEntityIT.java | 152 +++++++++++- .../oss/driver/mapper/InventoryITBase.java | 2 + .../oss/driver/mapper/NestedUdtIT.java | 216 ++++++++++++++---- .../oss/driver/mapper/QueryProviderIT.java | 4 +- .../oss/driver/mapper/SetEntityIT.java | 85 ++++++- manual/mapper/daos/getentity/README.md | 48 ++++ manual/mapper/daos/setentity/README.md | 49 ++++ .../dao/DaoGetEntityMethodGenerator.java | 16 +- .../dao/DaoInsertMethodGenerator.java | 2 +- .../dao/DaoSetEntityMethodGenerator.java | 7 +- .../dao/DaoUpdateMethodGenerator.java | 5 +- .../EntityHelperGetMethodGenerator.java | 123 +++++++--- .../EntityHelperSetMethodGenerator.java | 11 +- .../generation/GeneratedCodePatterns.java | 42 ++-- .../mapper/reactive/ReactiveDaoBase.java | 2 +- .../driver/api/mapper/annotations/Entity.java | 5 +- .../api/mapper/annotations/GetEntity.java | 16 +- .../api/mapper/annotations/SetEntity.java | 13 ++ .../api/mapper/entity/EntityHelper.java | 81 +++++-- .../oss/driver/internal/mapper/DaoBase.java | 11 +- .../mapper/entity/EntityHelperBase.java | 47 +++- upgrade_guide/README.md | 20 ++ 29 files changed, 946 insertions(+), 139 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 07a35a9352e..971a108e469 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.12.0 (in progress) +- [improvement] JAVA-2935: Make GetEntity and SetEntity methods resilient to incomplete data - [improvement] JAVA-2944: Upgrade MicroProfile Metrics to 3.0 ### 4.11.2 (in progress) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.java index 5cdd07f2a61..090cea49bc6 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.java @@ -99,6 +99,12 @@ public BoundStatementBuilder(@NonNull BoundStatement template) { this.node = template.getNode(); } + /** The prepared statement that was used to create this statement. */ + @NonNull + public PreparedStatement getPreparedStatement() { + return preparedStatement; + } + @NonNull @Override public List allIndicesOf(@NonNull CqlIdentifier id) { diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/CreateUserQueryProvider.java b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/CreateUserQueryProvider.java index dd70ce39f95..0200c429e3a 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/CreateUserQueryProvider.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/CreateUserQueryProvider.java @@ -116,14 +116,14 @@ private boolean insertCredentialsIfNotExists(String email, char[] password, UUID UserCredentials credentials = new UserCredentials(Objects.requireNonNull(email), passwordHash, userId); BoundStatementBuilder insertCredentials = preparedInsertCredentials.boundStatementBuilder(); - credentialsHelper.set(credentials, insertCredentials, NullSavingStrategy.DO_NOT_SET); + credentialsHelper.set(credentials, insertCredentials, NullSavingStrategy.DO_NOT_SET, false); ResultSet resultSet = session.execute(insertCredentials.build()); return resultSet.wasApplied(); } private void insertUser(User user) { BoundStatementBuilder insertUser = preparedInsertUser.boundStatementBuilder(); - userHelper.set(user, insertUser, NullSavingStrategy.DO_NOT_SET); + userHelper.set(user, insertUser, NullSavingStrategy.DO_NOT_SET, false); session.execute(insertUser.build()); } } diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/LoginQueryProvider.java b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/LoginQueryProvider.java index 7b968a65bc2..3790ea7dc68 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/LoginQueryProvider.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/user/LoginQueryProvider.java @@ -62,7 +62,7 @@ Optional login(String email, char[] password) { throw new IllegalStateException( "Should have found matching row for userid " + userid); } else { - return Optional.of(userHelper.get(userRow)); + return Optional.of(userHelper.get(userRow, false)); } } else { return Optional.empty(); diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java index 6ec1c7b1aaf..cb02f70d046 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/mapper/killrvideo/video/CreateVideoQueryProvider.java @@ -95,7 +95,7 @@ private static PreparedStatement prepareInsert( private static BoundStatement bind( PreparedStatement preparedStatement, T entity, EntityHelper entityHelper) { BoundStatementBuilder boundStatement = preparedStatement.boundStatementBuilder(); - entityHelper.set(entity, boundStatement, NullSavingStrategy.DO_NOT_SET); + entityHelper.set(entity, boundStatement, NullSavingStrategy.DO_NOT_SET, false); return boundStatement.build(); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java index 2ca29a688a9..643284fb225 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GetEntityIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; @@ -25,6 +26,8 @@ import com.datastax.oss.driver.api.core.cql.ResultSet; import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.data.UdtValue; +import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.mapper.annotations.Dao; import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace; @@ -38,6 +41,7 @@ import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; import com.datastax.oss.driver.shaded.guava.common.collect.Sets; +import java.util.UUID; import java.util.stream.Stream; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -56,6 +60,8 @@ public class GetEntityIT extends InventoryITBase { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); + private static final UUID PRODUCT_2D_ID = UUID.randomUUID(); + private static ProductDao dao; @BeforeClass @@ -67,6 +73,18 @@ public static void setup() { SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); } + UserDefinedType dimensions2d = + session + .getKeyspace() + .flatMap(ks -> session.getMetadata().getKeyspace(ks)) + .flatMap(ks -> ks.getUserDefinedType("dimensions2d")) + .orElseThrow(AssertionError::new); + session.execute( + "INSERT INTO product2d (id, description, dimensions) VALUES (?, ?, ?)", + PRODUCT_2D_ID, + "2D product", + dimensions2d.newValue(12, 34)); + InventoryMapper inventoryMapper = new GetEntityIT_InventoryMapperBuilder(session).build(); dao = inventoryMapper.productDao(SESSION_RULE.keyspace()); @@ -75,12 +93,13 @@ public static void setup() { } @Test - public void should_get_entity_from_row() { + public void should_get_entity_from_complete_row() { CqlSession session = SESSION_RULE.session(); ResultSet rs = session.execute( SimpleStatement.newInstance( - "SELECT * FROM product WHERE id = ?", FLAMETHROWER.getId())); + "SELECT id, description, dimensions, now() FROM product WHERE id = ?", + FLAMETHROWER.getId())); Row row = rs.one(); assertThat(row).isNotNull(); @@ -88,6 +107,84 @@ public void should_get_entity_from_row() { assertThat(product).isEqualTo(FLAMETHROWER); } + @Test + public void should_not_get_entity_from_partial_row_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT id, description, now() FROM product WHERE id = ?", FLAMETHROWER.getId())); + Row row = rs.one(); + assertThat(row).isNotNull(); + + Throwable error = catchThrowable(() -> dao.get(row)); + assertThat(error).hasMessage("dimensions is not a column in this row"); + } + + @Test + public void should_get_entity_from_partial_row_when_lenient() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT id, dimensions FROM product2d WHERE id = ?", PRODUCT_2D_ID)); + Row row = rs.one(); + assertThat(row).isNotNull(); + + Product product = dao.getLenient(row); + assertThat(product.getId()).isEqualTo(PRODUCT_2D_ID); + assertThat(product.getDescription()).isNull(); + assertThat(product.getDimensions()).isNotNull(); + assertThat(product.getDimensions().getWidth()).isEqualTo(12); + assertThat(product.getDimensions().getHeight()).isEqualTo(34); + assertThat(product.getDimensions().getLength()).isZero(); + } + + @Test + public void should_get_entity_from_complete_udt_value() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT dimensions FROM product WHERE id = ?", FLAMETHROWER.getId())); + Row row = rs.one(); + assertThat(row).isNotNull(); + + Dimensions dimensions = dao.get(row.getUdtValue(0)); + assertThat(dimensions).isEqualTo(FLAMETHROWER.getDimensions()); + } + + @Test + public void should_not_get_entity_from_partial_udt_value_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT dimensions FROM product2d WHERE id = ?", PRODUCT_2D_ID)); + Row row = rs.one(); + assertThat(row).isNotNull(); + + Throwable error = catchThrowable(() -> dao.get(row.getUdtValue(0))); + assertThat(error).hasMessage("length is not a field in this UDT"); + } + + @Test + public void should_get_entity_from_partial_udt_value_when_lenient() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT dimensions FROM product2d WHERE id = ?", PRODUCT_2D_ID)); + Row row = rs.one(); + assertThat(row).isNotNull(); + + Dimensions dimensions = dao.getLenient(row.getUdtValue(0)); + assertThat(dimensions).isNotNull(); + assertThat(dimensions.getWidth()).isEqualTo(12); + assertThat(dimensions.getHeight()).isEqualTo(34); + assertThat(dimensions.getLength()).isZero(); + } + @Test public void should_get_entity_from_first_row_of_result_set() { CqlSession session = SESSION_RULE.session(); @@ -144,9 +241,19 @@ public interface InventoryMapper { @Dao @DefaultNullSavingStrategy(NullSavingStrategy.SET_TO_NULL) public interface ProductDao { + @GetEntity Product get(Row row); + @GetEntity(lenient = true) + Product getLenient(Row row); + + @GetEntity + Dimensions get(UdtValue row); + + @GetEntity(lenient = true) + Dimensions getLenient(UdtValue row); + @GetEntity PagingIterable get(ResultSet resultSet); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GuavaFutureProducerService.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GuavaFutureProducerService.java index d1a44428aba..bebb2adeaa1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GuavaFutureProducerService.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/GuavaFutureProducerService.java @@ -106,7 +106,7 @@ protected Object convert( @NonNull AsyncResultSet resultSet, @Nullable EntityHelper entityHelper) { assert entityHelper != null; Row row = resultSet.one(); - return (row == null) ? null : entityHelper.get(row); + return (row == null) ? null : entityHelper.get(row, false); } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java index 9ed1666f848..cfbb5b67e67 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java @@ -20,7 +20,10 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.data.UdtValue; +import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.mapper.MapperBuilder; import com.datastax.oss.driver.api.mapper.annotations.Computed; import com.datastax.oss.driver.api.mapper.annotations.CqlName; @@ -29,6 +32,7 @@ import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace; import com.datastax.oss.driver.api.mapper.annotations.DefaultNullSavingStrategy; import com.datastax.oss.driver.api.mapper.annotations.Entity; +import com.datastax.oss.driver.api.mapper.annotations.GetEntity; import com.datastax.oss.driver.api.mapper.annotations.Insert; import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; @@ -56,6 +60,8 @@ public class ImmutableEntityIT extends InventoryITBase { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); + private static final UUID PRODUCT_2D_ID = UUID.randomUUID(); + private static ImmutableProductDao dao; @BeforeClass @@ -67,6 +73,18 @@ public static void setup() { SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); } + UserDefinedType dimensions2d = + session + .getKeyspace() + .flatMap(ks -> session.getMetadata().getKeyspace(ks)) + .flatMap(ks -> ks.getUserDefinedType("dimensions2d")) + .orElseThrow(AssertionError::new); + session.execute( + "INSERT INTO product2d (id, description, dimensions) VALUES (?, ?, ?)", + PRODUCT_2D_ID, + "2D product", + dimensions2d.newValue(12, 34)); + InventoryMapper mapper = InventoryMapper.builder(session).build(); dao = mapper.immutableProductDao(SESSION_RULE.keyspace()); } @@ -74,25 +92,90 @@ public static void setup() { @Test public void should_insert_and_retrieve_immutable_entities() { ImmutableProduct originalProduct = - new ImmutableProduct(UUID.randomUUID(), "mock description", new Dimensions(1, 2, 3), -1); + new ImmutableProduct( + UUID.randomUUID(), "mock description", new ImmutableDimensions(1, 2, 3), -1); dao.save(originalProduct); ImmutableProduct retrievedProduct = dao.findById(originalProduct.id()); assertThat(retrievedProduct).isEqualTo(originalProduct); } + @Test + public void should_map_immutable_entity_from_complete_row() { + ImmutableProduct originalProduct = + new ImmutableProduct( + UUID.randomUUID(), "mock description", new ImmutableDimensions(1, 2, 3), -1); + dao.save(originalProduct); + Row row = + SESSION_RULE + .session() + .execute( + "SELECT id, description, dimensions, writetime(description) AS writetime, now() " + + "FROM product WHERE id = ?", + originalProduct.id()) + .one(); + ImmutableProduct retrievedProduct = dao.mapStrict(row); + assertThat(retrievedProduct.id()).isEqualTo(originalProduct.id()); + assertThat(retrievedProduct.description()).isEqualTo(originalProduct.description()); + assertThat(retrievedProduct.dimensions()).isEqualTo(originalProduct.dimensions()); + assertThat(retrievedProduct.writetime()).isGreaterThan(0); + } + + @Test + public void should_map_immutable_entity_from_partial_row_when_lenient() { + Row row = + SESSION_RULE + .session() + .execute("SELECT id, dimensions FROM product2d WHERE id = ?", PRODUCT_2D_ID) + .one(); + ImmutableProduct retrievedProduct = dao.mapLenient(row); + assertThat(retrievedProduct.id()).isEqualTo(PRODUCT_2D_ID); + assertThat(retrievedProduct.dimensions()).isEqualTo(new ImmutableDimensions(0, 12, 34)); + assertThat(retrievedProduct.description()).isNull(); + assertThat(retrievedProduct.writetime()).isZero(); + } + + @Test + public void should_map_immutable_entity_from_complete_udt() { + ImmutableProduct originalProduct = + new ImmutableProduct( + UUID.randomUUID(), "mock description", new ImmutableDimensions(1, 2, 3), -1); + dao.save(originalProduct); + Row row = + SESSION_RULE + .session() + .execute("SELECT dimensions FROM product WHERE id = ?", originalProduct.id()) + .one(); + assertThat(row).isNotNull(); + ImmutableDimensions retrievedDimensions = dao.mapStrict(row.getUdtValue(0)); + assertThat(retrievedDimensions).isEqualTo(originalProduct.dimensions()); + } + + @Test + public void should_map_immutable_entity_from_partial_udt_when_lenient() { + Row row = + SESSION_RULE + .session() + .execute("SELECT dimensions FROM product2d WHERE id = ?", PRODUCT_2D_ID) + .one(); + assertThat(row).isNotNull(); + ImmutableDimensions retrievedDimensions = dao.mapLenient(row.getUdtValue(0)); + assertThat(retrievedDimensions).isEqualTo(new ImmutableDimensions(0, 12, 34)); + } + @Entity @CqlName("product") @PropertyStrategy(getterStyle = FLUENT, mutable = false) public static class ImmutableProduct { @PartitionKey private final UUID id; private final String description; - private final Dimensions dimensions; + private final ImmutableDimensions dimensions; @Computed("writetime(description)") private final long writetime; - public ImmutableProduct(UUID id, String description, Dimensions dimensions, long writetime) { + public ImmutableProduct( + UUID id, String description, ImmutableDimensions dimensions, long writetime) { this.id = id; this.description = description; this.dimensions = dimensions; @@ -107,7 +190,7 @@ public String description() { return description; } - public Dimensions dimensions() { + public ImmutableDimensions dimensions() { return dimensions; } @@ -135,6 +218,55 @@ public int hashCode() { } } + @Entity + @PropertyStrategy(mutable = false) + public static class ImmutableDimensions { + + private final int length; + private final int width; + private final int height; + + public ImmutableDimensions(int length, int width, int height) { + this.length = length; + this.width = width; + this.height = height; + } + + public int getLength() { + return length; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof ImmutableDimensions) { + ImmutableDimensions that = (ImmutableDimensions) other; + return this.length == that.length && this.width == that.width && this.height == that.height; + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(length, width, height); + } + + @Override + public String toString() { + return "Dimensions{length=" + length + ", width=" + width + ", height=" + height + '}'; + } + } + @Mapper public interface InventoryMapper { static MapperBuilder builder(CqlSession session) { @@ -153,5 +285,17 @@ public interface ImmutableProductDao { @Insert void save(ImmutableProduct product); + + @GetEntity + ImmutableProduct mapStrict(Row row); + + @GetEntity(lenient = true) + ImmutableProduct mapLenient(Row row); + + @GetEntity + ImmutableDimensions mapStrict(UdtValue udt); + + @GetEntity(lenient = true) + ImmutableDimensions mapLenient(UdtValue udt); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java index 2b094c4dbe8..3a0435c5da1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java @@ -62,6 +62,8 @@ protected static List createStatements(CcmRule ccmRule) { .add( "CREATE TYPE dimensions(length int, width int, height int)", "CREATE TABLE product(id uuid PRIMARY KEY, description text, dimensions frozen)", + "CREATE TYPE dimensions2d(width int, height int)", + "CREATE TABLE product2d(id uuid PRIMARY KEY, description text, dimensions frozen)", "CREATE TABLE product_without_id(id uuid, clustering int, description text, " + "PRIMARY KEY((id), clustering))", "CREATE TABLE product_sale(id uuid, day text, ts uuid, customer_id int, price " diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java index 6bcbde6ffff..b7b8742e53c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java @@ -16,11 +16,17 @@ package com.datastax.oss.driver.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; -import com.datastax.oss.driver.api.core.data.GettableByName; +import com.datastax.oss.driver.api.core.data.UdtValue; +import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.mapper.annotations.Dao; import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace; @@ -30,6 +36,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; import com.datastax.oss.driver.api.mapper.annotations.Select; +import com.datastax.oss.driver.api.mapper.annotations.SetEntity; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; @@ -43,6 +50,7 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; +import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -63,21 +71,24 @@ public class NestedUdtIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); - private static UUID CONTAINER_ID = UUID.randomUUID(); + private static final UUID CONTAINER_ID = UUID.randomUUID(); + private static final Container SAMPLE_CONTAINER = new Container( CONTAINER_ID, - ImmutableList.of(new Type1("a"), new Type1("b")), + ImmutableList.of(new Type1("a1", "a2"), new Type1("b1", "b2")), ImmutableMap.of( "cd", - ImmutableList.of(new Type1("c"), new Type1("d")), + ImmutableList.of(new Type1("c1", "c2"), new Type1("d1", "d2")), "ef", - ImmutableList.of(new Type1("e"), new Type1("f"))), + ImmutableList.of(new Type1("e1", "e2"), new Type1("f1", "f2"))), ImmutableMap.of( - new Type1("12"), - ImmutableSet.of(ImmutableList.of(new Type2(1)), ImmutableList.of(new Type2(2)))), + new Type1("12", "34"), + ImmutableSet.of( + ImmutableList.of(new Type2(1, 2)), ImmutableList.of(new Type2(3, 4)))), ImmutableMap.of( - new Type1("12"), ImmutableMap.of("12", ImmutableSet.of(new Type2(1), new Type2(2))))); + new Type1("12", "34"), + ImmutableMap.of("12", ImmutableSet.of(new Type2(1, 2), new Type2(3, 4))))); private static final Container SAMPLE_CONTAINER_NULL_LIST = new Container( @@ -85,14 +96,16 @@ public class NestedUdtIT { null, ImmutableMap.of( "cd", - ImmutableList.of(new Type1("c"), new Type1("d")), + ImmutableList.of(new Type1("c1", "c2"), new Type1("d1", "d2")), "ef", - ImmutableList.of(new Type1("e"), new Type1("f"))), + ImmutableList.of(new Type1("e1", "e2"), new Type1("f1", "f2"))), ImmutableMap.of( - new Type1("12"), - ImmutableSet.of(ImmutableList.of(new Type2(1)), ImmutableList.of(new Type2(2)))), + new Type1("12", "34"), + ImmutableSet.of( + ImmutableList.of(new Type2(1, 2)), ImmutableList.of(new Type2(3, 4)))), ImmutableMap.of( - new Type1("12"), ImmutableMap.of("12", ImmutableSet.of(new Type2(1), new Type2(2))))); + new Type1("12", "34"), + ImmutableMap.of("12", ImmutableSet.of(new Type2(1, 2), new Type2(3, 4))))); private static ContainerDao containerDao; @@ -102,18 +115,39 @@ public static void setup() { for (String query : ImmutableList.of( - "CREATE TYPE type1(s text)", - "CREATE TYPE type2(i int)", + "CREATE TYPE type1(s1 text, s2 text)", + "CREATE TYPE type2(i1 int, i2 int)", + "CREATE TYPE type1_partial(s1 text)", + "CREATE TYPE type2_partial(i1 int)", "CREATE TABLE container(id uuid PRIMARY KEY, " + "list frozen>, " + "map1 frozen>>, " + "map2 frozen>>>," + "map3 frozen>>>" + + ")", + "CREATE TABLE container_partial(id uuid PRIMARY KEY, " + + "list frozen>, " + + "map1 frozen>>, " + + "map2 frozen>>>," + + "map3 frozen>>>" + ")")) { session.execute( SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); } + UserDefinedType type1Partial = + session + .getKeyspace() + .flatMap(ks -> session.getMetadata().getKeyspace(ks)) + .flatMap(ks -> ks.getUserDefinedType("type1_partial")) + .orElseThrow(AssertionError::new); + + session.execute( + SimpleStatement.newInstance( + "INSERT INTO container_partial (id, list) VALUES (?, ?)", + SAMPLE_CONTAINER.getId(), + Lists.newArrayList(type1Partial.newValue("a"), type1Partial.newValue("b")))); + UdtsMapper udtsMapper = new NestedUdtIT_UdtsMapperBuilder(session).build(); containerDao = udtsMapper.containerDao(SESSION_RULE.keyspace()); } @@ -165,6 +199,71 @@ public void should_insert_set_to_null_udts() { assertThat(retrievedEntitySecond.list).isEmpty(); } + @Test + public void should_get_entity_from_complete_row() { + CqlSession session = SESSION_RULE.session(); + containerDao.save(SAMPLE_CONTAINER); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT * FROM container WHERE id = ?", SAMPLE_CONTAINER.getId())); + Row row = rs.one(); + assertThat(row).isNotNull(); + Container actual = containerDao.get(row); + assertThat(actual).isEqualTo(SAMPLE_CONTAINER); + } + + @Test + public void should_not_get_entity_from_partial_row_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + containerDao.save(SAMPLE_CONTAINER); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT id FROM container WHERE id = ?", SAMPLE_CONTAINER.getId())); + Row row = rs.one(); + assertThat(row).isNotNull(); + Throwable error = catchThrowable(() -> containerDao.get(row)); + assertThat(error).hasMessage("list is not a column in this row"); + } + + @Test + public void should_get_entity_from_partial_row_when_lenient() { + CqlSession session = SESSION_RULE.session(); + ResultSet rs = + session.execute( + SimpleStatement.newInstance( + "SELECT id, list FROM container_partial WHERE id = ?", SAMPLE_CONTAINER.getId())); + Row row = rs.one(); + assertThat(row).isNotNull(); + Container actual = containerDao.getLenient(row); + assertThat(actual.getId()).isEqualTo(SAMPLE_CONTAINER.getId()); + assertThat(actual.getList()).containsExactly(new Type1("a", null), new Type1("b", null)); + assertThat(actual.getMap1()).isNull(); + assertThat(actual.getMap2()).isNull(); + assertThat(actual.getMap3()).isNull(); + } + + @Test + public void should_set_entity_on_partial_statement_builder_when_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = + session.prepare("INSERT INTO container_partial (id, list) VALUES (?, ?)"); + BoundStatementBuilder builder = ps.boundStatementBuilder(); + containerDao.setLenient(SAMPLE_CONTAINER, builder); + assertThat(builder.getUuid(0)).isEqualTo(SAMPLE_CONTAINER.getId()); + assertThat(builder.getList(1, UdtValue.class)).hasSize(2); + } + + @Test + public void should_not_set_entity_on_partial_statement_builder_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO container (id, list) VALUES (?, ?)"); + Throwable error = + catchThrowable(() -> containerDao.set(SAMPLE_CONTAINER, ps.boundStatementBuilder())); + assertThat(error).hasMessage("map1 is not a variable in this bound statement"); + } + @Mapper public interface UdtsMapper { @DaoFactory @@ -187,7 +286,16 @@ public interface ContainerDao { void saveSetToNull(Container container); @GetEntity - Container get(GettableByName source); + Container get(Row source); + + @GetEntity(lenient = true) + Container getLenient(Row source); + + @SetEntity + void set(Container container, BoundStatementBuilder target); + + @SetEntity(lenient = true) + void setLenient(Container container, BoundStatementBuilder target); } @Entity @@ -278,73 +386,93 @@ public int hashCode() { @Entity public static class Type1 { - private String s; + private String s1; + private String s2; public Type1() {} - public Type1(String s) { - this.s = s; + public Type1(String s1, String s2) { + this.s1 = s1; + this.s2 = s2; } - public String getS() { - return s; + public String getS1() { + return s1; } - public void setS(String s) { - this.s = s; + public void setS1(String s1) { + this.s1 = s1; + } + + public String getS2() { + return s2; + } + + public void setS2(String s2) { + this.s2 = s2; } @Override - public boolean equals(Object other) { - if (other == this) { + public boolean equals(Object o) { + if (this == o) { return true; - } else if (other instanceof Type1) { - Type1 that = (Type1) other; - return Objects.equals(this.s, that.s); - } else { + } + if (!(o instanceof Type1)) { return false; } + Type1 type1 = (Type1) o; + return Objects.equals(s1, type1.s1) && Objects.equals(s2, type1.s2); } @Override public int hashCode() { - return s == null ? 0 : s.hashCode(); + return Objects.hash(s1, s2); } } @Entity public static class Type2 { - private int i; + private int i1; + private int i2; public Type2() {} - public Type2(int i) { - this.i = i; + public Type2(int i1, int i2) { + this.i1 = i1; + this.i2 = i2; } - public int getI() { - return i; + public int getI1() { + return i1; } - public void setI(int i) { - this.i = i; + public void setI1(int i1) { + this.i1 = i1; + } + + public int getI2() { + return i2; + } + + public void setI2(int i2) { + this.i2 = i2; } @Override - public boolean equals(Object other) { - if (other == this) { + public boolean equals(Object o) { + if (this == o) { return true; - } else if (other instanceof Type2) { - Type2 that = (Type2) other; - return this.i == that.i; - } else { + } + if (!(o instanceof Type2)) { return false; } + Type2 type2 = (Type2) o; + return i1 == type2.i1 && i2 == type2.i2; } @Override public int hashCode() { - return i; + return Objects.hash(i1, i2); } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java index 1fb92637b22..3fc54d2826d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryProviderIT.java @@ -168,7 +168,9 @@ public PagingIterable findSlice(int id, Integer month, Integer da boundStatementBuilder = boundStatementBuilder.setInt("day", day); } } - return session.execute(boundStatementBuilder.build()).map(sensorReadingHelper::get); + return session + .execute(boundStatementBuilder.build()) + .map(row -> sensorReadingHelper.get(row, false)); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SetEntityIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SetEntityIT.java index 32be286325f..f6fe6c6e25d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SetEntityIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SetEntityIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; @@ -52,8 +53,7 @@ public class SetEntityIT extends InventoryITBase { public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); private static ProductDao dao; - - private static InventoryMapper inventoryMapper; + private static UserDefinedType dimensions2d; @BeforeClass public static void setup() { @@ -64,8 +64,14 @@ public static void setup() { SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); } - inventoryMapper = new SetEntityIT_InventoryMapperBuilder(session).build(); + InventoryMapper inventoryMapper = new SetEntityIT_InventoryMapperBuilder(session).build(); dao = inventoryMapper.productDao(SESSION_RULE.keyspace()); + dimensions2d = + session + .getKeyspace() + .flatMap(ks -> session.getMetadata().getKeyspace(ks)) + .flatMap(ks -> ks.getUserDefinedType("dimensions2d")) + .orElseThrow(AssertionError::new); } @Test @@ -144,10 +150,74 @@ public void should_set_entity_on_udt_value() { assertThat(udtValue.getInt("height")).isEqualTo(dimensions.getHeight()); } + @Test + public void should_set_entity_on_partial_statement_when_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO product (id, description) VALUES (?, ?)"); + BoundStatement bound = dao.setLenient(FLAMETHROWER, ps.bind()); + assertThat(bound.getUuid(0)).isEqualTo(FLAMETHROWER.getId()); + assertThat(bound.getString(1)).isEqualTo(FLAMETHROWER.getDescription()); + } + + @Test + public void should_set_entity_on_partial_statement_builder_when_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO product (id, description) VALUES (?, ?)"); + BoundStatementBuilder builder = ps.boundStatementBuilder(); + dao.setLenient(FLAMETHROWER, builder); + assertThat(builder.getUuid(0)).isEqualTo(FLAMETHROWER.getId()); + assertThat(builder.getString(1)).isEqualTo(FLAMETHROWER.getDescription()); + } + + @Test + @SuppressWarnings("ResultOfMethodCallIgnored") + public void should_set_entity_on_partial_udt_when_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO product2d (id, dimensions) VALUES (?, ?)"); + BoundStatementBuilder builder = ps.boundStatementBuilder(); + builder.setUuid(0, FLAMETHROWER.getId()); + UdtValue dimensionsUdt = dimensions2d.newValue(); + Dimensions dimensions = new Dimensions(12, 34, 56); + dao.setLenient(dimensions, dimensionsUdt); + builder.setUdtValue(1, dimensionsUdt); + assertThat(dimensionsUdt.getInt("width")).isEqualTo(34); + assertThat(dimensionsUdt.getInt("height")).isEqualTo(56); + } + + @Test + public void should_not_set_entity_on_partial_statement_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO product (id, description) VALUES (?, ?)"); + Throwable error = catchThrowable(() -> dao.set(FLAMETHROWER, ps.bind())); + assertThat(error).hasMessage("dimensions is not a variable in this bound statement"); + } + + @Test + public void should_not_set_entity_on_partial_statement_builder_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO product (id, description) VALUES (?, ?)"); + Throwable error = catchThrowable(() -> dao.set(ps.boundStatementBuilder(), FLAMETHROWER)); + assertThat(error).hasMessage("dimensions is not a variable in this bound statement"); + } + + @Test + @SuppressWarnings("ResultOfMethodCallIgnored") + public void should_not_set_entity_on_partial_udt_when_not_lenient() { + CqlSession session = SESSION_RULE.session(); + PreparedStatement ps = session.prepare("INSERT INTO product2d (id, dimensions) VALUES (?, ?)"); + BoundStatementBuilder builder = ps.boundStatementBuilder(); + builder.setUuid(0, FLAMETHROWER.getId()); + UdtValue dimensionsUdt = dimensions2d.newValue(); + Dimensions dimensions = new Dimensions(12, 34, 56); + Throwable error = catchThrowable(() -> dao.set(dimensions, dimensionsUdt)); + assertThat(error).hasMessage("length is not a field in this UDT"); + } + private static void assertMatches(GettableByName data, Product entity) { assertThat(data.getUuid("id")).isEqualTo(entity.getId()); assertThat(data.getString("description")).isEqualTo(entity.getDescription()); UdtValue udtValue = data.getUdtValue("dimensions"); + assertThat(udtValue).isNotNull(); assertThat(udtValue.getType().getName().asInternal()).isEqualTo("dimensions"); assertThat(udtValue.getInt("length")).isEqualTo(entity.getDimensions().getLength()); assertThat(udtValue.getInt("width")).isEqualTo(entity.getDimensions().getWidth()); @@ -177,5 +247,14 @@ public interface ProductDao { @SetEntity void set(Dimensions dimensions, UdtValue udtValue); + + @SetEntity(lenient = true) + BoundStatement setLenient(Product product, BoundStatement boundStatement); + + @SetEntity(lenient = true) + void setLenient(Product product, BoundStatementBuilder builder); + + @SetEntity(lenient = true) + void setLenient(Dimensions dimensions, UdtValue udtValue); } } diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index 207f84e136d..e495f964557 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -23,6 +23,54 @@ product.setDescription(row.get("description", String.class)); It does not perform a query. Instead, those methods are intended for cases where you already have a query result, and just need the conversion logic. +### Lenient mode + +By default, the mapper operates in "strict" mode: the source row must contain a matching column for +every property in the entity definition, *including computed ones*. If such a column is not found, +an error will be thrown. + +Starting with driver 4.12.0, the `@GetEntity` annotation has a new `lenient` attribute. If this +attribute is explicitly set to `true`, the mapper will operate in "lenient" mode: all entity +properties that have a matching column in the source row will be set. However, *unmatched properties +will be left untouched*. + +As an example to illustrate how lenient mode works, assume that we have the following entity and +DAO: + +```java +@Entity class Product { + + @PartitionKey int id; + String description; + float price; + // other members omitted +} + +interface ProductDao { + + @GetEntity(lenient = true) + Product getLenient(Row row); + +} +``` + +Then the following code would be possible: + +```java +// row does not contain the price column +Row row = session.execute("SELECT id, description FROM product").one(); +Product product = productDao.getLenient(row); +assert product.price == 0.0; +``` + +Since no `price` column was found in the source row, `product.price` wasn't set and was left to its +default value (0.0). Without lenient mode, the code above would throw an error instead. + +Lenient mode allows to achieve the equivalent of driver 3.x [manual mapping +feature](https://docs.datastax.com/en/developer/java-driver/3.10/manual/object_mapper/using/#manual-mapping). + +**Beware that lenient mode may result in incomplete entities being produced.** + ### Parameters The method must have a single parameter. The following types are allowed: diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index 54925fac574..3d887b34a91 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -21,6 +21,55 @@ boundStatement = boundStatement.set("description", product.getDescription(), Str It does not perform a query. Instead, those methods are intended for cases where you will execute the query yourself, and just need the conversion logic. +### Lenient mode + +By default, the mapper operates in "strict" mode: the target statement must contain a matching +column for every property in the entity definition, *except computed ones*. If such a column is not +found, an error will be thrown. + +Starting with driver 4.12.0, the `@SetEntity` annotation has a new `lenient` attribute. If this +attribute is explicitly set to `true`, the mapper will operate in "lenient" mode: all entity +properties that have a matching column in the target statement will be set. However, *unmatched +properties will be left untouched*. + +As an example to illustrate how lenient mode works, assume that we have the following entity and +DAO: + +```java +@Entity class Product { + + @PartitionKey int id; + String description; + float price; + // other members omitted +} + +interface ProductDao { + + @SetEntity(lenient = true) + BoundStatement setLenient(Product product, BoundStatement stmt); + +} +``` + +Then the following code would be possible: + +```java +Product product = new Product(1, "scented candle", 12.99); +// stmt does not contain the price column +BoundStatement stmt = session.prepare("INSERT INTO product (id, description) VALUES (?, ?)").bind(); +stmt = productDao.setLenient(product, stmt); +``` + +Since no `price` column was found in the target statement, `product.price` wasn't read (if the +statement is executed, the resulting row in the database will have a price of zero). Without lenient +mode, the code above would throw an error instead. + +Lenient mode allows to achieve the equivalent of driver 3.x [manual mapping +feature](https://docs.datastax.com/en/developer/java-driver/3.10/manual/object_mapper/using/#manual-mapping). + +**Beware that lenient mode may result in incomplete rows being inserted in the database.** + ### Parameters The method must have two parameters: one is the entity instance, the other must be a subtype of diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java index 1d4d52fe940..04205891f61 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoGetEntityMethodGenerator.java @@ -54,6 +54,8 @@ private enum Transformation { STREAM, } + private final boolean lenient; + public DaoGetEntityMethodGenerator( ExecutableElement methodElement, Map typeParameters, @@ -61,6 +63,7 @@ public DaoGetEntityMethodGenerator( DaoImplementationSharedCode enclosingClass, ProcessorContext context) { super(methodElement, typeParameters, processedType, enclosingClass, context); + lenient = methodElement.getAnnotation(GetEntity.class).lenient(); } @Override @@ -170,23 +173,26 @@ public Optional generate() { GeneratedCodePatterns.override(methodElement, typeParameters); switch (transformation) { case NONE: - overridingMethodBuilder.addStatement("return $L.get($L)", helperFieldName, parameterName); + overridingMethodBuilder.addStatement( + "return $L.get($L, $L)", helperFieldName, parameterName, lenient); break; case ONE: overridingMethodBuilder .addStatement("$T row = $L.one()", Row.class, parameterName) - .addStatement("return (row == null) ? null : $L.get(row)", helperFieldName); + .addStatement( + "return (row == null) ? null : $L.get(row, $L)", helperFieldName, lenient); break; case MAP: overridingMethodBuilder.addStatement( - "return $L.map($L::get)", parameterName, helperFieldName); + "return $L.map(row -> $L.get(row, $L))", parameterName, helperFieldName, lenient); break; case STREAM: overridingMethodBuilder.addStatement( - "return $T.stream($L.map($L::get).spliterator(), false)", + "return $T.stream($L.map(row -> $L.get(row, $L)).spliterator(), false)", StreamSupport.class, parameterName, - helperFieldName); + helperFieldName, + lenient); break; } return Optional.of(overridingMethodBuilder.build()); diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java index 945cfeda370..8359c3ce505 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java @@ -159,7 +159,7 @@ public Optional generate() { Insert.class, Insert::nullSavingStrategy, methodElement, enclosingClass); createStatementBlock.addStatement( - "$1L.set($2L, boundStatementBuilder, $3T.$4L)", + "$1L.set($2L, boundStatementBuilder, $3T.$4L, false)", helperFieldName, entityParameterName, NullSavingStrategy.class, diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSetEntityMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSetEntityMethodGenerator.java index 71b40976a90..d3e4a69aaa6 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSetEntityMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSetEntityMethodGenerator.java @@ -35,6 +35,7 @@ public class DaoSetEntityMethodGenerator extends DaoMethodGenerator { private final NullSavingStrategyValidation nullSavingStrategyValidation; + private final boolean lenient; public DaoSetEntityMethodGenerator( ExecutableElement methodElement, @@ -44,6 +45,7 @@ public DaoSetEntityMethodGenerator( ProcessorContext context) { super(methodElement, typeParameters, processedType, enclosingClass, context); nullSavingStrategyValidation = new NullSavingStrategyValidation(context); + lenient = methodElement.getAnnotation(SetEntity.class).lenient(); } @Override @@ -130,13 +132,14 @@ public Optional generate() { return Optional.of( GeneratedCodePatterns.override(methodElement, typeParameters) .addStatement( - "$1L$2L.set($3L, $4L, $5T.$6L)", + "$1L$2L.set($3L, $4L, $5T.$6L, $7L)", isVoid ? "" : "return ", helperFieldName, entityParameterName, targetParameterName, NullSavingStrategy.class, - nullSavingStrategy) + nullSavingStrategy, + lenient) .build()); } } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java index 288778ee9c8..be9c53a7021 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java @@ -152,7 +152,7 @@ public Optional generate() { // We generated an update by primary key (see maybeAddWhereClause), all entity properties are // present as placeholders. createStatementBlock.addStatement( - "$1L.set($2L, boundStatementBuilder, $3T.$4L)", + "$1L.set($2L, boundStatementBuilder, $3T.$4L, false)", helperFieldName, entityParameterName, NullSavingStrategy.class, @@ -171,7 +171,8 @@ public Optional generate() { "boundStatementBuilder", createStatementBlock, enclosingClass, - true); + true, + false); } } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java index f0a84517c63..adcf8dd2634 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java @@ -55,6 +55,7 @@ public Optional generate() { .addModifiers(Modifier.PUBLIC) .addParameter( ParameterSpec.builder(ClassName.get(GettableByName.class), "source").build()) + .addParameter(ParameterSpec.builder(TypeName.BOOLEAN, "lenient").build()) .returns(entityDefinition.getClassName()); TypeName returnType = entityDefinition.getClassName(); @@ -75,20 +76,57 @@ public Optional generate() { String setterName = property.getSetterName(); String propertyValueName = enclosingClass.getNameIndex().uniqueField("propertyValue"); propertyValueNames.add(propertyValueName); - getBuilder.addCode("\n"); + if (type instanceof PropertyType.Simple) { TypeName typeName = ((PropertyType.Simple) type).typeName; String primitiveAccessor = GeneratedCodePatterns.PRIMITIVE_ACCESSORS.get(typeName); if (primitiveAccessor != null) { // Primitive type: use dedicated getter, since it is optimized to avoid boxing // int propertyValue1 = source.getInt("length"); - getBuilder.addStatement( - "$T $L = source.get$L($L)", typeName, propertyValueName, primitiveAccessor, cqlName); + if (mutable) { + getBuilder + .beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName) + .addStatement( + "$T $L = source.get$L($L)", + typeName, + propertyValueName, + primitiveAccessor, + cqlName) + .addStatement("$L.$L($L)", resultName, setterName, propertyValueName) + .endControlFlow(); + } else { + getBuilder.addStatement( + "$T $L = !lenient || hasProperty(source, $L) ? source.get$L($L) : $L", + typeName, + propertyValueName, + cqlName, + primitiveAccessor, + cqlName, + typeName.equals(TypeName.BOOLEAN) ? false : 0); + } } else if (typeName instanceof ClassName) { // Unparameterized class: use the generic, class-based getter: // UUID propertyValue1 = source.get("id", UUID.class); - getBuilder.addStatement( - "$T $L = source.get($L, $T.class)", typeName, propertyValueName, cqlName, typeName); + if (mutable) { + getBuilder + .beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName) + .addStatement( + "$T $L = source.get($L, $T.class)", + typeName, + propertyValueName, + cqlName, + typeName) + .addStatement("$L.$L($L)", resultName, setterName, propertyValueName) + .endControlFlow(); + } else { + getBuilder.addStatement( + "$T $L = !lenient || hasProperty(source, $L) ? source.get($L, $T.class) : null", + typeName, + propertyValueName, + cqlName, + cqlName, + typeName); + } } else { // Parameterized type: create a constant and use the GenericType-based getter: // private static final GenericType> GENERIC_TYPE = @@ -97,37 +135,56 @@ public Optional generate() { // Note that lists, sets and maps of unparameterized classes also fall under that // category. Their getter creates a GenericType under the hood, so there's no performance // advantage in calling them instead of the generic get(). - getBuilder.addStatement( - "$T $L = source.get($L, $L)", - typeName, - propertyValueName, - cqlName, - enclosingClass.addGenericTypeConstant(typeName)); + if (mutable) { + getBuilder + .beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName) + .addStatement( + "$T $L = source.get($L, $L)", + typeName, + propertyValueName, + cqlName, + enclosingClass.addGenericTypeConstant(typeName)) + .addStatement("$L.$L($L)", resultName, setterName, propertyValueName) + .endControlFlow(); + } else { + getBuilder.addStatement( + "$T $L = !lenient || hasProperty(source, $L) ? source.get($L, $L) : null", + typeName, + propertyValueName, + cqlName, + cqlName, + enclosingClass.addGenericTypeConstant(typeName)); + } } } else if (type instanceof PropertyType.SingleEntity) { ClassName entityClass = ((PropertyType.SingleEntity) type).entityName; // Other entity class: the CQL column is a mapped UDT: // Dimensions propertyValue1; // UdtValue udtValue1 = source.getUdtValue("dimensions"); - // if (udtValue1 == null) { - // propertyValue1 = null; - // } else { - // propertyValue1 = dimensionsHelper.get(udtValue1); - // } - getBuilder.addStatement("$T $L", entityClass, propertyValueName); - + // propertyValue1 = udtValue1 == null ? null : dimensionsHelper.get(udtValue1); String udtValueName = enclosingClass.getNameIndex().uniqueField("udtValue"); + if (mutable) { + getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName); + getBuilder.addStatement("$T $L", entityClass, propertyValueName); + } else { + getBuilder.addStatement("$T $L = null", entityClass, propertyValueName); + getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName); + } getBuilder.addStatement( "$T $L = source.getUdtValue($L)", UdtValue.class, udtValueName, cqlName); - getBuilder - .beginControlFlow("if ($L == null)", udtValueName) - .addStatement("$L = null", propertyValueName) - .nextControlFlow("else"); - // Get underlying udt object and set it on return type String childHelper = enclosingClass.addEntityHelperField(entityClass); - getBuilder.addStatement("$L = $L.get($L)", propertyValueName, childHelper, udtValueName); + getBuilder.addStatement( + "$L = $L == null ? null : $L.get($L, lenient)", + propertyValueName, + udtValueName, + childHelper, + udtValueName); + + if (mutable) { + getBuilder.addStatement("$L.$L($L)", resultName, setterName, propertyValueName); + } getBuilder.endControlFlow(); } else { // Collection of other entity class(es): the CQL column is a collection of mapped UDTs @@ -140,7 +197,13 @@ public Optional generate() { // traverse rawCollection1 and convert all UdtValue into entity classes, recursing // into nested collections if necessary // } - getBuilder.addStatement("$T $L", type.asTypeName(), propertyValueName); + if (mutable) { + getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName); + getBuilder.addStatement("$T $L", type.asTypeName(), propertyValueName); + } else { + getBuilder.addStatement("$T $L = null", type.asTypeName(), propertyValueName); + getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName); + } String rawCollectionName = enclosingClass.getNameIndex().uniqueField("rawCollection"); TypeName rawCollectionType = type.asRawTypeName(); @@ -157,10 +220,11 @@ public Optional generate() { .nextControlFlow("else"); convertUdtsIntoEntities(rawCollectionName, propertyValueName, type, getBuilder); getBuilder.endControlFlow(); - } - if (mutable) { - getBuilder.addStatement("$L.$L($L)", resultName, setterName, propertyValueName); + if (mutable) { + getBuilder.addStatement("$L.$L($L)", resultName, setterName, propertyValueName); + } + getBuilder.endControlFlow(); } } @@ -197,7 +261,8 @@ private void convertUdtsIntoEntities( if (type instanceof PropertyType.SingleEntity) { ClassName entityClass = ((PropertyType.SingleEntity) type).entityName; String entityHelperName = enclosingClass.addEntityHelperField(entityClass); - getBuilder.addStatement("$L = $L.get($L)", mappedObjectName, entityHelperName, rawObjectName); + getBuilder.addStatement( + "$L = $L.get($L, lenient)", mappedObjectName, entityHelperName, rawObjectName); } else if (type instanceof PropertyType.EntityList) { getBuilder.addStatement( "$L = $T.newArrayListWithExpectedSize($L.size())", diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java index 5e3042c10ac..482b4b5a8e5 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java @@ -25,6 +25,7 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; import java.util.Optional; import javax.lang.model.element.Modifier; @@ -43,8 +44,6 @@ public EntityHelperSetMethodGenerator( @Override public Optional generate() { - // TODO add an ignore mechanism? this fails if a property is missing on the target. - // The method's type variable: > TypeVariableName settableT = TypeVariableName.get("SettableT"); settableT = @@ -60,10 +59,15 @@ public Optional generate() { .addParameter(ParameterSpec.builder(settableT, "target").build()) .addParameter( ParameterSpec.builder(NullSavingStrategy.class, "nullSavingStrategy").build()) + .addParameter(ParameterSpec.builder(TypeName.BOOLEAN, "lenient").build()) .returns(settableT); CodeBlock.Builder injectBodyBuilder = CodeBlock.builder(); for (PropertyDefinition property : entityDefinition.getAllColumns()) { + + injectBodyBuilder.beginControlFlow( + "if (!lenient || hasProperty(target, $L))", property.getCqlName()); + GeneratedCodePatterns.setValue( property.getCqlName(), property.getType(), @@ -71,7 +75,10 @@ public Optional generate() { "target", injectBodyBuilder, enclosingClass, + true, true); + + injectBodyBuilder.endControlFlow(); } injectBodyBuilder.add("\n").addStatement("return target"); return Optional.of(injectBuilder.addCode(injectBodyBuilder.build()).build()); diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java index 48574a48721..2cbc7027b60 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java @@ -186,7 +186,8 @@ public static void bindParameters( "boundStatementBuilder", methodBuilder, enclosingClass, - useNullSavingStrategy); + useNullSavingStrategy, + false); } } @@ -214,7 +215,8 @@ public static void setValue( String targetName, CodeBlock.Builder methodBuilder, BindableHandlingSharedCode enclosingClass) { - setValue(cqlName, type, valueExtractor, targetName, methodBuilder, enclosingClass, false); + setValue( + cqlName, type, valueExtractor, targetName, methodBuilder, enclosingClass, false, false); } public static void setValue( @@ -224,8 +226,8 @@ public static void setValue( String targetName, CodeBlock.Builder methodBuilder, BindableHandlingSharedCode enclosingClass, - boolean useNullSavingStrategy) { - methodBuilder.add("\n"); + boolean useNullSavingStrategy, + boolean useLeniency) { if (type instanceof PropertyType.Simple) { TypeName typeName = ((PropertyType.Simple) type).typeName; @@ -293,12 +295,13 @@ public static void setValue( // driver doesn't have the ability to send partial UDT, unset values values will be // serialized to null - set NullSavingStrategy.DO_NOT_SET explicitly .addStatement( - "$L.set($L, $L, $T.$L)", + "$L.set($L, $L, $T.$L, $L)", childHelper, valueName, udtValueName, NullSavingStrategy.class, - NullSavingStrategy.DO_NOT_SET) + NullSavingStrategy.DO_NOT_SET, + useLeniency ? "lenient" : false) .addStatement("$1L = $1L.setUdtValue($2L, $3L)", targetName, cqlName, udtValueName); if (useNullSavingStrategy) { methodBuilder.nextControlFlow( @@ -331,7 +334,8 @@ public static void setValue( currentCqlType, udtTypesBuilder, conversionCodeBuilder, - enclosingClass); + enclosingClass, + useLeniency); methodBuilder .add(udtTypesBuilder.build()) @@ -439,7 +443,8 @@ public static void setValue( targetName, methodBuilder, enclosingClass, - useNullSavingStrategy); + useNullSavingStrategy, + false); } /** @@ -455,6 +460,7 @@ public static void setValue( * variables that extract the required {@link UserDefinedType} instances from the target * container. * @param conversionBuilder the code block to generate the conversion code into. + * @param useLeniency whether the 'lenient' boolean variable is in scope. */ private static void convertEntitiesIntoUdts( String mappedObjectName, @@ -463,7 +469,8 @@ private static void convertEntitiesIntoUdts( CodeBlock currentCqlType, CodeBlock.Builder udtTypesBuilder, CodeBlock.Builder conversionBuilder, - BindableHandlingSharedCode enclosingClass) { + BindableHandlingSharedCode enclosingClass, + boolean useLeniency) { if (type instanceof PropertyType.SingleEntity) { ClassName entityClass = ((PropertyType.SingleEntity) type).entityName; @@ -480,12 +487,13 @@ private static void convertEntitiesIntoUdts( // driver doesn't have the ability to send partial UDT, unset values values will be // serialized to null - set NullSavingStrategy.DO_NOT_SET explicitly .addStatement( - "$L.set($L, $L, $T.$L)", + "$L.set($L, $L, $T.$L, $L)", entityHelperName, mappedObjectName, rawObjectName, NullSavingStrategy.class, - NullSavingStrategy.DO_NOT_SET); + NullSavingStrategy.DO_NOT_SET, + useLeniency ? "lenient" : false); } else if (type instanceof PropertyType.EntityList) { TypeName rawCollectionType = type.asRawTypeName(); conversionBuilder.addStatement( @@ -506,7 +514,8 @@ private static void convertEntitiesIntoUdts( CodeBlock.of("(($T) $L).getElementType()", ListType.class, currentCqlType), udtTypesBuilder, conversionBuilder, - enclosingClass); + enclosingClass, + useLeniency); conversionBuilder.addStatement("$L.add($L)", rawObjectName, rawElementName).endControlFlow(); } else if (type instanceof PropertyType.EntitySet) { TypeName rawCollectionType = type.asRawTypeName(); @@ -528,7 +537,8 @@ private static void convertEntitiesIntoUdts( CodeBlock.of("(($T) $L).getElementType()", SetType.class, currentCqlType), udtTypesBuilder, conversionBuilder, - enclosingClass); + enclosingClass, + useLeniency); conversionBuilder.addStatement("$L.add($L)", rawObjectName, rawElementName).endControlFlow(); } else if (type instanceof PropertyType.EntityMap) { TypeName rawCollectionType = type.asRawTypeName(); @@ -562,7 +572,8 @@ private static void convertEntitiesIntoUdts( CodeBlock.of("(($T) $L).getKeyType()", MapType.class, currentCqlType), udtTypesBuilder, conversionBuilder, - enclosingClass); + enclosingClass, + useLeniency); } String mappedValueName = CodeBlock.of("$L.getValue()", mappedEntryName).toString(); String rawValueName; @@ -577,7 +588,8 @@ private static void convertEntitiesIntoUdts( CodeBlock.of("(($T) $L).getValueType()", MapType.class, currentCqlType), udtTypesBuilder, conversionBuilder, - enclosingClass); + enclosingClass, + useLeniency); } conversionBuilder .addStatement("$L.put($L, $L)", rawObjectName, rawKeyName, rawValueName) diff --git a/mapper-runtime/src/main/java/com/datastax/dse/driver/internal/mapper/reactive/ReactiveDaoBase.java b/mapper-runtime/src/main/java/com/datastax/dse/driver/internal/mapper/reactive/ReactiveDaoBase.java index 23c21c6f5f7..f5979cd6fb3 100644 --- a/mapper-runtime/src/main/java/com/datastax/dse/driver/internal/mapper/reactive/ReactiveDaoBase.java +++ b/mapper-runtime/src/main/java/com/datastax/dse/driver/internal/mapper/reactive/ReactiveDaoBase.java @@ -35,6 +35,6 @@ protected ReactiveResultSet executeReactive(Statement statement) { protected MappedReactiveResultSet executeReactiveAndMap( Statement statement, EntityHelper entityHelper) { ReactiveResultSet source = executeReactive(statement); - return new DefaultMappedReactiveResultSet<>(source, entityHelper::get); + return new DefaultMappedReactiveResultSet<>(source, row -> entityHelper.get(row, false)); } } diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/Entity.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/Entity.java index a8046f33adc..f358e961846 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/Entity.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/Entity.java @@ -47,8 +47,9 @@ * getDescription}) and has no parameters. The name of the property is obtained by removing * the "get" prefix and decapitalizing ({@code description}), and the type of the property is * the return type of the getter. - *
  • there must be a matching setter method ({@code setDescription}), with a single - * parameter that has the same type as the property (the return type does not matter). + *
  • unless the entity is {@linkplain PropertyStrategy#mutable() immutable}, there must + * be a matching setter method ({@code setDescription}), with a single parameter that has the + * same type as the property (the return type does not matter). * * * There may also be a matching field ({@code description}) that has the same type as the diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/GetEntity.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/GetEntity.java index ff4d5a8805c..0d01b8f373f 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/GetEntity.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/GetEntity.java @@ -102,4 +102,18 @@ */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) -public @interface GetEntity {} +public @interface GetEntity { + + /** + * Whether to tolerate missing columns in the source data structure. + * + *

    If {@code false} (the default), then the source must contain a matching column for every + * property in the entity definition, including computed ones. If such a column is not + * found, an {@link IllegalArgumentException} will be thrown. + * + *

    If {@code true}, the mapper will operate on a best-effort basis and attempt to read all + * entity properties that have a matching column in the source, leaving unmatched properties + * untouched. Beware that this may result in a partially-populated entity instance. + */ + boolean lenient() default false; +} diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SetEntity.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SetEntity.java index 834c549c3b7..818b1272be5 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SetEntity.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/annotations/SetEntity.java @@ -98,4 +98,17 @@ * or {@link NullSavingStrategy#DO_NOT_SET}. */ NullSavingStrategy nullSavingStrategy() default NullSavingStrategy.DO_NOT_SET; + + /** + * Whether to tolerate missing columns in the target data structure. + * + *

    If {@code false} (the default), then the target must contain a matching column for every + * property in the entity definition, except computed ones. If such a column is not + * found, an {@link IllegalArgumentException} will be thrown. + * + *

    If {@code true}, the mapper will operate on a best-effort basis and attempt to write all + * entity properties that have a matching column in the target, leaving unmatched properties + * untouched. Beware that this may result in a partially-populated target. + */ + boolean lenient() default false; } diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/entity/EntityHelper.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/entity/EntityHelper.java index 81f3144d529..c80242b0904 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/entity/EntityHelper.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/api/mapper/entity/EntityHelper.java @@ -49,7 +49,20 @@ public interface EntityHelper { /** * Sets the properties of an entity instance into a target data structure. * - *

    For example: + * @deprecated Use {@link #set(Object, SettableByName, NullSavingStrategy, boolean)} instead. + */ + @NonNull + @Deprecated + > SettableT set( + @NonNull EntityT entity, + @NonNull SettableT target, + @NonNull NullSavingStrategy nullSavingStrategy); + + /** + * Sets the properties of an entity instance into a target data structure. + * + *

    The generated code will attempt to write all entity properties in the target data structure. + * For example: * *

    {@code
        * target = target.set("id", entity.getId(), UUID.class);
    @@ -59,25 +72,50 @@ public interface EntityHelper {
        *
        * The column names are inferred from the naming strategy for this entity.
        *
    +   * 

    The target will typically be one of the built-in driver subtypes: {@link BoundStatement}, + * {@link BoundStatementBuilder} or {@link UdtValue}. Note that the default {@link BoundStatement} + * implementation is immutable, therefore this argument won't be modified in-place: you need to + * use the return value to get the resulting structure. + * + *

    If {@code lenient} is {@code true}, the mapper will operate on a best-effort basis and + * attempt to write all entity properties that have a matching column in the target, leaving + * unmatched properties untouched. Beware that this may result in a partially-populated target. + * + *

    If {@code lenient} is {@code false}, then the target must contain a matching column for + * every property in the entity definition, except computed ones. If such a column is not + * found, an {@link IllegalArgumentException} will be thrown. + * * @param entity the entity that the values will be read from. - * @param target the data structure to fill. This will typically be one of the built-in driver - * subtypes: {@link BoundStatement}, {@link BoundStatementBuilder} or {@link UdtValue}. Note - * that the default {@link BoundStatement} implementation is immutable, therefore this - * argument won't be modified in-place: you need to use the return value to get the resulting - * structure. + * @param target the data structure to fill. + * @param lenient whether to tolerate incomplete targets. * @return the data structure resulting from the assignments. This is useful for immutable target * implementations (see above), otherwise it will be the same as {@code target}. + * @throws IllegalArgumentException if lenient is false and the target does not contain matching + * columns for every entity property. */ @NonNull - > SettableT set( + default > SettableT set( @NonNull EntityT entity, @NonNull SettableT target, - @NonNull NullSavingStrategy nullSavingStrategy); + @NonNull NullSavingStrategy nullSavingStrategy, + boolean lenient) { + return set(entity, target, nullSavingStrategy); + } /** * Gets values from a data structure to fill an entity instance. * - *

    For example: + * @deprecated Use {@link #get(GettableByName, boolean)} instead. + */ + @NonNull + @Deprecated + EntityT get(@NonNull GettableByName source); + + /** + * Gets values from a data structure to fill an entity instance. + * + *

    The generated code will attempt to read all entity properties from the source data + * structure. For example: * *

    {@code
        * User returnValue = new User();
    @@ -88,14 +126,29 @@ > SettableT set(
        *
        * The column names are inferred from the naming strategy for this entity.
        *
    -   * @param source the data structure to read from. This will typically be one of the built-in
    -   *     driver subtypes: {@link Row} or {@link UdtValue} ({@link BoundStatement} and {@link
    -   *     BoundStatementBuilder} are also possible, although it's less likely that data would be read
    -   *     back from them in this manner).
    +   * 

    The source will typically be one of the built-in driver subtypes: {@link Row} or {@link + * UdtValue} ({@link BoundStatement} and {@link BoundStatementBuilder} are also possible, although + * it's less likely that data would be read back from them in this manner). + * + *

    If {@code lenient} is {@code true}, the mapper will operate on a best-effort basis and + * attempt to read all entity properties that have a matching column in the source, leaving + * unmatched properties untouched. Beware that this may result in a partially-populated entity + * instance. + * + *

    If {@code lenient} is {@code false}, then the source must contain a matching column for + * every property in the entity definition, including computed ones. If such a column is + * not found, an {@link IllegalArgumentException} will be thrown. + * + * @param source the data structure to read from. + * @param lenient whether to tolerate incomplete sources. * @return the resulting entity. + * @throws IllegalArgumentException if lenient is false and the source does not contain matching + * columns for every entity property. */ @NonNull - EntityT get(@NonNull GettableByName source); + default EntityT get(@NonNull GettableByName source, boolean lenient) { + return get(source); + } /** * Builds an insert query for this entity. diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java index 4af39a59b84..a9e5721c398 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java @@ -224,12 +224,12 @@ protected EntityT executeAndMapToSingleEntity( private EntityT asEntity(Row row, EntityHelper entityHelper) { return (row == null - // Special case for INSERT IF NOT EXISTS. If the row did not exists, the query returns + // Special case for INSERT IF NOT EXISTS. If the row did not exist, the query returns // only [applied], we want to return null to indicate there was no previous entity || (row.getColumnDefinitions().size() == 1 && row.getColumnDefinitions().get(0).getName().equals(APPLIED))) ? null - : entityHelper.get(row); + : entityHelper.get(row, false); } protected Optional executeAndMapToOptionalEntity( @@ -239,12 +239,13 @@ protected Optional executeAndMapToOptionalEntity( protected PagingIterable executeAndMapToEntityIterable( Statement statement, EntityHelper entityHelper) { - return execute(statement).map(entityHelper::get); + return execute(statement).map(row -> entityHelper.get(row, false)); } protected Stream executeAndMapToEntityStream( Statement statement, EntityHelper entityHelper) { - return StreamSupport.stream(execute(statement).map(entityHelper::get).spliterator(), false); + return StreamSupport.stream( + execute(statement).map(row -> entityHelper.get(row, false)).spliterator(), false); } protected CompletableFuture executeAsync(Statement statement) { @@ -287,7 +288,7 @@ protected CompletableFuture> executeAsyncAndMapToOpt protected CompletableFuture> executeAsyncAndMapToEntityIterable( Statement statement, EntityHelper entityHelper) { - return executeAsync(statement).thenApply(rs -> rs.map(entityHelper::get)); + return executeAsync(statement).thenApply(rs -> rs.map(row -> entityHelper.get(row, false))); } protected static void throwIfProtocolVersionV3(MapperContext context) { diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/entity/EntityHelperBase.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/entity/EntityHelperBase.java index d1198cff5d4..8be10fc15d8 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/entity/EntityHelperBase.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/entity/EntityHelperBase.java @@ -16,6 +16,13 @@ package com.datastax.oss.driver.internal.mapper.entity; import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.data.AccessibleByName; +import com.datastax.oss.driver.api.core.data.GettableByName; +import com.datastax.oss.driver.api.core.data.SettableByName; +import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata; import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.datastax.oss.driver.api.core.type.DataType; @@ -30,6 +37,7 @@ import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace; import com.datastax.oss.driver.api.mapper.annotations.Entity; import com.datastax.oss.driver.api.mapper.entity.EntityHelper; +import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.internal.core.util.CollectionsUtils; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -76,6 +84,23 @@ public CqlIdentifier getTableId() { return tableId; } + @NonNull + @Override + @Deprecated + public > SettableT set( + @NonNull EntityT entity, + @NonNull SettableT target, + @NonNull NullSavingStrategy nullSavingStrategy) { + return set(entity, target, nullSavingStrategy, false); + } + + @NonNull + @Override + @Deprecated + public EntityT get(@NonNull GettableByName source) { + return get(source, false); + } + public void throwIfKeyspaceMissing() { if (this.getKeyspaceId() == null && !context.getSession().getKeyspace().isPresent()) { throw new MapperException( @@ -201,6 +226,26 @@ public void throwMissingTypesIfNotEmpty( public boolean keyspaceNamePresent( Map keyspaces, CqlIdentifier keyspaceId) { - return keyspaces.keySet().contains(keyspaceId); + return keyspaces.containsKey(keyspaceId); + } + + public boolean hasProperty(AccessibleByName source, String name) { + if (source instanceof Row) { + return ((Row) source).getColumnDefinitions().contains(name); + } else if (source instanceof UdtValue) { + return ((UdtValue) source).getType().contains(name); + } else if (source instanceof BoundStatement) { + return ((BoundStatement) source) + .getPreparedStatement() + .getVariableDefinitions() + .contains(name); + } else if (source instanceof BoundStatementBuilder) { + return ((BoundStatementBuilder) source) + .getPreparedStatement() + .getVariableDefinitions() + .contains(name); + } + // other implementations: assume the property is present + return true; } } diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 1b92cb972d6..c0f6fee32e5 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -15,6 +15,26 @@ involves backwards-incompatible binary changes, users of this library and of the * If your application is using MicroProfile Metrics >= 3.0, then you must upgrade to driver 4.12 or higher, as previous versions of `java-driver-metrics-microprofile` will not work. +#### Mapper `@GetEntity` and `@SetEntity` methods can now be lenient + +Thanks to [JAVA-2935](https://datastax-oss.atlassian.net/browse/JAVA-2935), `@GetEntity` and +`@SetEntity` methods now have a new `lenient` attribute. + +If the attribute is `false` (the default value), then the source row or the target statement must +contain a matching column for every property in the entity definition, *including computed ones*. If +such a column is not found, an error will be thrown. This corresponds to the mapper's current +behavior prior to the introduction of the new attribute. + +If the new attribute is explicitly set to `true` however, the mapper will operate on a best-effort +basis and attempt to read or write all entity properties that have a matching column in the source +row or in the target statement, *leaving unmatched properties untouched*. + +This new, lenient behavior allows to achieve the equivalent of driver 3.x +[lenient mapping](https://docs.datastax.com/en/developer/java-driver/3.10/manual/object_mapper/using/#manual-mapping). + +Read the manual pages on [@GetEntity](../manual/mapper/daos/getentity) methods and +[@SetEntity](../manual/mapper/daos/setentity) methods for more details and examples of lenient mode. + ### 4.11.0 #### Native protocol V5 is now production-ready From c6cab7303f88ffd285ede10330effeb6bc7a5f74 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 12:02:58 +0200 Subject: [PATCH 146/395] JAVA-2932: Make DefaultDriverConfigLoader.close() resilient to terminated executors (#1557) --- changelog/README.md | 1 + .../config/typesafe/DefaultDriverConfigLoader.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 52d34c9b02a..8fbb4385f16 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.2 (in progress) +- [bug] JAVA-2932: Make DefaultDriverConfigLoader.close() resilient to terminated executors - [bug] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method - [bug] JAVA-2947: Release buffer after decoding multi-slice frame - [bug] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java index 9f87960adc6..2c679e3f520 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/DefaultDriverConfigLoader.java @@ -39,6 +39,7 @@ import java.time.Duration; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import net.jcip.annotations.ThreadSafe; @@ -235,8 +236,14 @@ public Supplier getConfigSupplier() { @Override public void close() { SingleThreaded singleThreaded = this.singleThreaded; - if (singleThreaded != null) { - RunOrSchedule.on(singleThreaded.adminExecutor, singleThreaded::close); + if (singleThreaded != null && !singleThreaded.adminExecutor.terminationFuture().isDone()) { + try { + RunOrSchedule.on(singleThreaded.adminExecutor, singleThreaded::close); + } catch (RejectedExecutionException e) { + // Checking the future is racy, there is still a tiny window that could get us here. + // We can safely ignore this error because, if the execution is rejected, the periodic + // reload task, if any, has been already cancelled. + } } } From 262cc4f99dcf127ff24bf347131f19e5a173a62d Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 12:00:57 +0200 Subject: [PATCH 147/395] Fix raw usage of generic class --- .../core/util/concurrent/ScheduledTaskCapturingEventLoop.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/ScheduledTaskCapturingEventLoop.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/ScheduledTaskCapturingEventLoop.java index 79f56fb3215..540ee86a8a8 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/ScheduledTaskCapturingEventLoop.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/ScheduledTaskCapturingEventLoop.java @@ -47,7 +47,7 @@ @SuppressWarnings("FunctionalInterfaceClash") // does not matter for test code public class ScheduledTaskCapturingEventLoop extends DefaultEventLoop { - private final BlockingQueue capturedTasks = new ArrayBlockingQueue<>(100); + private final BlockingQueue> capturedTasks = new ArrayBlockingQueue<>(100); public ScheduledTaskCapturingEventLoop(EventLoopGroup parent) { super(parent); From 29d11d9cf9f61cafed508ad0e8e0904f35b23121 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 12:01:41 +0200 Subject: [PATCH 148/395] Replace mention of "cluster" by "session" in DriverConfigLoader.close() --- .../datastax/oss/driver/api/core/config/DriverConfigLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java index fcc7ea41689..6bbd8d2c96e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DriverConfigLoader.java @@ -376,7 +376,7 @@ static DriverConfigLoader compose( boolean supportsReloading(); /** - * Called when the cluster closes. This is a good time to release any external resource, for + * Called when the session closes. This is a good time to release any external resource, for * example cancel a scheduled reloading task. */ @Override From 8b77ec2745f7d6297c3e1a32a1a6d5614e5dcc48 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 12 Jun 2021 19:03:13 +0200 Subject: [PATCH 149/395] Wait until index is built --- .../mapper/SelectCustomWhereClauseIT.java | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java index e86ff9f2d5b..3afcc03e451 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.mapper; import static com.datastax.oss.driver.assertions.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static org.junit.Assume.assumeFalse; import com.datastax.oss.driver.api.core.CqlIdentifier; @@ -36,8 +37,8 @@ import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; +import java.time.Duration; import java.util.concurrent.CompletionStage; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -73,29 +74,35 @@ public static void setup() { InventoryMapper inventoryMapper = new SelectCustomWhereClauseIT_InventoryMapperBuilder(session).build(); dao = inventoryMapper.productDao(SESSION_RULE.keyspace()); - } - - @Before - public void insertData() { dao.save(FLAMETHROWER); dao.save(MP3_DOWNLOAD); } @Test public void should_select_with_custom_clause() { - PagingIterable products = dao.findByDescription("%mp3%"); - assertThat(products.one()).isEqualTo(MP3_DOWNLOAD); - assertThat(products.iterator()).isExhausted(); + await() + .atMost(Duration.ofMinutes(1)) + .untilAsserted( + () -> { + PagingIterable products = dao.findByDescription("%mp3%"); + assertThat(products.one()).isEqualTo(MP3_DOWNLOAD); + assertThat(products.iterator()).isExhausted(); + }); } @Test public void should_select_with_custom_clause_asynchronously() { - MappedAsyncPagingIterable iterable = - CompletableFutures.getUninterruptibly( - dao.findByDescriptionAsync("%mp3%").toCompletableFuture()); - assertThat(iterable.one()).isEqualTo(MP3_DOWNLOAD); - assertThat(iterable.currentPage().iterator()).isExhausted(); - assertThat(iterable.hasMorePages()).isFalse(); + await() + .atMost(Duration.ofMinutes(1)) + .untilAsserted( + () -> { + MappedAsyncPagingIterable iterable = + CompletableFutures.getUninterruptibly( + dao.findByDescriptionAsync("%mp3%").toCompletableFuture()); + assertThat(iterable.one()).isEqualTo(MP3_DOWNLOAD); + assertThat(iterable.currentPage().iterator()).isExhausted(); + assertThat(iterable.hasMorePages()).isFalse(); + }); } @Mapper From 3fde31eb8cea42ab4e342eb1ab555fe56c413ac8 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 14:23:43 +0200 Subject: [PATCH 150/395] Prepare changelog for 4.11.2 release --- changelog/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 8fbb4385f16..48c5d442249 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,7 +2,7 @@ -### 4.11.2 (in progress) +### 4.11.2 - [bug] JAVA-2932: Make DefaultDriverConfigLoader.close() resilient to terminated executors - [bug] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method From 130ab655b4a45bae3dd6683bdb5427c88de48850 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 14:28:10 +0200 Subject: [PATCH 151/395] [maven-release-plugin] prepare release 4.11.2 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 970e0cbcd26..5bcee4affef 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-core-shaded - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-mapper-processor - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-mapper-runtime - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-query-builder - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-test-infra - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-metrics-micrometer - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss java-driver-metrics-microprofile - 4.11.2-SNAPSHOT + 4.11.2 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 7e204b6726c..d35d412a916 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 44aeda012e4..d8edccc65fc 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 73891ec302b..71e5a37e8f5 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 08ee8f717e0..2a0f99f9105 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.2-SNAPSHOT + 4.11.2 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 8097819fde0..ea602b1b840 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 99f35eb1986..a2851350807 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index f8e8bcd6c06..7de0fe21945 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index d5072187884..944500c52cd 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 169d04622e7..bab6a2a2a3e 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 58820c4ba3d..195b4308551 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index a306b90a655..656861cb5d8 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.11.2 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 8eac5a3ffbd..c3b65acf3ab 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 5cf30a2048b..b5a3d724789 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2-SNAPSHOT + 4.11.2 java-driver-test-infra bundle From 0d97dfd8d9e43721b41939e3bdbcd0a696d381c4 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 14:28:20 +0200 Subject: [PATCH 152/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 5bcee4affef..f107d8bb9b5 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.11.2 + 4.11.3-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index d35d412a916..2dc72176cce 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index d8edccc65fc..9fcd5642208 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 71e5a37e8f5..b7e5bd41edb 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 2a0f99f9105..c2b3a76164f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.2 + 4.11.3-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index ea602b1b840..d306d17b365 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index a2851350807..a8d29a6154f 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 7de0fe21945..dbfda81840e 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 944500c52cd..0c4c444bf17 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index bab6a2a2a3e..e5946089c8f 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 195b4308551..bb094c7c158 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 656861cb5d8..6f40a34b9a8 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.11.2 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index c3b65acf3ab..601a40ee9d8 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index b5a3d724789..2b23d248516 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.2 + 4.11.3-SNAPSHOT java-driver-test-infra bundle From 7070f075cc3a1c245f3ad891aa164977925b1e33 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 15:21:11 +0200 Subject: [PATCH 153/395] Update version in docs --- README.md | 4 +- changelog/README.md | 13 +++- manual/case_sensitivity/README.md | 10 +-- manual/core/README.md | 26 +++---- manual/core/address_resolution/README.md | 2 +- manual/core/async/README.md | 2 +- manual/core/authentication/README.md | 16 ++-- manual/core/bom/README.md | 4 +- manual/core/configuration/README.md | 20 ++--- manual/core/control_connection/README.md | 2 +- manual/core/custom_codecs/README.md | 74 +++++++++---------- manual/core/detachable_types/README.md | 14 ++-- manual/core/dse/geotypes/README.md | 6 +- manual/core/dse/graph/README.md | 4 +- manual/core/dse/graph/fluent/README.md | 4 +- .../core/dse/graph/fluent/explicit/README.md | 12 +-- manual/core/dse/graph/results/README.md | 6 +- manual/core/dse/graph/script/README.md | 6 +- manual/core/idempotence/README.md | 4 +- manual/core/integration/README.md | 7 +- manual/core/load_balancing/README.md | 12 +-- manual/core/metadata/README.md | 6 +- manual/core/metadata/node/README.md | 28 +++---- manual/core/metadata/schema/README.md | 20 ++--- manual/core/metadata/token/README.md | 4 +- manual/core/native_protocol/README.md | 6 +- manual/core/non_blocking/README.md | 44 +++++------ manual/core/paging/README.md | 12 +-- manual/core/performance/README.md | 10 +-- manual/core/pooling/README.md | 2 +- manual/core/query_timestamps/README.md | 4 +- manual/core/reactive/README.md | 24 +++--- manual/core/reconnection/README.md | 8 +- manual/core/request_tracker/README.md | 4 +- manual/core/retries/README.md | 36 ++++----- manual/core/speculative_execution/README.md | 2 +- manual/core/ssl/README.md | 6 +- manual/core/statements/README.md | 8 +- manual/core/statements/batch/README.md | 6 +- .../statements/per_query_keyspace/README.md | 2 +- manual/core/statements/prepared/README.md | 8 +- manual/core/statements/simple/README.md | 6 +- manual/core/temporal_types/README.md | 8 +- manual/core/throttling/README.md | 6 +- manual/core/tracing/README.md | 12 +-- manual/core/tuples/README.md | 4 +- manual/core/udts/README.md | 4 +- manual/developer/common/concurrency/README.md | 4 +- manual/mapper/config/kotlin/README.md | 2 +- manual/mapper/config/record/README.md | 2 +- manual/mapper/config/scala/README.md | 2 +- manual/mapper/daos/README.md | 8 +- manual/mapper/daos/custom_types/README.md | 10 +-- manual/mapper/daos/delete/README.md | 18 ++--- manual/mapper/daos/getentity/README.md | 18 ++--- manual/mapper/daos/increment/README.md | 12 +-- manual/mapper/daos/insert/README.md | 14 ++-- manual/mapper/daos/null_saving/README.md | 10 +-- manual/mapper/daos/query/README.md | 24 +++--- manual/mapper/daos/queryprovider/README.md | 16 ++-- manual/mapper/daos/select/README.md | 28 +++---- manual/mapper/daos/setentity/README.md | 10 +-- .../daos/statement_attributes/README.md | 2 +- manual/mapper/daos/update/README.md | 12 +-- manual/mapper/entities/README.md | 36 ++++----- manual/mapper/mapper/README.md | 10 +-- manual/osgi/README.md | 6 +- manual/query_builder/README.md | 10 +-- manual/query_builder/condition/README.md | 2 +- manual/query_builder/delete/README.md | 4 +- manual/query_builder/insert/README.md | 2 +- manual/query_builder/relation/README.md | 4 +- manual/query_builder/schema/README.md | 2 +- .../query_builder/schema/aggregate/README.md | 2 +- .../query_builder/schema/function/README.md | 2 +- manual/query_builder/schema/index/README.md | 2 +- .../query_builder/schema/keyspace/README.md | 2 +- .../schema/materialized_view/README.md | 4 +- manual/query_builder/schema/table/README.md | 6 +- manual/query_builder/schema/type/README.md | 2 +- manual/query_builder/select/README.md | 4 +- manual/query_builder/term/README.md | 4 +- manual/query_builder/truncate/README.md | 2 +- manual/query_builder/update/README.md | 4 +- 84 files changed, 421 insertions(+), 409 deletions(-) diff --git a/README.md b/README.md index 5a137ac947a..19b09697684 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.11.0](https://github.com/datastax/java-driver/tree/4.11.0).* +[4.12.0](https://github.com/datastax/java-driver/tree/4.12.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol @@ -82,7 +82,7 @@ See the [upgrade guide](upgrade_guide/) for details. * [Changelog] * [FAQ] -[API docs]: https://docs.datastax.com/en/drivers/java/4.11 +[API docs]: https://docs.datastax.com/en/drivers/java/4.12 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [@dsJavaDriver]: https://twitter.com/dsJavaDriver diff --git a/changelog/README.md b/changelog/README.md index 49a04dffa06..c301cfe4a54 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,11 +2,22 @@ -### 4.12.0 (in progress) +### 4.12.0 - [improvement] JAVA-2935: Make GetEntity and SetEntity methods resilient to incomplete data - [improvement] JAVA-2944: Upgrade MicroProfile Metrics to 3.0 +Merged from 4.11.x: + +- [bug] JAVA-2932: Make DefaultDriverConfigLoader.close() resilient to terminated executors +- [bug] JAVA-2945: Reinstate InternalDriverContext.getNodeFilter method +- [bug] JAVA-2947: Release buffer after decoding multi-slice frame +- [bug] JAVA-2946: Make MapperResultProducerService instances be located with user-provided class loader +- [bug] JAVA-2942: GraphStatement.setConsistencyLevel() is not effective +- [bug] JAVA-2941: Cannot add a single static column with the alter table API +- [bug] JAVA-2943: Prevent session leak with wrong keyspace name +- [bug] JAVA-2938: OverloadedException message is misleading + ### 4.11.2 - [bug] JAVA-2932: Make DefaultDriverConfigLoader.close() resilient to terminated executors diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index 4138ae42d89..7e85cd2d091 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -106,11 +106,11 @@ For "consuming" methods, string overloads are also provided for convenience, for * in other cases, the string is always assumed to be in CQL form, and converted on the fly with `CqlIdentifier.fromCql`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html -[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html +[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/AccessibleByName.html ### Good practices diff --git a/manual/core/README.md b/manual/core/README.md index 6a316245c50..4648e53f4bd 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -314,18 +314,18 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { } ``` -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html -[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html#builder-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/TupleValue.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html -[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- -[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html#builder-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/TupleValue.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html +[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- +[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index 61954f38c43..2407f589f78 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -124,7 +124,7 @@ Cassandra node: domain name of the target instance. Then it performs a forward DNS lookup of the domain name; the EC2 DNS does the private/public switch automatically based on location). -[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html +[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html [cassandra.yaml]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html [rpc_address]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html?scroll=configCassandra_yaml__rpc_address diff --git a/manual/core/async/README.md b/manual/core/async/README.md index aeaaa53e5ce..50005ffb7a8 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -207,4 +207,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 8b3a2a61099..9a11ad0a8e0 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -215,12 +215,12 @@ session.execute(statement); [SASL]: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer -[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/auth/AuthProvider.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html -[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html -[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html -[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html -[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- -[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- -[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- +[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/auth/AuthProvider.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html +[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html +[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html +[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- +[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- +[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- [reference.conf]: ../configuration/reference/ \ No newline at end of file diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index 690ed1ce3cc..357bd6c58b7 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.11.0 + 4.12.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.11.0 + 4.12.0 diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index 55e7bf6d91c..656115b18a3 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -520,16 +520,16 @@ config.getDefaultProfile().getString(MyCustomOption.ADMIN_EMAIL); config.getDefaultProfile().getInt(MyCustomOption.AWESOMENESS_FACTOR); ``` -[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfig.html -[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html -[DriverOption]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverOption.html -[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html -[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- -[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- -[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- -[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- +[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfig.html +[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html +[DriverOption]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverOption.html +[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html +[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- +[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- +[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- +[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- [Typesafe Config]: https://github.com/typesafehub/config [config standard behavior]: https://github.com/typesafehub/config#standard-behavior diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index a1d9a345cee..2cb88323cd1 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -23,4 +23,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index b90ea31ad10..3413f9d5934 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -660,13 +660,13 @@ private static String formatRow(Row row) { } ``` -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html -[format()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- -[parse()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- -[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html -[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html +[format()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- +[parse()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- +[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html +[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- [Enums]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html [Enum.name()]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#name-- @@ -680,36 +680,36 @@ private static String formatRow(Row row) { [java.time.LocalDateTime]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html [java.time.ZoneId]: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html -[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html -[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY -[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY -[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY -[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY -[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY -[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY -[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY -[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY -[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC -[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- -[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM -[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC -[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC -[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC -[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED -[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- -[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- -[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- -[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- - -[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB -[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP +[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html +[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY +[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY +[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY +[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY +[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY +[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY +[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY +[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY +[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC +[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- +[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM +[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC +[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC +[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC +[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED +[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- +[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- +[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- +[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- + +[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB +[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index 737dd1b41c9..927cb3e372d 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -137,13 +137,13 @@ Even then, the defaults used by detached objects might be good enough for you: Otherwise, just make sure you reattach objects any time you deserialize them or create them from scratch. -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT -[DataType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/DataType.html -[Detachable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/detach/Detachable.html -[Session]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html -[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html -[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT +[DataType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/DataType.html +[Detachable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/detach/Detachable.html +[Session]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html +[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html +[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html [Java serialization]: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html [protocol specifications]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index f6329a2fd5a..ad081b246c4 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -166,9 +166,9 @@ All geospatial types interoperate with three standard formats: [ESRI]: https://github.com/Esri/geometry-api-java -[LineString]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/data/geometry/LineString.html -[Point]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/data/geometry/Point.html -[Polygon]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/data/geometry/Polygon.html +[LineString]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/data/geometry/LineString.html +[Point]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/data/geometry/Point.html +[Polygon]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/data/geometry/Polygon.html [Well-known text]: https://en.wikipedia.org/wiki/Well-known_text [Well-known binary]: https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index d18b1959c93..aa8409db760 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -74,8 +74,8 @@ fluent API returns Apache TinkerPop™ types directly. [Apache TinkerPop™]: http://tinkerpop.apache.org/ -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html -[GraphSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/GraphSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html +[GraphSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/GraphSession.html [DSE developer guide]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphTOC.html [Gremlin]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dseGraphAbout.html#dseGraphAbout__what-is-cql diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index 090ccc248fb..15784ba833a 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -109,8 +109,8 @@ All the DSE predicates are available on the driver side: .values("name"); ``` -[Search]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/predicates/Search.html -[Geo]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/predicates/Geo.html +[Search]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/predicates/Search.html +[Geo]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/predicates/Geo.html [Apache TinkerPop™]: http://tinkerpop.apache.org/ [TinkerPop DSL]: http://tinkerpop.apache.org/docs/current/reference/#dsl diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index 533a257d218..bef059fe467 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -105,9 +105,9 @@ added in a future version. See also the [parent page](../) for topics common to all fluent traversals. -[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html -[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html -[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- -[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- +[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html +[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html +[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- +[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index 7c9356b19b6..1d3891b0994 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -137,8 +137,8 @@ If a type doesn't have a corresponding `asXxx()` method, use the variant that ta UUID uuid = graphNode.as(UUID.class); ``` -[GraphNode]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/GraphNode.html -[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/GraphResultSet.html -[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html +[GraphNode]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/GraphNode.html +[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/GraphResultSet.html +[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html [DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index f26ab58bdf4..8bdf9799b63 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -101,6 +101,6 @@ Note however that some types of queries can only be performed through the script * configuration; * DSE graph schema queries. -[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html -[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html +[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index 1bb97d92c64..f10bcae0721 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -60,5 +60,5 @@ assert bs.isIdempotent(); The query builder tries to infer idempotence automatically; refer to [its manual](../../query_builder/idempotence/) for more details. -[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- -[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- +[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- +[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 6fab5af9003..6a41fa4751d 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -543,6 +543,7 @@ Here are the recommended TinkerPop versions for each driver version: + @@ -641,6 +642,6 @@ The remaining core driver dependencies are the only ones that are truly mandator [guava]: https://github.com/google/guava/issues/2721 [annotation processing]: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#sthref65 -[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- -[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[Uuids]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html +[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- +[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[Uuids]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/uuid/Uuids.html diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index fdac96702fe..d74546d6e99 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -426,12 +426,12 @@ Then it uses the "closest" distance for any given node. For example: * policy1 changes its suggestion to IGNORED. node1 is set to REMOTE; * policy1 changes its suggestion to REMOTE. node1 stays at REMOTE. -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html -[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html +[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html [BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java -[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- -[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- -[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- -[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html +[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- +[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- +[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index 8b5557dd994..117c802c966 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -56,6 +56,6 @@ new keyspace in the schema metadata before the token metadata was updated. Schema and node state events are debounced. This allows you to control how often the metadata gets refreshed. See the [Performance](../performance/#debouncing) page for more details. -[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- -[Metadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- +[Metadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html +[Node]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 715b26df732..fb5780a30ff 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -112,17 +112,17 @@ beyond the scope of this document; if you're interested, study the `TopologyMoni the source code. -[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- -[Node]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html -[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- -[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- -[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- -[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- -[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- -[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- -[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- -[NodeState]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/NodeState.html -[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html -[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file +[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- +[Node]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html +[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- +[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- +[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- +[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- +[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- +[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- +[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- +[NodeState]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeState.html +[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html +[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html +[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index 4fb70ac326c..43a3ec1880a 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -307,16 +307,16 @@ unavailable for the excluded keyspaces. If you issue schema-altering requests from the driver (e.g. `session.execute("CREATE TABLE ..")`), take a look at the [Performance](../../performance/#schema-updates) page for a few tips. -[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html -[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html -[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- -[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- -[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- -[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html -[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html -[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html +[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html +[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html +[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- +[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- +[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- +[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html +[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html +[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html [JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 [java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index e3dc6d903c3..db830c64bae 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -169,5 +169,5 @@ on [schema metadata](../schema/). If schema metadata is disabled or filtered, to also be unavailable for the excluded keyspaces. -[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index e2ed651de6d..4d43687f792 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -135,6 +135,6 @@ If you want to see the details of mixed cluster negotiation, enable `DEBUG` leve [protocol spec]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources [driver3]: https://docs.datastax.com/en/developer/java-driver/3.10/manual/native_protocol/ -[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- -[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- -[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- +[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- +[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- +[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index efb068912b2..61a6618f757 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -49,22 +49,22 @@ For example, calling any synchronous method declared in [`SyncCqlSession`], such will block until the result is available. These methods should never be used in non-blocking applications. -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` -[`execute`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all safe for use in non-blocking applications; the statement execution and asynchronous result delivery is guaranteed to never block. -[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html -[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the returned publisher will never block when subscribed to, until the final results are delivered to the subscriber. -[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- There is one exception though: continuous paging queries (a feature specific to DSE) have a special execution model which uses internal locks for coordination. Although such locks are only held for @@ -77,10 +77,10 @@ reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactiv though, continuous paging is extremely efficient and can safely be used in most non-blocking contexts, unless they require strict lock-freedom. -[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html -[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html -[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- -[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- #### Driver lock-free guarantees per session lifecycle phases @@ -110,8 +110,8 @@ Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` should be avoided in non-blocking applications. -[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- -[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- Once the session is initialized, however, the driver is guaranteed to be non-blocking during the session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. @@ -121,8 +121,8 @@ during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseab asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is shut down and lock-freedom enforcement is disabled. -[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html -[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- #### Driver lock-free guarantees for specific components @@ -131,7 +131,7 @@ Certain driver components are not implemented in lock-free algorithms. For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It should not be used if strict lock-freedom is enforced. -[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html The same is valid for both built-in [request throttlers]: @@ -143,7 +143,7 @@ use locks internally, and depending on how many requests are being executed in p contention on these locks can be high: in short, if your application enforces strict lock-freedom, then these components should not be used. -[request throttlers]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html +[request throttlers]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html Other components may be lock-free, *except* for their first invocation. This is the case of the following items: @@ -151,8 +151,8 @@ following items: * All built-in implementations of [`TimestampGenerator`], upon instantiation; * The utility method [`Uuids.timeBased()`]. -[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/time/TimestampGenerator.html -[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- Both components need to access native libraries when they get initialized and this may involve hitting the local filesystem, thus causing the initialization to become a blocking call. @@ -172,7 +172,7 @@ One component, the codec registry, can block when its [`register`] method is cal therefore advised that codecs should be registered during application startup exclusively. See the [custom codecs](../custom_codecs) section for more details about registering codecs. -[`register`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[`register`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- Finally, a few internal components also use locks, but only during session initialization; once the session is ready, they are either discarded, or don't use locks anymore for the rest of the @@ -213,7 +213,7 @@ lock-freedom enforcement tools could report calls to that method, but it was imp these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a non-blocking call and random UUIDs can now be safely generated in non-blocking applications. -[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- [JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 #### Driver lock-free guarantees when reloading the configuration @@ -228,8 +228,8 @@ detectors. If that is the case, it is advised to disable hot-reloading by settin `datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on [configuration](../configuration) for more information. -[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- #### Driver lock-free guarantees when connecting to DSE diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index 288127679a0..7c33aa5b43a 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -253,12 +253,12 @@ protocol page size and the logical page size to the same value. The [driver examples] include two complete web service implementations demonstrating forward-only and offset paging. -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- -[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- -[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/paging/OffsetPager.html -[PagingState]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/PagingState.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- +[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- +[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/paging/OffsetPager.html +[PagingState]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/PagingState.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index 6f6cfb9f2fb..46bd567aa0f 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -345,8 +345,8 @@ possible to reuse the same event loop group for I/O, admin tasks, and even your (the driver's internal code is fully asynchronous so it will never block any thread). The timer is the only one that will have to stay on a separate thread. -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html -[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- -[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html +[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index e6ba907b95f..c57808c692a 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -170,5 +170,5 @@ you experience the issue, here's what to look out for: Try adding more connections per node. Thanks to the driver's hot-reload mechanism, you can do that at runtime and see the effects immediately. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html [CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index c98d1030392..6851fdd7e57 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -187,9 +187,9 @@ Here is the order of precedence of all the methods described so far: 3. otherwise, if the timestamp generator assigned a timestamp, use it; 4. otherwise, let the server assign the timestamp. -[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/time/TimestampGenerator.html [gettimeofday]: http://man7.org/linux/man-pages/man2/settimeofday.2.html [JNR]: https://github.com/jnr/jnr-posix [Lightweight transactions]: https://docs.datastax.com/en/dse/6.0/cql/cql/cql_using/useInsertLWT.html -[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- +[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index c8485c982bd..d70a9bd4094 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -367,18 +367,18 @@ Note that the driver already has a [built-in retry mechanism] that can transpare queries; the above example should be seen as a demonstration of application-level retries, when a more fine-grained control of what should be retried, and how, is required. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html -[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html -[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html -[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- -[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- -[wasApplied]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- -[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- -[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- -[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html +[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html +[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html +[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- +[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- +[wasApplied]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- +[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- +[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- +[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- [built-in retry mechanism]: ../retries/ [request throttling]: ../throttling/ diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index 36b2d55b832..3ec3c8ef3cc 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -84,7 +84,7 @@ Note that the session is not accessible until it is fully ready: the `CqlSession call — or the future returned by `buildAsync()` — will not complete until the connection was established. -[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/context/DriverContext.html -[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html +[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index e959c09dfd7..4aa9fff0404 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -117,5 +117,5 @@ all FROM users WHERE user_id=? [v0=42] com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined column name all ``` -[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/tracker/RequestTracker.html +[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index df8ac5b9003..eb24ead3ad1 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -231,21 +231,21 @@ configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html -[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/DriverTimeoutException.html -[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html -[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/HeartbeatException.html -[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html -[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html -[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html -[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html -[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html -[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryDecision.html -[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryPolicy.html -[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/retry/RetryVerdict.html -[ServerError]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/ServerError.html -[TruncateException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/TruncateException.html -[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html -[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html -[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html +[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/DriverTimeoutException.html +[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html +[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/HeartbeatException.html +[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html +[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html +[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html +[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html +[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html +[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/retry/RetryDecision.html +[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/retry/RetryPolicy.html +[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[ServerError]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ServerError.html +[TruncateException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/TruncateException.html +[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html +[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html +[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index f5ba057d431..6e0e86f8606 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -250,4 +250,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index bac3786c624..d21bf0e7839 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -204,6 +204,6 @@ the box, but with a bit of custom development it is fairly easy to add. See [dsClientToNode]: https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html [pickle]: http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html [JSSE system properties]: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization -[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- -[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- -[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html +[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- +[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- +[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index 2e1dd1aa75f..b8a0621bc1d 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -59,7 +59,7 @@ the [configuration](../configuration/). Namely, these are: idempotent flag, quer consistency levels and page size. We recommended the configuration approach whenever possible (you can create execution profiles to capture common combinations of those options). -[Statement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html -[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/StatementBuilder.html -[execute]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- -[executeAsync]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[Statement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html +[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/StatementBuilder.html +[execute]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[executeAsync]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index df917e33af5..1cb479ce2bc 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -61,8 +61,8 @@ In addition, simple statements with named parameters are currently not supported due to a [protocol limitation][CASSANDRA-10246] that will be fixed in a future version). If you try to execute such a batch, an `IllegalArgumentException` is thrown. -[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BatchStatement.html -[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- -[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BatchStatement.html +[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- [batch_dse]: http://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/useBatch.html [CASSANDRA-10246]: https://issues.apache.org/jira/browse/CASSANDRA-10246 diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index 152816071d2..cd5295805f4 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -124,6 +124,6 @@ SimpleStatement statement = At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we'll probably deprecate `setRoutingKeyspace()`. -[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index afb24ac38ed..e7e7d4007d4 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -330,10 +330,10 @@ With Cassandra 4 and [native protocol](../../native_protocol/) v5, this issue is new version with the response; the driver updates its local cache transparently, and the client can observe the new columns in the result set. -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [CASSANDRA-10786]: https://issues.apache.org/jira/browse/CASSANDRA-10786 [CASSANDRA-10813]: https://issues.apache.org/jira/browse/CASSANDRA-10813 [guava eviction]: https://github.com/google/guava/wiki/CachesExplained#reference-based-eviction -[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- -[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- +[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- +[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index e614885039a..a07fa66126b 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -182,6 +182,6 @@ session.execute( Or you could also use [prepared statements](../prepared/), which don't have this limitation since parameter types are known in advance. -[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SimpleStatement.html -[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- -[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- +[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SimpleStatement.html +[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- +[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index e30f8fca947..cf5273b4e0f 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -146,7 +146,7 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]" ``` -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index 3b5c025032f..eb69b160a99 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -145,6 +145,6 @@ datastax-java-driver { If you enable `throttling.delay`, make sure to also check the associated extra options to correctly size the underlying histograms (`metrics.session.throttling.delay.*`). -[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/RequestThrottlingException.html -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/RequestThrottlingException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index 07d4416efba..7864ac147a1 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -113,9 +113,9 @@ for (TraceEvent event : trace.getEvents()) { If you call `getQueryTrace()` for a statement that didn't have tracing enabled, an exception is thrown. -[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html -[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/QueryTrace.html -[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- -[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- -[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- -[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html +[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/QueryTrace.html +[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- +[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- +[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- +[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index 1662aa3beb7..cfecdf3f8f8 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -139,5 +139,5 @@ BoundStatement bs = [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html -[TupleType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/TupleType.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/TupleValue.html +[TupleType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/TupleType.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/TupleValue.html diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index 8fdd72050a2..90f7bff59ff 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -135,5 +135,5 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index 2ab2ab7db35..c0697d439c8 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -101,8 +101,8 @@ public interface ExecutionInfo { When a public API method is blocking, this is generally clearly stated in its javadocs. -[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index 58e104513de..e016cfec768 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -106,4 +106,4 @@ before compilation: [build.gradle]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/build.gradle [UserDao.kt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/src/main/kotlin/com/datastax/examples/mapper/killrvideo/user/UserDao.kt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index d296439870f..520eeb773b7 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -27,7 +27,7 @@ You need to build with Java 14, and pass the `--enable-preview` flag to both the runtime JVM. See [pom.xml] in the example. -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html [DataStax-Examples/object-mapper-jvm/record]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/record [pom.xml]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/record/pom.xml diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index f5d2e120637..6d2ed670fc8 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -54,4 +54,4 @@ mapper builder. [DataStax-Examples/object-mapper-jvm/scala]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/scala [build.sbt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/scala/build.sbt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index 6bbd1b9f35a..9a15815acb0 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -148,8 +148,8 @@ In this case, any annotations declared in `Dao1` would be chosen over `Dao2`. To control how the hierarchy is scanned, annotate interfaces with [@HierarchyScanStrategy]. -[@Dao]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html [Entity Inheritance]: ../entities/#inheritance diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index 6b8a6707b48..7d39e8b7038 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -236,8 +236,8 @@ flag: With this configuration, if a DAO method declares a non built-in return type, it will be surfaced as a compiler error. -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/MapperContext.html -[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html -[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/MapperContext.html +[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html +[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index 1526079f611..290180038e1 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -151,15 +151,15 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@Delete]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Delete.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@Delete]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Delete.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index e495f964557..63a82e96e14 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -130,15 +130,15 @@ If the return type doesn't match the parameter type (for example [PagingIterable [AsyncResultSet]), the mapper processor will issue a compile-time error. -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[GettableByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/GettableByName.html -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[GettableByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/GettableByName.html +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html [Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index 834bdb752f1..c8680e9b6ab 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -75,12 +75,12 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[@Increment]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Increment.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Increment]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Increment.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/CqlName.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index f7bf250b304..79337a093a9 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -108,13 +108,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Insert]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Insert]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index bf754441703..80be5c17652 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -93,10 +93,10 @@ public interface UserDao extends InventoryDao { } ``` -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[MapperException]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/MapperException.html -[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET -[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[MapperException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/MapperException.html +[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET +[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL [CASSANDRA-7304]: https://issues.apache.org/jira/browse/CASSANDRA-7304 diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index b95b118c48f..bde13b37a41 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -113,18 +113,18 @@ Then: query succeeds or not depends on whether the session that the mapper was built with has a [default keyspace]. -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Query]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Query.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[Row]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/Row.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Query]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Query.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index e1e71bcc608..61e2212079e 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -137,11 +137,11 @@ Here is the full implementation: the desired [PagingIterable][PagingIterable]. -[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html -[providerClass]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- -[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- -[providerMethod]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/MapperContext.html -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/EntityHelper.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html +[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html +[providerClass]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- +[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- +[providerMethod]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/MapperContext.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/EntityHelper.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index 3cb6cc168c5..e9403d913ec 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -155,20 +155,20 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html -[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- -[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- -[groupBy()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- -[limit()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- -[orderBy()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- -[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html +[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- +[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- +[groupBy()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- +[limit()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- +[orderBy()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- +[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index 3d887b34a91..5fc441b9bf8 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -112,8 +112,8 @@ BoundStatement bind(Product product, BoundStatement statement); If you use a void method with [BoundStatement], the mapper processor will issue a compile-time warning. -[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html -[SettableByName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/SettableByName.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/data/UdtValue.html +[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html +[SettableByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/SettableByName.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index 1793c8ac806..4ca17cfbb96 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -60,4 +60,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 44fcdec02c6..8ffa06a1b4c 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -143,13 +143,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Update]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Update.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Update]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Update.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html [Boolean]: https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Boolean.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/ResultSet.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index 35b457f9bb9..41f8a2a2a4f 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -555,22 +555,22 @@ the same level. To control how the class hierarchy is scanned, annotate classes with [@HierarchyScanStrategy]. -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/CqlName.html -[@Dao]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@Entity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Entity.html -[NameConverter]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html -[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html -[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Computed]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Computed.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Select.html -[@Insert]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[@Update]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Update.html -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[@Query]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Query.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@Entity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Entity.html +[NameConverter]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html +[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html +[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Computed]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Computed.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html +[@Insert]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[@Update]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Update.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[@Query]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Query.html [aliases]: http://cassandra.apache.org/doc/latest/cql/dml.html?#aliases -[@Transient]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Transient.html -[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@Transient]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Transient.html +[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index bebb2a62133..032381e39bf 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -230,8 +230,8 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) You can also permanently disable validation of an individual entity by annotating it with `@SchemaHint(targetElement = NONE)`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html -[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html -[@Mapper]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/mapper/annotations/Mapper.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html +[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html +[@Mapper]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Mapper.html diff --git a/manual/osgi/README.md b/manual/osgi/README.md index be8430c31e7..670625960cb 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -138,7 +138,7 @@ starting the driver: [driver configuration]: ../core/configuration [OSGi]:https://www.osgi.org [JNR]: https://github.com/jnr/jnr-posix -[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- [JAVA-1127]:https://datastax-oss.atlassian.net/browse/JAVA-1127 -[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- -[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- +[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- +[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index f4f1c12db73..6f2e6e2afd6 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -212,8 +212,8 @@ For a complete tour of the API, browse the child pages in this manual: * [Terms](term/) * [Idempotence](idempotence/) -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/CqlIdentifier.html -[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html -[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html +[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html +[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index 8a58139085e..3d8682c32cf 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -132,4 +132,4 @@ It is mutually exclusive with column conditions: if you previously specified col the statement, they will be ignored; conversely, adding a column condition cancels a previous IF EXISTS clause. -[Condition]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/condition/Condition.html +[Condition]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/condition/Condition.html diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index 36f0400c43a..0fbcf27ea77 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -141,5 +141,5 @@ deleteFrom("user") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index 3442ed55bab..2d2c66fd526 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -114,4 +114,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index ba55a2c38b8..6e6cb03829e 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -201,5 +201,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Relation]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/relation/Relation.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Relation]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/relation/Relation.html diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index 38fc701d798..b285a68acef 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -44,4 +44,4 @@ element type: * [function](function/) * [aggregate](aggregate/) -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index 78de7419719..a2aea551f47 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -76,4 +76,4 @@ dropAggregate("average").ifExists(); // DROP AGGREGATE IF EXISTS average ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index 5cf564f99eb..f9dfc5d0af8 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -92,4 +92,4 @@ dropFunction("log").ifExists(); // DROP FUNCTION IF EXISTS log ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index 183f4e35fec..8e1ed2d8125 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -99,4 +99,4 @@ dropIndex("my_idx").ifExists(); // DROP INDEX IF EXISTS my_idx ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index 643a1354ac7..b772b9b0d6d 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -83,6 +83,6 @@ dropKeyspace("cycling").ifExists(); // DROP KEYSPACE IF EXISTS cycling ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index 20617636769..54354907a5e 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -85,5 +85,5 @@ dropTable("cyclist_by_age").ifExists(); // DROP MATERIALIZED VIEW IF EXISTS cyclist_by_age ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index b7f923d90cc..12b2577e21c 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -107,6 +107,6 @@ dropTable("cyclist_name").ifExists(); // DROP TABLE IF EXISTS cyclist_name ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html -[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html +[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index f08f3305bcc..fe0791c970d 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -88,4 +88,4 @@ dropTable("address").ifExists(); // DROP TYPE IF EXISTS address ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index 9ed26281765..b0c13bc438f 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -391,5 +391,5 @@ selectFrom("user").all().allowFiltering(); // SELECT * FROM user ALLOW FILTERING ``` -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index ca650d5d196..a0995a4b516 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -105,5 +105,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index b513b6a52ab..88ffcf47de8 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -17,4 +17,4 @@ Truncate truncate2 = truncate(CqlIdentifier.fromCql("mytable")); Note that, at this stage, the query is ready to build. After creating a TRUNCATE query it does not take any values. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index 2069bb54541..4771641e40b 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -251,5 +251,5 @@ update("foo") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Assignment]: https://docs.datastax.com/en/drivers/java/4.11/com/datastax/oss/driver/api/querybuilder/update/Assignment.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Assignment]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/update/Assignment.html From a2b797b420726a183b58e900b4a83bdfe193fd8d Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 15:34:18 +0200 Subject: [PATCH 154/395] [maven-release-plugin] prepare release 4.12.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index f50076bb957..e81b7e2c7e7 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-core-shaded - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-mapper-processor - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-mapper-runtime - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-query-builder - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-test-infra - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-metrics-micrometer - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss java-driver-metrics-microprofile - 4.12.0-SNAPSHOT + 4.12.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 414d305fb2a..4d223d4bbbe 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 5da7d297d88..b7c60b23507 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index cfd4596ddb4..be6ad61af87 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index cf67d0aa406..851eab03e3c 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.12.0-SNAPSHOT + 4.12.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 0c13ec6f589..676b2508547 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 53f2c874759..1aa3e8f46ae 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 1890231c202..aaa0b4194e4 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 3f54eeb3959..7eef3bd5912 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 48782b475c9..39a5d63d129 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index c88c033d4d6..7e0917ca279 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 72e4194db9a..f913367f87f 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.12.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 7fc68474e2c..0475d2c16e2 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index f1000d40618..ac5343f7850 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0-SNAPSHOT + 4.12.0 java-driver-test-infra bundle From e9edbcd1d32504be866229544ee5d139380d5c8b Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 15:34:29 +0200 Subject: [PATCH 155/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index e81b7e2c7e7..e47c97e29e3 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.12.0 + 4.13.0-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 4d223d4bbbe..076dbfa6918 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index b7c60b23507..34d1b7478b6 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index be6ad61af87..2a579b0440a 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 851eab03e3c..b95827307ad 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.12.0 + 4.13.0-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 676b2508547..c5b6cc77594 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 1aa3e8f46ae..cc14f3d2e8b 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index aaa0b4194e4..68d76446bf1 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 7eef3bd5912..8c2755c7c62 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 39a5d63d129..78c04909c55 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 7e0917ca279..12e8b9641dc 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index f913367f87f..5049d6af22e 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.12.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 0475d2c16e2..3ae527917a1 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index ac5343f7850..d29046b4934 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.0 + 4.13.0-SNAPSHOT java-driver-test-infra bundle From 5f3026bbd370152985532042865f42029ff8a871 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Mon, 14 Jun 2021 15:51:25 +0200 Subject: [PATCH 156/395] Minor correction regarding GetEntity/SetEntity leniency --- upgrade_guide/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index c0f6fee32e5..4e0de35703c 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -21,9 +21,9 @@ Thanks to [JAVA-2935](https://datastax-oss.atlassian.net/browse/JAVA-2935), `@Ge `@SetEntity` methods now have a new `lenient` attribute. If the attribute is `false` (the default value), then the source row or the target statement must -contain a matching column for every property in the entity definition, *including computed ones*. If -such a column is not found, an error will be thrown. This corresponds to the mapper's current -behavior prior to the introduction of the new attribute. +contain a matching column for every property in the entity definition. If such a column is not +found, an error will be thrown. This corresponds to the mapper's current behavior prior to the +introduction of the new attribute. If the new attribute is explicitly set to `true` however, the mapper will operate on a best-effort basis and attempt to read or write all entity properties that have a matching column in the source From a92bc7dcf81243ae39cb21e1f2b5b78dac271e24 Mon Sep 17 00:00:00 2001 From: David Garcia Date: Fri, 9 Jul 2021 10:36:38 +0100 Subject: [PATCH 157/395] Fixed CHANGELOG indentation (#1558) --- changelog/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index c301cfe4a54..a517b58557d 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -568,28 +568,28 @@ changelog](https://docs.datastax.com/en/developer/java-driver-dse/latest/changel - [bug] JAVA-1499: Wait for load balancing policy at cluster initialization - [new feature] JAVA-1495: Add prepared statements -## 3.10.2 +### 3.10.2 - [bug] JAVA-2860: Avoid NPE if channel initialization crashes. -## 3.10.1 +### 3.10.1 - [bug] JAVA-2857: Fix NPE when built statements without parameters are logged at TRACE level. - [bug] JAVA-2843: Successfully parse DSE table schema in OSS driver. -## 3.10.0 +### 3.10.0 - [improvement] JAVA-2676: Don't reschedule flusher after empty runs - [new feature] JAVA-2772: Support new protocol v5 message format -## 3.9.0 +### 3.9.0 - [bug] JAVA-2627: Avoid logging error message including stack trace in request handler. - [new feature] JAVA-2706: Add now_in_seconds to protocol v5 query messages. - [improvement] JAVA-2730: Add support for Cassandra® 4.0 table options - [improvement] JAVA-2702: Transient Replication Support for Cassandra® 4.0 -## 3.8.0 +### 3.8.0 - [new feature] JAVA-2356: Support for DataStax Cloud API. - [improvement] JAVA-2483: Allow to provide secure bundle via URL. From edbf967ff5dadd44f4e9b46c7d72293f7a1774a4 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 9 Jul 2021 12:18:41 +0200 Subject: [PATCH 158/395] Increase timeout --- .../driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java index a312d6162bf..b0707f0356f 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/retry/ConsistencyDowngradingRetryPolicyIT.java @@ -284,7 +284,7 @@ public void should_retry_on_same_on_read_timeout_when_enough_responses_but_data_ oneCounter.assertTotalCount(0); // expect 2 messages: RETRY_SAME, then RETHROW - verify(appender, timeout(500).times(2)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(2000).times(2)).doAppend(loggingEventCaptor.capture()); List loggedEvents = loggingEventCaptor.getAllValues(); assertThat(loggedEvents).hasSize(2); assertThat(loggedEvents.get(0).getFormattedMessage()) From 4af33a009d8c7376af53eb0f3f825ed6b83bdb75 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 9 Jul 2021 12:19:11 +0200 Subject: [PATCH 159/395] Use slow profile for DDL queries --- .../api/core/cql/continuous/ContinuousPagingIT.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java index 3ba00e4095b..a0a3aaf3cf5 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java @@ -240,7 +240,9 @@ public void simple_statement_paging_should_be_resilient_to_schema_change() { public void prepared_statement_paging_should_be_resilient_to_schema_change() { CqlSession session = sessionRule.session(); // Create table and prepare select * query against it. - session.execute("CREATE TABLE test_prep (k text PRIMARY KEY, v int)"); + session.execute( + SimpleStatement.newInstance("CREATE TABLE test_prep (k text PRIMARY KEY, v int)") + .setExecutionProfile(SessionUtils.slowProfile(session))); for (int i = 0; i < 100; i++) { session.execute(String.format("INSERT INTO test_prep (k, v) VALUES ('foo', %d)", i)); } @@ -267,7 +269,9 @@ public void prepared_statement_paging_should_be_resilient_to_schema_change() { CqlSession schemaChangeSession = SessionUtils.newSession( ccmRule, session.getKeyspace().orElseThrow(IllegalStateException::new)); - schemaChangeSession.execute("ALTER TABLE test_prep DROP v;"); + schemaChangeSession.execute( + SimpleStatement.newInstance("ALTER TABLE test_prep DROP v;") + .setExecutionProfile(SessionUtils.slowProfile(schemaChangeSession))); while (it.hasNext()) { // Each row should have a value for k, v should still be present, but null since column was // dropped. From 6d537c6c4670bf006ca9c7580f714b8e45375306 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 9 Jul 2021 12:19:35 +0200 Subject: [PATCH 160/395] Test nullity of fields in tearDown method --- .../datastax/oss/driver/core/PeersV2NodeRefreshIT.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java index 089c4d4fa53..52a5b6eef53 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/PeersV2NodeRefreshIT.java @@ -45,8 +45,12 @@ public static void setup() { @AfterClass public static void tearDown() { - cluster.stop(); - peersV2Server.close(); + if (cluster != null) { + cluster.stop(); + } + if (peersV2Server != null) { + peersV2Server.close(); + } } @Test From c4c561f7d154b50fec50be9da3b4ca9c4c34f4e2 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 9 Jul 2021 16:08:15 +0200 Subject: [PATCH 161/395] Remove spurious line breaks from generated code --- .../mapper/processor/dao/DaoDeleteMethodGenerator.java | 5 ++--- .../mapper/processor/dao/DaoIncrementMethodGenerator.java | 5 ++--- .../mapper/processor/dao/DaoInsertMethodGenerator.java | 5 ++--- .../mapper/processor/dao/DaoQueryMethodGenerator.java | 5 ++--- .../mapper/processor/dao/DaoSelectMethodGenerator.java | 5 ++--- .../mapper/processor/dao/DaoUpdateMethodGenerator.java | 5 ++--- .../processor/entity/EntityHelperGetMethodGenerator.java | 1 - .../processor/entity/EntityHelperSetMethodGenerator.java | 2 +- .../processor/util/generation/GeneratedCodePatterns.java | 1 - 9 files changed, 13 insertions(+), 21 deletions(-) diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java index e80ff89eadf..3f141e31e8c 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java @@ -279,9 +279,8 @@ public Optional generate() { } } - createStatementBlock - .add("\n") - .addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); + createStatementBlock.addStatement( + "$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); return crudMethod(createStatementBlock, returnType, helperFieldName); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoIncrementMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoIncrementMethodGenerator.java index 2b064490f0a..0d0c279b809 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoIncrementMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoIncrementMethodGenerator.java @@ -217,9 +217,8 @@ public Optional generate() { context, false); - updateStatementBlock - .add("\n") - .addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); + updateStatementBlock.addStatement( + "$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); return crudMethod(updateStatementBlock, returnType, helperFieldName); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java index 945cfeda370..9ac0fe9260f 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoInsertMethodGenerator.java @@ -176,9 +176,8 @@ public Optional generate() { } } - createStatementBlock - .add("\n") - .addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); + createStatementBlock.addStatement( + "$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); return crudMethod(createStatementBlock, returnType, helperFieldName); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGenerator.java index 6d6ec0fc8a7..d9bb9547c4d 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGenerator.java @@ -125,9 +125,8 @@ public Optional generate() { GeneratedCodePatterns.bindParameters( parameters, createStatementBlock, enclosingClass, context, true); - createStatementBlock - .add("\n") - .addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); + createStatementBlock.addStatement( + "$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); return crudMethod(createStatementBlock, returnType, helperFieldName); } else { diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java index 8c8878b133b..4d0d7457da6 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java @@ -202,9 +202,8 @@ public Optional generate() { } } - createStatementBlock - .add("\n") - .addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); + createStatementBlock.addStatement( + "$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); return crudMethod(createStatementBlock, returnType, helperFieldName); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java index 288778ee9c8..50f99264c40 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoUpdateMethodGenerator.java @@ -187,9 +187,8 @@ public Optional generate() { } } - createStatementBlock - .add("\n") - .addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); + createStatementBlock.addStatement( + "$T boundStatement = boundStatementBuilder.build()", BoundStatement.class); return crudMethod(createStatementBlock, returnType, helperFieldName); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java index f0a84517c63..5e98f1a20b3 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperGetMethodGenerator.java @@ -75,7 +75,6 @@ public Optional generate() { String setterName = property.getSetterName(); String propertyValueName = enclosingClass.getNameIndex().uniqueField("propertyValue"); propertyValueNames.add(propertyValueName); - getBuilder.addCode("\n"); if (type instanceof PropertyType.Simple) { TypeName typeName = ((PropertyType.Simple) type).typeName; String primitiveAccessor = GeneratedCodePatterns.PRIMITIVE_ACCESSORS.get(typeName); diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java index 5e3042c10ac..c102c231698 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/entity/EntityHelperSetMethodGenerator.java @@ -73,7 +73,7 @@ public Optional generate() { enclosingClass, true); } - injectBodyBuilder.add("\n").addStatement("return target"); + injectBodyBuilder.addStatement("return target"); return Optional.of(injectBuilder.addCode(injectBodyBuilder.build()).build()); } } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java index 48574a48721..78d1a02aa03 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/util/generation/GeneratedCodePatterns.java @@ -225,7 +225,6 @@ public static void setValue( CodeBlock.Builder methodBuilder, BindableHandlingSharedCode enclosingClass, boolean useNullSavingStrategy) { - methodBuilder.add("\n"); if (type instanceof PropertyType.Simple) { TypeName typeName = ((PropertyType.Simple) type).typeName; From 18aa11249b7eabdb505f8d4fc4dd49d40e62da63 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 9 Jul 2021 09:52:22 -0500 Subject: [PATCH 162/395] JAVA-2950: Remove reference to Reflection class from DependencyCheck (#1561) Decoupled dependency definition from logic to check for presence of dependencies. This check logic has been moved to two discrete classes, one for regular lookups and one for Graal build-time lookups which has to be a bit more restrictive about what it can use. --- changelog/README.md | 4 + .../type/codec/DseTypeCodecsRegistrar.java | 6 +- .../DseTypeCodecsRegistrarSubstitutions.java | 6 +- .../core/context/DefaultDriverContext.java | 6 +- .../core/metrics/DefaultMetricsFactory.java | 6 +- .../DefaultMetricsFactorySubstitutions.java | 6 +- .../protocol/CompressorSubstitutions.java | 6 +- .../internal/core/protocol/Lz4Compressor.java | 6 +- .../core/protocol/SnappyCompressor.java | 5 +- .../session/BuiltInRequestProcessors.java | 12 ++- ...BuiltInRequestProcessorsSubstitutions.java | 15 ++-- .../core/util/DefaultDependencyChecker.java | 59 ++++++++++++++ .../driver/internal/core/util/Dependency.java | 60 ++++++++++++++ .../internal/core/util/DependencyCheck.java | 79 ------------------- .../core/util/GraalDependencyChecker.java | 60 ++++++++++++++ 15 files changed, 232 insertions(+), 104 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/GraalDependencyChecker.java diff --git a/changelog/README.md b/changelog/README.md index 48c5d442249..778ef17730a 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,10 @@ +### 4.11.3 (in progress) + +- [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck + ### 4.11.2 - [bug] JAVA-2932: Make DefaultDriverConfigLoader.close() resilient to terminated executors diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java index 5075caa68b2..5035e7be095 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrar.java @@ -15,9 +15,11 @@ */ package com.datastax.dse.driver.internal.core.type.codec; +import static com.datastax.oss.driver.internal.core.util.Dependency.ESRI; + import com.datastax.dse.driver.api.core.type.codec.DseTypeCodecs; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,7 +29,7 @@ public class DseTypeCodecsRegistrar { public static void registerDseCodecs(MutableCodecRegistry registry) { registry.register(DseTypeCodecs.DATE_RANGE); - if (DependencyCheck.ESRI.isPresent()) { + if (DefaultDependencyChecker.isPresent(ESRI)) { registry.register(DseTypeCodecs.LINE_STRING, DseTypeCodecs.POINT, DseTypeCodecs.POLYGON); } else { LOG.debug("ESRI was not found on the classpath: geo codecs will not be available"); diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java index 51c4958824d..5464673c373 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/type/codec/DseTypeCodecsRegistrarSubstitutions.java @@ -15,9 +15,11 @@ */ package com.datastax.dse.driver.internal.core.type.codec; +import static com.datastax.oss.driver.internal.core.util.Dependency.ESRI; + import com.datastax.dse.driver.api.core.type.codec.DseTypeCodecs; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.GraalDependencyChecker; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import java.util.function.BooleanSupplier; @@ -37,7 +39,7 @@ public static void registerDseCodecs(MutableCodecRegistry registry) { public static class EsriMissing implements BooleanSupplier { @Override public boolean getAsBoolean() { - return !DependencyCheck.ESRI.isPresent(); + return !GraalDependencyChecker.isPresent(ESRI); } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index e09e5ee3b5c..fc73d47ca8d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -15,6 +15,8 @@ */ package com.datastax.oss.driver.internal.core.context; +import static com.datastax.oss.driver.internal.core.util.Dependency.JACKSON; + import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.internal.core.InsightsClientLifecycleListener; import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; @@ -82,7 +84,7 @@ import com.datastax.oss.driver.internal.core.tracker.NoopRequestTracker; import com.datastax.oss.driver.internal.core.tracker.RequestLogFormatter; import com.datastax.oss.driver.internal.core.type.codec.registry.DefaultCodecRegistry; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; import com.datastax.oss.driver.internal.core.util.Reflection; import com.datastax.oss.driver.internal.core.util.concurrent.CycleDetector; import com.datastax.oss.driver.internal.core.util.concurrent.LazyReference; @@ -655,7 +657,7 @@ protected Optional buildAuthProvider(AuthProvider authProviderFrom } protected List buildLifecycleListeners() { - if (DependencyCheck.JACKSON.isPresent()) { + if (DefaultDependencyChecker.isPresent(JACKSON)) { return Collections.singletonList(new InsightsClientLifecycleListener(this, initStackTrace)); } else { if (config.getDefaultProfile().getBoolean(DseDriverOption.MONITOR_REPORTING_ENABLED)) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java index e6d78d30dc1..2aba13a4e1c 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactory.java @@ -15,10 +15,12 @@ */ package com.datastax.oss.driver.internal.core.metrics; +import static com.datastax.oss.driver.internal.core.util.Dependency.DROPWIZARD; + import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.Metrics; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; import java.util.Optional; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; @@ -33,7 +35,7 @@ public class DefaultMetricsFactory implements MetricsFactory { @SuppressWarnings("unused") public DefaultMetricsFactory(DriverContext context) { - if (DependencyCheck.DROPWIZARD.isPresent()) { + if (DefaultDependencyChecker.isPresent(DROPWIZARD)) { this.delegate = new DropwizardMetricsFactory(context); } else { this.delegate = new NoopMetricsFactory(context); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java index 3965efc8354..4fa3a49a7d0 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DefaultMetricsFactorySubstitutions.java @@ -15,8 +15,10 @@ */ package com.datastax.oss.driver.internal.core.metrics; +import static com.datastax.oss.driver.internal.core.util.Dependency.DROPWIZARD; + import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.GraalDependencyChecker; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; @@ -49,7 +51,7 @@ public static final class DeleteDropwizardMetricsFactory {} public static class DropwizardMissing implements BooleanSupplier { @Override public boolean getAsBoolean() { - return !DependencyCheck.DROPWIZARD.isPresent(); + return !GraalDependencyChecker.isPresent(DROPWIZARD); } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java index c760344940c..889e4e1c137 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java @@ -15,9 +15,11 @@ */ package com.datastax.oss.driver.internal.core.protocol; +import static com.datastax.oss.driver.internal.core.util.Dependency.LZ4; + import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.GraalDependencyChecker; import com.datastax.oss.protocol.internal.Compressor; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; @@ -91,7 +93,7 @@ public static final class DeleteSnappyCompressor {} public static class Lz4Present implements BooleanSupplier { @Override public boolean getAsBoolean() { - return DependencyCheck.LZ4.isPresent(); + return GraalDependencyChecker.isPresent(LZ4); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/Lz4Compressor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/Lz4Compressor.java index e3b2ce1a344..f3bfc2ed84d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/Lz4Compressor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/Lz4Compressor.java @@ -15,8 +15,10 @@ */ package com.datastax.oss.driver.internal.core.protocol; +import static com.datastax.oss.driver.internal.core.util.Dependency.LZ4; + import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import io.netty.buffer.ByteBuf; import java.nio.ByteBuffer; @@ -41,7 +43,7 @@ public Lz4Compressor(DriverContext context) { @VisibleForTesting Lz4Compressor(String sessionName) { - if (DependencyCheck.LZ4.isPresent()) { + if (DefaultDependencyChecker.isPresent(LZ4)) { LZ4Factory lz4Factory = LZ4Factory.fastestInstance(); LOG.info("[{}] Using {}", sessionName, lz4Factory.toString()); this.compressor = lz4Factory.fastCompressor(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SnappyCompressor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SnappyCompressor.java index fbfd3eff9b2..229a044f1a0 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SnappyCompressor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/SnappyCompressor.java @@ -16,7 +16,8 @@ package com.datastax.oss.driver.internal.core.protocol; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; +import com.datastax.oss.driver.internal.core.util.Dependency; import io.netty.buffer.ByteBuf; import java.io.IOException; import java.nio.ByteBuffer; @@ -34,7 +35,7 @@ public class SnappyCompressor extends ByteBufCompressor { public SnappyCompressor(@SuppressWarnings("unused") DriverContext context) { - if (!DependencyCheck.SNAPPY.isPresent()) { + if (!DefaultDependencyChecker.isPresent(Dependency.SNAPPY)) { throw new IllegalStateException( "Could not find the Snappy library on the classpath " + "(the driver declares it as an optional dependency, " diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java index a4690847838..e502714f1b2 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java @@ -15,6 +15,9 @@ */ package com.datastax.oss.driver.internal.core.session; +import static com.datastax.oss.driver.internal.core.util.Dependency.REACTIVE_STREAMS; +import static com.datastax.oss.driver.internal.core.util.Dependency.TINKERPOP; + import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousCqlRequestAsyncProcessor; import com.datastax.dse.driver.internal.core.cql.continuous.ContinuousCqlRequestSyncProcessor; import com.datastax.dse.driver.internal.core.cql.continuous.reactive.ContinuousCqlRequestReactiveProcessor; @@ -28,7 +31,7 @@ import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; import com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor; import com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; @@ -41,18 +44,19 @@ public class BuiltInRequestProcessors { public static List> createDefaultProcessors(DefaultDriverContext context) { List> processors = new ArrayList<>(); addBasicProcessors(processors); - if (DependencyCheck.TINKERPOP.isPresent()) { + if (DefaultDependencyChecker.isPresent(TINKERPOP)) { addGraphProcessors(context, processors); } else { LOG.debug("Tinkerpop was not found on the classpath: graph extensions will not be available"); } - if (DependencyCheck.REACTIVE_STREAMS.isPresent()) { + if (DefaultDependencyChecker.isPresent(REACTIVE_STREAMS)) { addReactiveProcessors(processors); } else { LOG.debug( "Reactive Streams was not found on the classpath: reactive extensions will not be available"); } - if (DependencyCheck.REACTIVE_STREAMS.isPresent() && DependencyCheck.TINKERPOP.isPresent()) { + if (DefaultDependencyChecker.isPresent(REACTIVE_STREAMS) + && DefaultDependencyChecker.isPresent(TINKERPOP)) { addGraphReactiveProcessors(context, processors); } return processors; diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java index e0afbb06892..4485caed33d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java @@ -15,8 +15,11 @@ */ package com.datastax.oss.driver.internal.core.session; +import static com.datastax.oss.driver.internal.core.util.Dependency.REACTIVE_STREAMS; +import static com.datastax.oss.driver.internal.core.util.Dependency.TINKERPOP; + import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; -import com.datastax.oss.driver.internal.core.util.DependencyCheck; +import com.datastax.oss.driver.internal.core.util.GraalDependencyChecker; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import java.util.ArrayList; @@ -67,22 +70,24 @@ public static final class BuiltInRequestProcessorsGraphPresentReactiveMissing { public static class GraphMissingReactiveMissing implements BooleanSupplier { @Override public boolean getAsBoolean() { - return !DependencyCheck.TINKERPOP.isPresent() - && !DependencyCheck.REACTIVE_STREAMS.isPresent(); + return !GraalDependencyChecker.isPresent(TINKERPOP) + && !GraalDependencyChecker.isPresent(REACTIVE_STREAMS); } } public static class GraphMissingReactivePresent implements BooleanSupplier { @Override public boolean getAsBoolean() { - return !DependencyCheck.TINKERPOP.isPresent() && DependencyCheck.REACTIVE_STREAMS.isPresent(); + return !GraalDependencyChecker.isPresent(TINKERPOP) + && GraalDependencyChecker.isPresent(REACTIVE_STREAMS); } } public static class GraphPresentReactiveMissing implements BooleanSupplier { @Override public boolean getAsBoolean() { - return DependencyCheck.TINKERPOP.isPresent() && !DependencyCheck.REACTIVE_STREAMS.isPresent(); + return GraalDependencyChecker.isPresent(TINKERPOP) + && !GraalDependencyChecker.isPresent(REACTIVE_STREAMS); } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java new file mode 100644 index 00000000000..8dfabb66105 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java @@ -0,0 +1,59 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util; + +import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A checker for the presence of various {@link Dependency} instances at runtime. Predicate tests + * for Graal substitutions should NOT use this class; see {@link GraalDependencyChecker} for more + * information. + */ +public class DefaultDependencyChecker { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultDependencyChecker.class); + + private static ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + + /** + * Return true iff we can find all classes for the dependency on the classpath, false otherwise + * + * @param dependency the dependency to search for + * @return true if the dependency is available, false otherwise + */ + public static boolean isPresent(Dependency dependency) { + try { + return CACHE.computeIfAbsent( + dependency, + (dep) -> { + for (String classNameToTest : dependency.classes()) { + // Always use the driver class loader, assuming that the driver classes and + // the dependency classes are either being loaded by the same class loader, + // or – as in OSGi deployments – by two distinct, but compatible class loaders. + if (Reflection.loadClass(null, classNameToTest) == null) { + return false; + } + } + return true; + }); + } catch (Exception e) { + LOG.warn("Unexpected exception when checking for dependency " + dependency, e); + return false; + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java new file mode 100644 index 00000000000..bbefe698d55 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java @@ -0,0 +1,60 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util; + +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; + +/** + * A set of driver optional dependencies and a common mechanism to test the presence of such + * dependencies on the application's classpath. + * + *

    We use the given fully-qualified names of classes to test the presence of the whole dependency + * on the classpath, including its transitive dependencies if applicable. This assumes that if these + * classes are present, then the entire library is present and functional, and vice versa. + * + *

    Note: some of the libraries declared here may be shaded; in these cases the shade plugin will + * replace the package names listed above with names starting with {@code + * com.datastax.oss.driver.shaded.*}, but the presence check would still work as expected. + */ +public enum Dependency { + SNAPPY("org.xerial.snappy.Snappy"), + LZ4("net.jpountz.lz4.LZ4Compressor"), + ESRI("com.esri.core.geometry.ogc.OGCGeometry"), + TINKERPOP( + // gremlin-core + "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal", + // tinkergraph-gremlin + "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0"), + REACTIVE_STREAMS("org.reactivestreams.Publisher"), + JACKSON( + // jackson-core + "com.fasterxml.jackson.core.JsonParser", + // jackson-databind + "com.fasterxml.jackson.databind.ObjectMapper"), + DROPWIZARD("com.codahale.metrics.MetricRegistry"), + ; + + @SuppressWarnings("ImmutableEnumChecker") + private final ImmutableList clzs; + + Dependency(String... classNames) { + clzs = ImmutableList.copyOf(classNames); + } + + public Iterable classes() { + return this.clzs; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java deleted file mode 100644 index 0accb5388a0..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DependencyCheck.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.internal.core.util; - -import com.datastax.oss.driver.shaded.guava.common.base.Supplier; -import com.datastax.oss.driver.shaded.guava.common.base.Suppliers; - -/** - * A set of driver optional dependencies and a common mechanism to test the presence of such - * dependencies on the application's classpath. - */ -public enum DependencyCheck { - SNAPPY("org.xerial.snappy.Snappy"), - LZ4("net.jpountz.lz4.LZ4Compressor"), - ESRI("com.esri.core.geometry.ogc.OGCGeometry"), - TINKERPOP( - // gremlin-core - "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal", - // tinkergraph-gremlin - "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0"), - REACTIVE_STREAMS("org.reactivestreams.Publisher"), - JACKSON( - // jackson-core - "com.fasterxml.jackson.core.JsonParser", - // jackson-databind - "com.fasterxml.jackson.databind.ObjectMapper"), - DROPWIZARD("com.codahale.metrics.MetricRegistry"), - ; - - @SuppressWarnings("ImmutableEnumChecker") - private final Supplier present; - - /** - * We use the given fully-qualified names of classes to test the presence of the whole dependency - * on the classpath, including its transitive dependencies if applicable. This assumes that if - * these classes are present, then the entire library is present and functional, and vice versa. - * - *

    Note: some of the libraries declared here may be shaded; in these cases the shade plugin - * will replace the package names listed above with names starting with {@code - * com.datastax.oss.driver.shaded.*}, but the presence check would still work as expected. - */ - DependencyCheck(String... classNamesToTest) { - this.present = - Suppliers.memoize( - () -> { - for (String classNameToTest : classNamesToTest) { - // Always use the driver class loader, assuming that the driver classes and - // the dependency classes are either being loaded by the same class loader, - // or – as in OSGi deployments – by two distinct, but compatible class loaders. - if (Reflection.loadClass(null, classNameToTest) == null) { - return false; - } - } - return true; - }); - } - - /** - * Checks if the dependency is present on the application's classpath and is loadable. - * - * @return true if the dependency is present and loadable, false otherwise. - */ - public boolean isPresent() { - return present.get(); - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/GraalDependencyChecker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/GraalDependencyChecker.java new file mode 100644 index 00000000000..b91e5716b0d --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/GraalDependencyChecker.java @@ -0,0 +1,60 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * A dependency checker implementation which should be safe to use for build-time checks when + * building Graal native images. This class is similar to {@link DefaultDependencyChecker} but + * doesn't introduce any external dependencies which might complicate the native image build + * process. Expectation is that this will be most prominently used in the various predicate classes + * which determine whether or not Graal substitutions should be used. + */ +public class GraalDependencyChecker { + + private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + + /** + * Return true iff we can find all classes for the dependency on the classpath, false otherwise + * + * @param dependency the dependency to search for + * @return true if the dependency is available, false otherwise + */ + public static boolean isPresent(Dependency dependency) { + try { + return CACHE.computeIfAbsent( + dependency, + (dep) -> { + for (String classNameToTest : dependency.classes()) { + // Note that this lands in a pretty similar spot to + // Reflection.loadClass() with a null class loader + // arg. Major difference here is that we avoid the + // more complex exception handling/logging ops in + // that code. + try { + Class.forName(classNameToTest); + } catch (LinkageError | Exception e) { + return false; + } + } + return true; + }); + } catch (Exception e) { + return false; + } + } +} From 5b39de639d00d7be3e41ab99a328511a32593a5f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 13:26:43 +0200 Subject: [PATCH 163/395] Fix links to RetryPolicy methods in javadocs of driver error classes --- .../driver/api/core/connection/HeartbeatException.java | 4 ++-- .../api/core/servererrors/ReadFailureException.java | 2 +- .../api/core/servererrors/ReadTimeoutException.java | 8 ++++---- .../oss/driver/api/core/servererrors/ServerError.java | 2 +- .../driver/api/core/servererrors/TruncateException.java | 2 +- .../api/core/servererrors/UnavailableException.java | 8 ++++---- .../api/core/servererrors/WriteFailureException.java | 2 +- .../api/core/servererrors/WriteTimeoutException.java | 8 ++++---- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/connection/HeartbeatException.java b/core/src/main/java/com/datastax/oss/driver/api/core/connection/HeartbeatException.java index 183f7c5366e..e74446d2583 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/connection/HeartbeatException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/connection/HeartbeatException.java @@ -28,8 +28,8 @@ * *

    Heartbeat queries are sent automatically on idle connections, to ensure that they are still * alive. If a heartbeat query fails, the connection is closed, and all pending queries are aborted. - * The exception will be passed to {@link RetryPolicy#onRequestAborted(Request, Throwable, int)}, - * which decides what to do next (the default policy retries the query on the next node). + * The exception will be passed to {@link RetryPolicy#onRequestAbortedVerdict(Request, Throwable, + * int)}, which decides what to do next (the default policy retries the query on the next node). */ public class HeartbeatException extends DriverException { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.java index adecf20ccbe..494102b120e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.java @@ -33,7 +33,7 @@ *

    This happens when some of the replicas that were contacted by the coordinator replied with an * error. * - *

    This exception is processed by {@link RetryPolicy#onErrorResponse(Request, + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, * CoordinatorException, int)}, which will decide if it is rethrown directly to the client or if the * request should be retried. If all other tried nodes also fail, this exception will appear in the * {@link AllNodesFailedException} thrown to the client. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java index 1d199a695eb..cac44b4983d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java @@ -27,10 +27,10 @@ /** * A server-side timeout during a read query. * - *

    This exception is processed by {@link RetryPolicy#onReadTimeout(Request, ConsistencyLevel, - * int, int, boolean, int)}, which will decide if it is rethrown directly to the client or if the - * request should be retried. If all other tried nodes also fail, this exception will appear in the - * {@link AllNodesFailedException} thrown to the client. + *

    This exception is processed by {@link RetryPolicy#onReadTimeoutVerdict(Request, + * ConsistencyLevel, int, int, boolean, int)}, which will decide if it is rethrown directly to the + * client or if the request should be retried. If all other tried nodes also fail, this exception + * will appear in the {@link AllNodesFailedException} thrown to the client. */ public class ReadTimeoutException extends QueryConsistencyException { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ServerError.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ServerError.java index 9afe5ea45b3..6cc0c48f984 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ServerError.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ServerError.java @@ -29,7 +29,7 @@ * *

    This should be considered as a server bug and reported as such. * - *

    This exception is processed by {@link RetryPolicy#onErrorResponse(Request, + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, * CoordinatorException, int)}, which will decide if it is rethrown directly to the client or if the * request should be retried. If all other tried nodes also fail, this exception will appear in the * {@link AllNodesFailedException} thrown to the client. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/TruncateException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/TruncateException.java index 12f265e135d..39e79c53182 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/TruncateException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/TruncateException.java @@ -27,7 +27,7 @@ /** * An error during a truncation operation. * - *

    This exception is processed by {@link RetryPolicy#onErrorResponse(Request, + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, * CoordinatorException, int)}, which will decide if it is rethrown directly to the client or if the * request should be retried. If all other tried nodes also fail, this exception will appear in the * {@link AllNodesFailedException} thrown to the client. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/UnavailableException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/UnavailableException.java index 98e119791d8..39df831251a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/UnavailableException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/UnavailableException.java @@ -28,10 +28,10 @@ * Thrown when the coordinator knows there is not enough replicas alive to perform a query with the * requested consistency level. * - *

    This exception is processed by {@link RetryPolicy#onUnavailable(Request, ConsistencyLevel, - * int, int, int)}, which will decide if it is rethrown directly to the client or if the request - * should be retried. If all other tried nodes also fail, this exception will appear in the {@link - * AllNodesFailedException} thrown to the client. + *

    This exception is processed by {@link RetryPolicy#onUnavailableVerdict(Request, + * ConsistencyLevel, int, int, int)}, which will decide if it is rethrown directly to the client or + * if the request should be retried. If all other tried nodes also fail, this exception will appear + * in the {@link AllNodesFailedException} thrown to the client. */ public class UnavailableException extends QueryExecutionException { private final ConsistencyLevel consistencyLevel; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.java index f2589ff1b65..aa3ca7431fc 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.java @@ -33,7 +33,7 @@ *

    This happens when some of the replicas that were contacted by the coordinator replied with an * error. * - *

    This exception is processed by {@link RetryPolicy#onErrorResponse(Request, + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, * CoordinatorException, int)}, which will decide if it is rethrown directly to the client or if the * request should be retried. If all other tried nodes also fail, this exception will appear in the * {@link AllNodesFailedException} thrown to the client. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.java index 600b5e36895..4cf922ce5fe 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.java @@ -28,10 +28,10 @@ /** * A server-side timeout during a write query. * - *

    This exception is processed by {@link RetryPolicy#onWriteTimeout(Request, ConsistencyLevel, - * WriteType, int, int, int)}, which will decide if it is rethrown directly to the client or if the - * request should be retried. If all other tried nodes also fail, this exception will appear in the - * {@link AllNodesFailedException} thrown to the client. + *

    This exception is processed by {@link RetryPolicy#onWriteTimeoutVerdict(Request, + * ConsistencyLevel, WriteType, int, int, int)}, which will decide if it is rethrown directly to the + * client or if the request should be retried. If all other tried nodes also fail, this exception + * will appear in the {@link AllNodesFailedException} thrown to the client. */ public class WriteTimeoutException extends QueryConsistencyException { From 456f173012e557d4536664586b3682adb706dd1f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 14:22:15 +0200 Subject: [PATCH 164/395] Fix compiler warnings in SessionUtils --- .../api/testinfra/session/SessionUtils.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java index 34f5554ccb2..3b9824698fe 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; +import com.datastax.oss.driver.internal.core.loadbalancing.helper.NodeFilterToDistanceEvaluatorAdapter; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; @@ -130,34 +131,34 @@ public static SessionT newSession( return newSession(cassandraResourceRule, keyspace, null, null, null, loader); } - private static SessionBuilder builder( + private static SessionBuilder builder( CassandraResourceRule cassandraResource, CqlIdentifier keyspace, NodeStateListener nodeStateListener, SchemaChangeListener schemaChangeListener, Predicate nodeFilter) { - SessionBuilder builder = - baseBuilder() - .addContactEndPoints(cassandraResource.getContactPoints()) - .withKeyspace(keyspace) - .withNodeStateListener(nodeStateListener) - .withSchemaChangeListener(schemaChangeListener); + SessionBuilder builder = baseBuilder(); + builder + .addContactEndPoints(cassandraResource.getContactPoints()) + .withKeyspace(keyspace) + .withNodeStateListener(nodeStateListener) + .withSchemaChangeListener(schemaChangeListener); if (nodeFilter != null) { - builder = builder.withNodeFilter(nodeFilter); + builder.withNodeDistanceEvaluator(new NodeFilterToDistanceEvaluatorAdapter(nodeFilter)); } return builder; } - @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) + @SuppressWarnings({"TypeParameterUnusedInFormals"}) public static SessionT newSession( CassandraResourceRule cassandraResource, CqlIdentifier keyspace, NodeStateListener nodeStateListener, SchemaChangeListener schemaChangeListener, Predicate nodeFilter) { - SessionBuilder builder = + SessionBuilder builder = builder(cassandraResource, keyspace, nodeStateListener, schemaChangeListener, nodeFilter); - return (SessionT) builder.build(); + return builder.build(); } @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) @@ -168,7 +169,7 @@ public static SessionT newSession( SchemaChangeListener schemaChangeListener, Predicate nodeFilter, DriverConfigLoader loader) { - SessionBuilder builder = + SessionBuilder builder = builder(cassandraResource, keyspace, nodeStateListener, schemaChangeListener, nodeFilter); return (SessionT) builder.withConfigLoader(loader).build(); } From 6368e2e9effee4f118b75b217789dfe8d1d6dc50 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 14:22:29 +0200 Subject: [PATCH 165/395] Move test-infra module down --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f40a34b9a8..2abaa6ce103 100644 --- a/pom.xml +++ b/pom.xml @@ -32,9 +32,9 @@ query-builder mapper-runtime mapper-processor - test-infra metrics/micrometer metrics/microprofile + test-infra integration-tests osgi-tests distribution From 4ee475e4454b5ec0f408dc7313d3b934b40166e5 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 17:06:37 +0200 Subject: [PATCH 166/395] Make field final --- .../oss/driver/internal/core/time/AtomicTimestampGenerator.java | 2 +- .../oss/driver/internal/core/util/DefaultDependencyChecker.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/time/AtomicTimestampGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/time/AtomicTimestampGenerator.java index 28bd5fdf2e4..c6e13716c54 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/time/AtomicTimestampGenerator.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/time/AtomicTimestampGenerator.java @@ -46,7 +46,7 @@ @ThreadSafe public class AtomicTimestampGenerator extends MonotonicTimestampGenerator { - private AtomicLong lastRef = new AtomicLong(0); + private final AtomicLong lastRef = new AtomicLong(0); public AtomicTimestampGenerator(DriverContext context) { super(context); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java index 8dfabb66105..755c4a1252a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/DefaultDependencyChecker.java @@ -28,7 +28,7 @@ public class DefaultDependencyChecker { private static final Logger LOG = LoggerFactory.getLogger(DefaultDependencyChecker.class); - private static ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); /** * Return true iff we can find all classes for the dependency on the classpath, false otherwise From 0606b495c3088dddeec4d213e6603214f7b184c5 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 18:15:10 +0200 Subject: [PATCH 167/395] JAVA-2949: Provide mapper support for CompletionStage> (#1563) --- changelog/README.md | 1 + .../oss/driver/mapper/QueryReturnTypesIT.java | 11 ++++++++++ .../datastax/oss/driver/mapper/SelectIT.java | 17 ++++++++++++++++ manual/mapper/daos/select/README.md | 5 +++++ .../dao/DaoSelectMethodGenerator.java | 2 ++ .../dao/DefaultDaoReturnTypeKind.java | 20 +++++++++++++++++++ .../dao/DefaultDaoReturnTypeParser.java | 1 + .../dao/DaoQueryMethodGeneratorTest.java | 8 +++++--- .../dao/DaoSelectMethodGeneratorTest.java | 4 ++-- .../oss/driver/internal/mapper/DaoBase.java | 8 ++++++++ 10 files changed, 72 insertions(+), 5 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 778ef17730a..8f994136575 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.11.3 (in progress) +- [bug] JAVA-2949: Provide mapper support for CompletionStage> - [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck ### 4.11.2 diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java index 8002bf19f6a..990b38ac2e1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/QueryReturnTypesIT.java @@ -47,6 +47,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import org.junit.Before; import org.junit.BeforeClass; @@ -239,6 +240,13 @@ public void should_execute_async_query_and_map_to_iterable() { assertThat(iterable.hasMorePages()).isFalse(); } + @Test + public void should_execute_query_and_map_to_stream_async() + throws ExecutionException, InterruptedException { + CompletableFuture> stream = dao.findByIdAsStreamAsync(1); + assertThat(stream.get()).hasSize(10); + } + @Dao @DefaultNullSavingStrategy(NullSavingStrategy.SET_TO_NULL) public interface TestDao { @@ -300,6 +308,9 @@ public interface TestDao { @Query("SELECT * FROM ${qualifiedTableId} WHERE id = :id") CompletableFuture> findByIdAsync(int id); + + @Query("SELECT * FROM ${qualifiedTableId} WHERE id = :id") + CompletableFuture> findByIdAsStreamAsync(int id); } @Entity diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java index 2dda4b7e63a..ccd98fad15a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectIT.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.MappedAsyncPagingIterable; import com.datastax.oss.driver.api.core.PagingIterable; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.mapper.annotations.Dao; @@ -100,11 +101,21 @@ public void should_select_all() { assertThat(dao.all().all()).hasSize(2); } + @Test + public void should_select_all_async() { + assertThat(CompletableFutures.getUninterruptibly(dao.allAsync()).currentPage()).hasSize(2); + } + @Test public void should_select_all_stream() { assertThat(dao.stream()).hasSize(2); } + @Test + public void should_select_all_stream_async() { + assertThat(CompletableFutures.getUninterruptibly(dao.streamAsync())).hasSize(2); + } + @Test public void should_select_by_primary_key_asynchronously() { assertThat(CompletableFutures.getUninterruptibly(dao.findByIdAsync(FLAMETHROWER.getId()))) @@ -211,9 +222,15 @@ public interface ProductDao { @Select PagingIterable all(); + @Select + CompletionStage> allAsync(); + @Select Stream stream(); + @Select + CompletionStage> streamAsync(); + @Select Optional findOptionalById(UUID productId); diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index 3cb6cc168c5..4900c67387c 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -135,6 +135,11 @@ In all cases, the method can return: @Select(customWhereClause = "description LIKE :searchString") CompletionStage> findByDescriptionAsync(String searchString); ``` + + For streams, even if the initial query is executed asynchronously, traversing the returned + stream may block the traversing thread. Blocking calls can indeed be required as more results + are fetched from the server in the background. For this reason, _the usage of + `CompletionStage>` cannot be considered as a fully asynchronous execution method_. * a [MappedReactiveResultSet] of the entity class. diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java index 4d0d7457da6..70b24add090 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java @@ -20,6 +20,7 @@ import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_ASYNC_PAGING_ITERABLE; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_ENTITY; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_OPTIONAL_ENTITY; +import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_STREAM; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.MAPPED_REACTIVE_RESULT_SET; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.OPTIONAL_ENTITY; import static com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.PAGING_ITERABLE; @@ -71,6 +72,7 @@ protected Set getSupportedReturnTypes() { PAGING_ITERABLE, STREAM, FUTURE_OF_ASYNC_PAGING_ITERABLE, + FUTURE_OF_STREAM, MAPPED_REACTIVE_RESULT_SET, CUSTOM); } diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java index 41c841cd2e7..a4f111bd9ce 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeKind.java @@ -475,6 +475,26 @@ public CodeBlock wrapWithErrorHandling( return innerBlock; } }, + + FUTURE_OF_STREAM { + @Override + public void addExecuteStatement( + CodeBlock.Builder methodBuilder, + String helperFieldName, + ExecutableElement methodElement, + Map typeParameters) { + methodBuilder.addStatement( + "return executeAsyncAndMapToEntityStream(boundStatement, $L)", helperFieldName); + } + + @Override + public CodeBlock wrapWithErrorHandling( + CodeBlock innerBlock, + ExecutableElement methodElement, + Map typeParameters) { + return wrapWithErrorHandling(innerBlock, FAILED_FUTURE); + } + }, ; @Override diff --git a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java index 5d7c18c63cf..786d7d4b830 100644 --- a/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java +++ b/mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DefaultDaoReturnTypeParser.java @@ -101,6 +101,7 @@ public class DefaultDaoReturnTypeParser implements DaoReturnTypeParser { .put( MappedAsyncPagingIterable.class, DefaultDaoReturnTypeKind.FUTURE_OF_ASYNC_PAGING_ITERABLE) + .put(Stream.class, DefaultDaoReturnTypeKind.FUTURE_OF_STREAM) .build(); protected final ProcessorContext context; diff --git a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java index ea0f28badce..bda92a40b48 100644 --- a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java +++ b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoQueryMethodGeneratorTest.java @@ -43,9 +43,11 @@ public static Object[][] invalidSignatures() { { "Invalid return type: Query methods must return one of [VOID, BOOLEAN, LONG, ROW, " + "ENTITY, OPTIONAL_ENTITY, RESULT_SET, BOUND_STATEMENT, PAGING_ITERABLE, FUTURE_OF_VOID, " - + "FUTURE_OF_BOOLEAN, FUTURE_OF_LONG, FUTURE_OF_ROW, FUTURE_OF_ENTITY, " - + "FUTURE_OF_OPTIONAL_ENTITY, FUTURE_OF_ASYNC_RESULT_SET, " - + "FUTURE_OF_ASYNC_PAGING_ITERABLE, REACTIVE_RESULT_SET, MAPPED_REACTIVE_RESULT_SET, STREAM]", + + "FUTURE_OF_BOOLEAN, FUTURE_OF_LONG, FUTURE_OF_ROW, " + + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, " + + "FUTURE_OF_ASYNC_RESULT_SET, FUTURE_OF_ASYNC_PAGING_ITERABLE, " + + "REACTIVE_RESULT_SET, MAPPED_REACTIVE_RESULT_SET, " + + "STREAM, FUTURE_OF_STREAM]", MethodSpec.methodBuilder("select") .addAnnotation( AnnotationSpec.builder(Query.class) diff --git a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java index c133d19e41a..4f9307f121c 100644 --- a/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java +++ b/mapper-processor/src/test/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGeneratorTest.java @@ -42,7 +42,7 @@ public static Object[][] invalidSignatures() { { "Invalid return type: Select methods must return one of [ENTITY, OPTIONAL_ENTITY, " + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, STREAM, " - + "FUTURE_OF_ASYNC_PAGING_ITERABLE, MAPPED_REACTIVE_RESULT_SET]", + + "FUTURE_OF_ASYNC_PAGING_ITERABLE, FUTURE_OF_STREAM, MAPPED_REACTIVE_RESULT_SET]", MethodSpec.methodBuilder("select") .addAnnotation(Select.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) @@ -52,7 +52,7 @@ public static Object[][] invalidSignatures() { { "Invalid return type: Select methods must return one of [ENTITY, OPTIONAL_ENTITY, " + "FUTURE_OF_ENTITY, FUTURE_OF_OPTIONAL_ENTITY, PAGING_ITERABLE, STREAM, " - + "FUTURE_OF_ASYNC_PAGING_ITERABLE, MAPPED_REACTIVE_RESULT_SET]", + + "FUTURE_OF_ASYNC_PAGING_ITERABLE, FUTURE_OF_STREAM, MAPPED_REACTIVE_RESULT_SET]", MethodSpec.methodBuilder("select") .addAnnotation(Select.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) diff --git a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java index 4af39a59b84..862d31b0b3d 100644 --- a/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java +++ b/mapper-runtime/src/main/java/com/datastax/oss/driver/internal/mapper/DaoBase.java @@ -35,6 +35,7 @@ import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.cql.ResultSets; import com.datastax.oss.protocol.internal.ProtocolConstants; import java.time.Duration; import java.util.Optional; @@ -290,6 +291,13 @@ CompletableFuture> executeAsyncAndMapToEntity return executeAsync(statement).thenApply(rs -> rs.map(entityHelper::get)); } + protected CompletableFuture> executeAsyncAndMapToEntityStream( + Statement statement, EntityHelper entityHelper) { + return executeAsync(statement) + .thenApply(ResultSets::newInstance) + .thenApply(rs -> StreamSupport.stream(rs.map(entityHelper::get).spliterator(), false)); + } + protected static void throwIfProtocolVersionV3(MapperContext context) { if (isProtocolVersionV3(context)) { throw new MapperException( From 4da0ccb1b8f715e4392bce78b00aab0bdcf82420 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 18:16:46 +0200 Subject: [PATCH 168/395] Switch tests to Cassandra 4.0 by default (#1566) * Switch CCM to Cassandra 4.0 by default * Add a few startup tweaks for C* 3+ and 4+ --- .../driver/core/cql/PreparedStatementIT.java | 4 +- .../oss/driver/core/metadata/SchemaIT.java | 18 +++++- .../src/test/resources/logback-test.xml | 2 +- .../driver/api/testinfra/ccm/CcmBridge.java | 62 +++++++++---------- .../DefaultCcmBridgeBuilderCustomizer.java | 8 +++ 5 files changed, 58 insertions(+), 36 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index 1e7e91084ba..1b07edb53af 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -279,7 +279,9 @@ public void should_fail_to_reprepare_if_query_becomes_invalid() { Throwable t = catchThrowable(() -> session.execute(ps.bind())); // Then - assertThat(t).isInstanceOf(InvalidQueryException.class).hasMessage("Undefined column name d"); + assertThat(t) + .isInstanceOf(InvalidQueryException.class) + .hasMessageContaining("Undefined column name d"); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index dc915e25c77..1e2803c7ef4 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -226,7 +226,8 @@ public void should_get_virtual_metadata() { assertThat(tm).isNotNull(); assertThat(tm.getName().toString()).isEqualTo("sstable_tasks"); assertThat(tm.isVirtual()).isTrue(); - assertThat(tm.getColumns().size()).isEqualTo(7); + // DSE 6.8+ reports 7 columns, Cassandra 4+ reports 8 columns + assertThat(tm.getColumns().size()).isGreaterThanOrEqualTo(7); assertThat(tm.getIndexes().size()).isEqualTo(0); assertThat(tm.getPartitionKey().size()).isEqualTo(1); assertThat(tm.getPartitionKey().get(0).getName().toString()).isEqualTo("keyspace_name"); @@ -235,11 +236,24 @@ public void should_get_virtual_metadata() { assertThat(tm.getOptions().size()).isEqualTo(0); assertThat(tm.getKeyspace()).isEqualTo(kmd.getName()); assertThat(tm.describe(true)) - .isEqualTo( + .isIn( + // DSE 6.8+ + "/* VIRTUAL TABLE system_views.sstable_tasks (\n" + + " keyspace_name text,\n" + + " table_name text,\n" + + " task_id uuid,\n" + + " kind text,\n" + + " progress bigint,\n" + + " total bigint,\n" + + " unit text,\n" + + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" + + "); */", + // Cassandra 4.0 "/* VIRTUAL TABLE system_views.sstable_tasks (\n" + " keyspace_name text,\n" + " table_name text,\n" + " task_id uuid,\n" + + " completion_ratio double,\n" + " kind text,\n" + " progress bigint,\n" + " total bigint,\n" diff --git a/integration-tests/src/test/resources/logback-test.xml b/integration-tests/src/test/resources/logback-test.xml index 36dd79c1040..b3668ff68b0 100644 --- a/integration-tests/src/test/resources/logback-test.xml +++ b/integration-tests/src/test/resources/logback-test.xml @@ -29,7 +29,7 @@ - + diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java index c41aa0b278f..cef9e13c4b6 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java @@ -49,28 +49,10 @@ public class CcmBridge implements AutoCloseable { - private static final Logger logger = LoggerFactory.getLogger(CcmBridge.class); - - private final int[] nodes; - - private final Path configDirectory; - - private final AtomicBoolean started = new AtomicBoolean(); - - private final AtomicBoolean created = new AtomicBoolean(); - - private final String ipPrefix; - - private final Map cassandraConfiguration; - private final Map dseConfiguration; - private final List rawDseYaml; - private final List createOptions; - private final List dseWorkloads; - - private final String jvmArgs; + private static final Logger LOG = LoggerFactory.getLogger(CcmBridge.class); public static final Version VERSION = - Objects.requireNonNull(Version.parse(System.getProperty("ccm.version", "3.11.0"))); + Objects.requireNonNull(Version.parse(System.getProperty("ccm.version", "4.0.0"))); public static final String INSTALL_DIRECTORY = System.getProperty("ccm.directory"); @@ -126,6 +108,26 @@ public class CcmBridge implements AutoCloseable { private static final Version V3_0_15 = Version.parse("3.0.15"); private static final Version V2_1_19 = Version.parse("2.1.19"); + static { + if (DSE_ENABLEMENT) { + LOG.info("CCM Bridge configured with DSE version {}", VERSION); + } else { + LOG.info("CCM Bridge configured with Apache Cassandra version {}", VERSION); + } + } + + private final int[] nodes; + private final Path configDirectory; + private final AtomicBoolean started = new AtomicBoolean(); + private final AtomicBoolean created = new AtomicBoolean(); + private final String ipPrefix; + private final Map cassandraConfiguration; + private final Map dseConfiguration; + private final List rawDseYaml; + private final List createOptions; + private final List dseWorkloads; + private final String jvmArgs; + private CcmBridge( Path configDirectory, int[] nodes, @@ -141,10 +143,7 @@ private CcmBridge( // Hack to ensure that the default DC is always called 'dc1': pass a list ('-nX:0') even if // there is only one DC (with '-nX', CCM configures `SimpleSnitch`, which hard-codes the name // to 'datacenter1') - int[] tmp = new int[2]; - tmp[0] = nodes[0]; - tmp[1] = 0; - this.nodes = tmp; + this.nodes = new int[] {nodes[0], 0}; } else { this.nodes = nodes; } @@ -351,9 +350,9 @@ private void executeCheckLogError() { private void execute(CommandLine cli, boolean forceErrorLogging) { if (forceErrorLogging) { - logger.error("Executing: " + cli); + LOG.error("Executing: " + cli); } else { - logger.debug("Executing: " + cli); + LOG.debug("Executing: " + cli); } ExecuteWatchdog watchDog = new ExecuteWatchdog(TimeUnit.MINUTES.toMillis(10)); try (LogOutputStream outStream = @@ -361,9 +360,9 @@ private void execute(CommandLine cli, boolean forceErrorLogging) { @Override protected void processLine(String line, int logLevel) { if (forceErrorLogging) { - logger.error("ccmout> {}", line); + LOG.error("ccmout> {}", line); } else { - logger.debug("ccmout> {}", line); + LOG.debug("ccmout> {}", line); } } }; @@ -371,7 +370,7 @@ protected void processLine(String line, int logLevel) { new LogOutputStream() { @Override protected void processLine(String line, int logLevel) { - logger.error("ccmerr> {}", line); + LOG.error("ccmerr> {}", line); } }) { Executor executor = new DefaultExecutor(); @@ -381,8 +380,7 @@ protected void processLine(String line, int logLevel) { int retValue = executor.execute(cli); if (retValue != 0) { - logger.error( - "Non-zero exit code ({}) returned from executing ccm command: {}", retValue, cli); + LOG.error("Non-zero exit code ({}) returned from executing ccm command: {}", retValue, cli); } } catch (IOException ex) { if (watchDog.killedProcess()) { @@ -413,7 +411,7 @@ private static File createTempStore(String storePath) { f.deleteOnExit(); Resources.copy(CcmBridge.class.getResource(storePath), os); } catch (IOException e) { - logger.warn("Failure to write keystore, SSL-enabled servers may fail to start.", e); + LOG.warn("Failure to write keystore, SSL-enabled servers may fail to start.", e); } return f; } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java index 8dfe6e99b6e..96a0ac5fdce 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java @@ -17,6 +17,8 @@ import com.datastax.oss.driver.api.core.Version; +/** @see CcmRule */ +@SuppressWarnings("unused") public class DefaultCcmBridgeBuilderCustomizer { public static CcmBridge.Builder configureBuilder(CcmBridge.Builder builder) { @@ -25,6 +27,12 @@ public static CcmBridge.Builder configureBuilder(CcmBridge.Builder builder) { builder.withCassandraConfiguration("enable_materialized_views", true); builder.withCassandraConfiguration("enable_sasi_indexes", true); } + if (CcmBridge.VERSION.nextStable().compareTo(Version.V3_0_0) >= 0) { + builder.withJvmArgs("-Dcassandra.superuser_setup_delay_ms=0"); + builder.withJvmArgs("-Dcassandra.skip_wait_for_gossip_to_settle=0"); + builder.withCassandraConfiguration("num_tokens", "1"); + builder.withCassandraConfiguration("initial_token", "0"); + } return builder; } } From 5642d4df822e56386cfbe7579284d8db1168d002 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 18:29:19 +0200 Subject: [PATCH 169/395] Update changelog with 4.13.0 --- changelog/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 18e34c8591c..dba51c891ab 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,13 @@ +### 4.13.0 (in progress) + +Merged from 4.12.x: + +- [bug] JAVA-2949: Provide mapper support for CompletionStage> +- [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck + ### 4.12.1 (in progress) Merged from 4.11.x: From f08db2ef5fcc70b3486bd0b9ad74e9356a1be7bc Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 18:49:33 +0200 Subject: [PATCH 170/395] JAVA-2951: Accept multiple node state listeners, schema change listeners and request trackers (#1565) --- changelog/README.md | 2 + .../api/core/config/DefaultDriverOption.java | 30 ++ .../api/core/config/OngoingConfigOptions.java | 10 + .../driver/api/core/config/OptionsMap.java | 3 - .../api/core/config/TypedDriverOption.java | 43 +- .../loadbalancing/LoadBalancingPolicy.java | 26 +- .../api/core/metadata/NodeStateListener.java | 8 +- .../metadata/schema/SchemaChangeListener.java | 5 +- .../core/session/ProgrammaticArguments.java | 63 +++ .../api/core/session/SessionBuilder.java | 76 ++- .../api/core/tracker/RequestTracker.java | 6 +- .../core/context/DefaultDriverContext.java | 162 +++++-- .../DefaultLoadBalancingPolicy.java | 9 +- .../MultiplexingNodeStateListener.java | 125 +++++ .../core/metadata/NoopNodeStateListener.java | 21 +- .../MultiplexingSchemaChangeListener.java | 209 ++++++++ .../schema/NoopSchemaChangeListener.java | 21 +- .../tracker/MultiplexingRequestTracker.java | 122 +++-- .../core/tracker/NoopRequestTracker.java | 20 +- .../internal/core/tracker/RequestLogger.java | 4 +- .../driver/internal/core/util/Reflection.java | 85 +++- core/src/main/resources/reference.conf | 66 +-- ...ringLoadBalancingPolicyDcFailoverTest.java | 10 - ...erringLoadBalancingPolicyDistanceTest.java | 10 - ...nferringLoadBalancingPolicyEventsTest.java | 10 - ...cInferringLoadBalancingPolicyInitTest.java | 10 - ...aultLoadBalancingPolicyDcFailoverTest.java | 10 - ...efaultLoadBalancingPolicyDistanceTest.java | 10 - .../DefaultLoadBalancingPolicyEventsTest.java | 10 - .../DefaultLoadBalancingPolicyInitTest.java | 10 - ...faultLoadBalancingPolicyQueryPlanTest.java | 2 - ...LoadBalancingPolicyRequestTrackerTest.java | 2 - .../MultiplexingNodeStateListenerTest.java | 194 ++++++++ .../MultiplexingSchemaChangeListenerTest.java | 450 ++++++++++++++++++ .../MultiplexingRequestTrackerTest.java | 211 ++++++++ .../core/config/DriverConfigValidationIT.java | 43 +- .../oss/driver/core/session/ListenersIT.java | 151 +++++- .../driver/core/tracker/RequestLoggerIT.java | 19 +- manual/core/metadata/node/README.md | 25 +- manual/core/metadata/schema/README.md | 22 +- manual/core/request_tracker/README.md | 30 +- upgrade_guide/README.md | 63 +++ 42 files changed, 2053 insertions(+), 355 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListener.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListener.java rename core/src/main/java/com/datastax/{dse => oss}/driver/internal/core/tracker/MultiplexingRequestTracker.java (53%) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListenerTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListenerTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTrackerTest.java diff --git a/changelog/README.md b/changelog/README.md index dba51c891ab..ed90fea7c97 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,8 @@ ### 4.13.0 (in progress) +- [improvement] JAVA-2951: Accept multiple node state listeners, schema change listeners and request trackers + Merged from 4.12.x: - [bug] JAVA-2949: Provide mapper support for CompletionStage> diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 3d2fde238e9..b2fba21d6a3 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -296,7 +296,10 @@ public enum DefaultDriverOption implements DriverOption { * The class of a session-wide component that tracks the outcome of requests. * *

    Value-type: {@link String} + * + * @deprecated Use {@link #REQUEST_TRACKER_CLASSES} instead. */ + @Deprecated REQUEST_TRACKER_CLASS("advanced.request-tracker.class"), /** * Whether to log successful requests. @@ -388,14 +391,20 @@ public enum DefaultDriverOption implements DriverOption { * The class of a session-wide component that listens for node state changes. * *

    Value-type: {@link String} + * + * @deprecated Use {@link #METADATA_NODE_STATE_LISTENER_CLASSES} instead. */ + @Deprecated METADATA_NODE_STATE_LISTENER_CLASS("advanced.node-state-listener.class"), /** * The class of a session-wide component that listens for schema changes. * *

    Value-type: {@link String} + * + * @deprecated Use {@link #METADATA_SCHEMA_CHANGE_LISTENER_CLASSES} instead. */ + @Deprecated METADATA_SCHEMA_CHANGE_LISTENER_CLASS("advanced.schema-change-listener.class"), /** @@ -909,6 +918,27 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: boolean */ PREPARED_CACHE_WEAK_VALUES("advanced.prepared-statements.prepared-cache.weak-values"), + + /** + * The classes of session-wide components that track the outcome of requests. + * + *

    Value-type: List of {@link String} + */ + REQUEST_TRACKER_CLASSES("advanced.request-tracker.classes"), + + /** + * The classes of session-wide components that listen for node state changes. + * + *

    Value-type: List of {@link String} + */ + METADATA_NODE_STATE_LISTENER_CLASSES("advanced.node-state-listener.classes"), + + /** + * The classes of session-wide components that listen for schema changes. + * + *

    Value-type: List of {@link String} + */ + METADATA_SCHEMA_CHANGE_LISTENER_CLASSES("advanced.schema-change-listener.classes"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OngoingConfigOptions.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OngoingConfigOptions.java index 0345150d770..62b76a9d39e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OngoingConfigOptions.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OngoingConfigOptions.java @@ -19,6 +19,7 @@ import java.time.Duration; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** An object where config options can be set programmatically. */ public interface OngoingConfigOptions> { @@ -59,6 +60,15 @@ default SelfT withClass(@NonNull DriverOption option, @NonNull Class value) { return withString(option, value.getName()); } + /** + * Note that this is just a shortcut to call {@link #withStringList(DriverOption, List)} with + * class names obtained from {@link Class#getName()}. + */ + @NonNull + default SelfT withClassList(@NonNull DriverOption option, @NonNull List> values) { + return withStringList(option, values.stream().map(Class::getName).collect(Collectors.toList())); + } + @NonNull SelfT withStringList(@NonNull DriverOption option, @NonNull List value); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 90e66126dd9..8f5aa01592e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -280,10 +280,7 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.TIMESTAMP_GENERATOR_DRIFT_WARNING_THRESHOLD, Duration.ofSeconds(1)); map.put(TypedDriverOption.TIMESTAMP_GENERATOR_DRIFT_WARNING_INTERVAL, Duration.ofSeconds(10)); map.put(TypedDriverOption.TIMESTAMP_GENERATOR_FORCE_JAVA_CLOCK, false); - map.put(TypedDriverOption.REQUEST_TRACKER_CLASS, "NoopRequestTracker"); map.put(TypedDriverOption.REQUEST_THROTTLER_CLASS, "PassThroughRequestThrottler"); - map.put(TypedDriverOption.METADATA_NODE_STATE_LISTENER_CLASS, "NoopNodeStateListener"); - map.put(TypedDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASS, "NoopSchemaChangeListener"); map.put(TypedDriverOption.ADDRESS_TRANSLATOR_CLASS, "PassThroughAddressTranslator"); map.put(TypedDriverOption.RESOLVE_CONTACT_POINTS, true); map.put(TypedDriverOption.PROTOCOL_MAX_FRAME_LENGTH, 256L * 1024 * 1024); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index 044a7b71de6..bce8f923c77 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -254,9 +254,21 @@ public String toString() { public static final TypedDriverOption TIMESTAMP_GENERATOR_DRIFT_WARNING_INTERVAL = new TypedDriverOption<>( DefaultDriverOption.TIMESTAMP_GENERATOR_DRIFT_WARNING_INTERVAL, GenericType.DURATION); - /** The class of a session-wide component that tracks the outcome of requests. */ + + /** + * The class of a session-wide component that tracks the outcome of requests. + * + * @deprecated Use {@link #REQUEST_TRACKER_CLASSES} instead. + */ + @Deprecated public static final TypedDriverOption REQUEST_TRACKER_CLASS = new TypedDriverOption<>(DefaultDriverOption.REQUEST_TRACKER_CLASS, GenericType.STRING); + + /** The classes of session-wide components that track the outcome of requests. */ + public static final TypedDriverOption> REQUEST_TRACKER_CLASSES = + new TypedDriverOption<>( + DefaultDriverOption.REQUEST_TRACKER_CLASSES, GenericType.listOf(String.class)); + /** Whether to log successful requests. */ public static final TypedDriverOption REQUEST_LOGGER_SUCCESS_ENABLED = new TypedDriverOption<>( @@ -312,14 +324,39 @@ public String toString() { public static final TypedDriverOption REQUEST_THROTTLER_DRAIN_INTERVAL = new TypedDriverOption<>( DefaultDriverOption.REQUEST_THROTTLER_DRAIN_INTERVAL, GenericType.DURATION); - /** The class of a session-wide component that listens for node state changes. */ + + /** + * The class of a session-wide component that listens for node state changes. + * + * @deprecated Use {@link #METADATA_NODE_STATE_LISTENER_CLASSES} instead. + */ + @Deprecated public static final TypedDriverOption METADATA_NODE_STATE_LISTENER_CLASS = new TypedDriverOption<>( DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASS, GenericType.STRING); - /** The class of a session-wide component that listens for schema changes. */ + + /** + * The class of a session-wide component that listens for schema changes. + * + * @deprecated Use {@link #METADATA_SCHEMA_CHANGE_LISTENER_CLASSES} instead. + */ + @Deprecated public static final TypedDriverOption METADATA_SCHEMA_CHANGE_LISTENER_CLASS = new TypedDriverOption<>( DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASS, GenericType.STRING); + + /** The classes of session-wide components that listen for node state changes. */ + public static final TypedDriverOption> METADATA_NODE_STATE_LISTENER_CLASSES = + new TypedDriverOption<>( + DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASSES, + GenericType.listOf(String.class)); + + /** The classes of session-wide components that listen for schema changes. */ + public static final TypedDriverOption> METADATA_SCHEMA_CHANGE_LISTENER_CLASSES = + new TypedDriverOption<>( + DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASSES, + GenericType.listOf(String.class)); + /** * The class of the address translator to use to convert the addresses sent by Cassandra nodes * into ones that the driver uses to connect. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java index 425e11c0c5a..d5663cce42c 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java @@ -19,22 +19,40 @@ import com.datastax.oss.driver.api.core.metadata.NodeState; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.api.core.tracker.RequestTracker; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Map; +import java.util.Optional; import java.util.Queue; import java.util.UUID; /** Decides which Cassandra nodes to contact for each query. */ public interface LoadBalancingPolicy extends AutoCloseable { + /** + * Returns an optional {@link RequestTracker} to be registered with the session. Registering a + * request tracker allows load-balancing policies to track node latencies in order to pick the + * fastest ones. + * + *

    This method is invoked only once during session configuration, and before any other methods + * in this interface. Note that at this point, the driver hasn't connected to any node yet. + * + * @since 4.13.0 + */ + @NonNull + default Optional getRequestTracker() { + return Optional.empty(); + } + /** * Initializes this policy with the nodes discovered during driver initialization. * *

    This method is guaranteed to be called exactly once per instance, and before any other - * method in this class. At this point, the driver has successfully connected to one of the - * contact points, and performed a first refresh of topology information (by default, the contents - * of {@code system.peers}), to discover other nodes in the cluster. + * method in this interface except {@link #getRequestTracker()}. At this point, the driver has + * successfully connected to one of the contact points, and performed a first refresh of topology + * information (by default, the contents of {@code system.peers}), to discover other nodes in the + * cluster. * *

    This method must call {@link DistanceReporter#setDistance(Node, NodeDistance) * distanceReporter.setDistance} for each provided node (otherwise that node will stay at distance @@ -50,7 +68,7 @@ public interface LoadBalancingPolicy extends AutoCloseable { * @param nodes all the nodes that are known to exist in the cluster (regardless of their state) * at the time of invocation. * @param distanceReporter an object that will be used by the policy to signal distance changes. - * Implementations will typically store a this in a field, since new nodes may get {@link + * Implementations will typically store this in a field, since new nodes may get {@link * #onAdd(Node) added} later and will need to have their distance set (or the policy might * change distances dynamically over time). */ diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/metadata/NodeStateListener.java b/core/src/main/java/com/datastax/oss/driver/api/core/metadata/NodeStateListener.java index 3d665a3dc3d..66c5654ddd4 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/metadata/NodeStateListener.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/metadata/NodeStateListener.java @@ -23,8 +23,9 @@ /** * A listener that gets notified when nodes states change. * - *

    An implementation of this interface can be registered in the configuration, or with {@link - * SessionBuilder#withNodeStateListener(NodeStateListener)}. + *

    Implementations of this interface can be registered either via the configuration (see {@code + * reference.conf} in the manual or core driver JAR), or programmatically via {@link + * SessionBuilder#addNodeStateListener(NodeStateListener)}. * *

    Note that the methods defined by this interface will be executed by internal driver threads, * and are therefore expected to have short execution times. If you need to perform long @@ -33,6 +34,9 @@ * *

    If you implement this interface but don't need to implement all the methods, extend {@link * NodeStateListenerBase}. + * + *

    If your implementation of this interface requires access to a fully-initialized session, + * consider wrapping it in a {@link SafeInitNodeStateListener}. */ public interface NodeStateListener extends AutoCloseable { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.java b/core/src/main/java/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.java index bfcd53b8a16..4ea47713df3 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.java @@ -23,8 +23,9 @@ /** * Tracks schema changes. * - *

    An implementation of this interface can be registered in the configuration, or with {@link - * SessionBuilder#withSchemaChangeListener(SchemaChangeListener)}. + *

    Implementations of this interface can be registered either via the configuration (see {@code + * reference.conf} in the manual or core driver JAR), or programmatically via {@link + * SessionBuilder#addSchemaChangeListener(SchemaChangeListener)}. * *

    Note that the methods defined by this interface will be executed by internal driver threads, * and are therefore expected to have short execution times. If you need to perform long diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java index 9e4f034ef00..b8b2bd8b723 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java @@ -25,6 +25,9 @@ import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; import com.datastax.oss.driver.internal.core.loadbalancing.helper.NodeFilterToDistanceEvaluatorAdapter; +import com.datastax.oss.driver.internal.core.metadata.MultiplexingNodeStateListener; +import com.datastax.oss.driver.internal.core.metadata.schema.MultiplexingSchemaChangeListener; +import com.datastax.oss.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import edu.umd.cs.findbugs.annotations.NonNull; @@ -33,6 +36,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.UUID; import java.util.function.Predicate; @@ -217,18 +221,77 @@ public Builder withNodeStateListener(@Nullable NodeStateListener nodeStateListen return this; } + @NonNull + public Builder addNodeStateListener(@NonNull NodeStateListener nodeStateListener) { + Objects.requireNonNull(nodeStateListener, "nodeStateListener cannot be null"); + if (this.nodeStateListener == null) { + this.nodeStateListener = nodeStateListener; + } else { + NodeStateListener previousListener = this.nodeStateListener; + if (previousListener instanceof MultiplexingNodeStateListener) { + ((MultiplexingNodeStateListener) previousListener).register(nodeStateListener); + } else { + MultiplexingNodeStateListener multiplexingNodeStateListener = + new MultiplexingNodeStateListener(); + multiplexingNodeStateListener.register(previousListener); + multiplexingNodeStateListener.register(nodeStateListener); + this.nodeStateListener = multiplexingNodeStateListener; + } + } + return this; + } + @NonNull public Builder withSchemaChangeListener(@Nullable SchemaChangeListener schemaChangeListener) { this.schemaChangeListener = schemaChangeListener; return this; } + @NonNull + public Builder addSchemaChangeListener(@NonNull SchemaChangeListener schemaChangeListener) { + Objects.requireNonNull(schemaChangeListener, "schemaChangeListener cannot be null"); + if (this.schemaChangeListener == null) { + this.schemaChangeListener = schemaChangeListener; + } else { + SchemaChangeListener previousListener = this.schemaChangeListener; + if (previousListener instanceof MultiplexingSchemaChangeListener) { + ((MultiplexingSchemaChangeListener) previousListener).register(schemaChangeListener); + } else { + MultiplexingSchemaChangeListener multiplexingSchemaChangeListener = + new MultiplexingSchemaChangeListener(); + multiplexingSchemaChangeListener.register(previousListener); + multiplexingSchemaChangeListener.register(schemaChangeListener); + this.schemaChangeListener = multiplexingSchemaChangeListener; + } + } + return this; + } + @NonNull public Builder withRequestTracker(@Nullable RequestTracker requestTracker) { this.requestTracker = requestTracker; return this; } + @NonNull + public Builder addRequestTracker(@NonNull RequestTracker requestTracker) { + Objects.requireNonNull(requestTracker, "requestTracker cannot be null"); + if (this.requestTracker == null) { + this.requestTracker = requestTracker; + } else { + RequestTracker previousTracker = this.requestTracker; + if (previousTracker instanceof MultiplexingRequestTracker) { + ((MultiplexingRequestTracker) previousTracker).register(requestTracker); + } else { + MultiplexingRequestTracker multiplexingRequestTracker = new MultiplexingRequestTracker(); + multiplexingRequestTracker.register(previousTracker); + multiplexingRequestTracker.register(requestTracker); + this.requestTracker = multiplexingRequestTracker; + } + } + return this; + } + @NonNull public Builder withLocalDatacenter( @NonNull String profileName, @NonNull String localDatacenter) { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index 990044b66c9..02070063d3b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -220,8 +220,11 @@ public SelfT addTypeCodecs(@NonNull TypeCodec... typeCodecs) { /** * Registers a node state listener to use with the session. * - *

    If the listener is specified programmatically with this method, it overrides the - * configuration (that is, the {@code metadata.node-state-listener.class} option will be ignored). + *

    Listeners can be registered in two ways: either programmatically with this method, or via + * the configuration using the {@code advanced.metadata.node-state-listener.classes} option. + * + *

    This method unregisters any previously-registered listener. If you intend to register more + * than one listener, use {@link #addNodeStateListener(NodeStateListener)} instead. */ @NonNull public SelfT withNodeStateListener(@Nullable NodeStateListener nodeStateListener) { @@ -229,12 +232,32 @@ public SelfT withNodeStateListener(@Nullable NodeStateListener nodeStateListener return self; } + /** + * Registers a node state listener to use with the session, without removing previously-registered + * listeners. + * + *

    Listeners can be registered in two ways: either programmatically with this method, or via + * the configuration using the {@code advanced.metadata.node-state-listener.classes} option. + * + *

    Unlike {@link #withNodeStateListener(NodeStateListener)}, this method adds the new listener + * to the list of already-registered listeners, thus allowing applications to register multiple + * listeners. When multiple listeners are registered, they are notified in sequence every time a + * new listener event is triggered. + */ + @NonNull + public SelfT addNodeStateListener(@NonNull NodeStateListener nodeStateListener) { + programmaticArgumentsBuilder.addNodeStateListener(nodeStateListener); + return self; + } + /** * Registers a schema change listener to use with the session. * - *

    If the listener is specified programmatically with this method, it overrides the - * configuration (that is, the {@code metadata.schema-change-listener.class} option will be - * ignored). + *

    Listeners can be registered in two ways: either programmatically with this method, or via + * the configuration using the {@code advanced.metadata.schema-change-listener.classes} option. + * + *

    This method unregisters any previously-registered listener. If you intend to register more + * than one listener, use {@link #addSchemaChangeListener(SchemaChangeListener)} instead. */ @NonNull public SelfT withSchemaChangeListener(@Nullable SchemaChangeListener schemaChangeListener) { @@ -242,11 +265,32 @@ public SelfT withSchemaChangeListener(@Nullable SchemaChangeListener schemaChang return self; } + /** + * Registers a schema change listener to use with the session, without removing + * previously-registered listeners. + * + *

    Listeners can be registered in two ways: either programmatically with this method, or via + * the configuration using the {@code advanced.metadata.schema-change-listener.classes} option. + * + *

    Unlike {@link #withSchemaChangeListener(SchemaChangeListener)}, this method adds the new + * listener to the list of already-registered listeners, thus allowing applications to register + * multiple listeners. When multiple listeners are registered, they are notified in sequence every + * time a new listener event is triggered. + */ + @NonNull + public SelfT addSchemaChangeListener(@NonNull SchemaChangeListener schemaChangeListener) { + programmaticArgumentsBuilder.addSchemaChangeListener(schemaChangeListener); + return self; + } + /** * Registers a request tracker to use with the session. * - *

    If the tracker is specified programmatically with this method, it overrides the - * configuration (that is, the {@code request.tracker.class} option will be ignored). + *

    Trackers can be registered in two ways: either programmatically with this method, or via the + * configuration using the {@code advanced.request-tracker.classes} option. + * + *

    This method unregisters any previously-registered tracker. If you intend to register more + * than one tracker, use {@link #addRequestTracker(RequestTracker)} instead. */ @NonNull public SelfT withRequestTracker(@Nullable RequestTracker requestTracker) { @@ -254,6 +298,24 @@ public SelfT withRequestTracker(@Nullable RequestTracker requestTracker) { return self; } + /** + * Registers a request tracker to use with the session, without removing previously-registered + * trackers. + * + *

    Trackers can be registered in two ways: either programmatically with this method, or via the + * configuration using the {@code advanced.request-tracker.classes} option. + * + *

    Unlike {@link #withRequestTracker(RequestTracker)}, this method adds the new tracker to the + * list of already-registered trackers, thus allowing applications to register multiple trackers. + * When multiple trackers are registered, they are notified in sequence every time a new tracker + * event is triggered. + */ + @NonNull + public SelfT addRequestTracker(@NonNull RequestTracker requestTracker) { + programmaticArgumentsBuilder.addRequestTracker(requestTracker); + return self; + } + /** * Registers an authentication provider to use with the session. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java index 4d8f08e25a3..c88a61b037d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java @@ -27,9 +27,9 @@ /** * Tracks request execution for a session. * - *

    There is exactly one tracker per {@link Session}. It can be provided either via the - * configuration (see {@code reference.conf} in the manual or core driver JAR), or programmatically - * via {@link SessionBuilder#withRequestTracker(RequestTracker)}. + *

    Implementations of this interface can be registered either via the configuration (see {@code + * reference.conf} in the manual or core driver JAR), or programmatically via {@link + * SessionBuilder#addRequestTracker(RequestTracker)}. */ public interface RequestTracker extends AutoCloseable { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index fc73d47ca8d..2dc0e45d7b8 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -19,7 +19,6 @@ import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.internal.core.InsightsClientLifecycleListener; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.dse.driver.internal.core.type.codec.DseTypeCodecsRegistrar; import com.datastax.dse.protocol.internal.DseProtocolV1ClientCodecs; import com.datastax.dse.protocol.internal.DseProtocolV2ClientCodecs; @@ -59,7 +58,11 @@ import com.datastax.oss.driver.internal.core.metadata.DefaultTopologyMonitor; import com.datastax.oss.driver.internal.core.metadata.LoadBalancingPolicyWrapper; import com.datastax.oss.driver.internal.core.metadata.MetadataManager; +import com.datastax.oss.driver.internal.core.metadata.MultiplexingNodeStateListener; +import com.datastax.oss.driver.internal.core.metadata.NoopNodeStateListener; import com.datastax.oss.driver.internal.core.metadata.TopologyMonitor; +import com.datastax.oss.driver.internal.core.metadata.schema.MultiplexingSchemaChangeListener; +import com.datastax.oss.driver.internal.core.metadata.schema.NoopSchemaChangeListener; import com.datastax.oss.driver.internal.core.metadata.schema.parsing.DefaultSchemaParserFactory; import com.datastax.oss.driver.internal.core.metadata.schema.parsing.SchemaParserFactory; import com.datastax.oss.driver.internal.core.metadata.schema.queries.DefaultSchemaQueriesFactory; @@ -81,6 +84,7 @@ import com.datastax.oss.driver.internal.core.session.RequestProcessorRegistry; import com.datastax.oss.driver.internal.core.ssl.JdkSslHandlerFactory; import com.datastax.oss.driver.internal.core.ssl.SslHandlerFactory; +import com.datastax.oss.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.internal.core.tracker.NoopRequestTracker; import com.datastax.oss.driver.internal.core.tracker.RequestLogFormatter; import com.datastax.oss.driver.internal.core.type.codec.registry.DefaultCodecRegistry; @@ -99,6 +103,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -585,63 +590,120 @@ protected RequestThrottler buildRequestThrottler() { protected NodeStateListener buildNodeStateListener( NodeStateListener nodeStateListenerFromBuilder) { - return (nodeStateListenerFromBuilder != null) - ? nodeStateListenerFromBuilder - : Reflection.buildFromConfig( - this, - DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASS, - NodeStateListener.class, - "com.datastax.oss.driver.internal.core.metadata") - .orElseThrow( - () -> - new IllegalArgumentException( - String.format( - "Missing node state listener, check your configuration (%s)", - DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASS))); + List listeners = new ArrayList<>(); + if (nodeStateListenerFromBuilder != null) { + listeners.add(nodeStateListenerFromBuilder); + } + DefaultDriverOption newOption = DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASSES; + @SuppressWarnings("deprecation") + DefaultDriverOption legacyOption = DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASS; + DriverExecutionProfile profile = config.getDefaultProfile(); + if (profile.isDefined(newOption)) { + listeners.addAll( + Reflection.buildFromConfigList( + this, + newOption, + NodeStateListener.class, + "com.datastax.oss.driver.internal.core.metadata")); + } + if (profile.isDefined(legacyOption)) { + LOG.warn( + "Option {} has been deprecated and will be removed in a future release; please use option {} instead.", + legacyOption, + newOption); + Reflection.buildFromConfig( + this, + legacyOption, + NodeStateListener.class, + "com.datastax.oss.driver.internal.core.metadata") + .ifPresent(listeners::add); + } + if (listeners.isEmpty()) { + return new NoopNodeStateListener(this); + } else if (listeners.size() == 1) { + return listeners.get(0); + } else { + return new MultiplexingNodeStateListener(listeners); + } } protected SchemaChangeListener buildSchemaChangeListener( SchemaChangeListener schemaChangeListenerFromBuilder) { - return (schemaChangeListenerFromBuilder != null) - ? schemaChangeListenerFromBuilder - : Reflection.buildFromConfig( - this, - DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASS, - SchemaChangeListener.class, - "com.datastax.oss.driver.internal.core.metadata.schema") - .orElseThrow( - () -> - new IllegalArgumentException( - String.format( - "Missing schema change listener, check your configuration (%s)", - DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASS))); + List listeners = new ArrayList<>(); + if (schemaChangeListenerFromBuilder != null) { + listeners.add(schemaChangeListenerFromBuilder); + } + DefaultDriverOption newOption = DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASSES; + @SuppressWarnings("deprecation") + DefaultDriverOption legacyOption = DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASS; + DriverExecutionProfile profile = config.getDefaultProfile(); + if (profile.isDefined(newOption)) { + listeners.addAll( + Reflection.buildFromConfigList( + this, + newOption, + SchemaChangeListener.class, + "com.datastax.oss.driver.internal.core.metadata.schema")); + } + if (profile.isDefined(legacyOption)) { + LOG.warn( + "Option {} has been deprecated and will be removed in a future release; please use option {} instead.", + legacyOption, + newOption); + Reflection.buildFromConfig( + this, + legacyOption, + SchemaChangeListener.class, + "com.datastax.oss.driver.internal.core.metadata.schema") + .ifPresent(listeners::add); + } + if (listeners.isEmpty()) { + return new NoopSchemaChangeListener(this); + } else if (listeners.size() == 1) { + return listeners.get(0); + } else { + return new MultiplexingSchemaChangeListener(listeners); + } } protected RequestTracker buildRequestTracker(RequestTracker requestTrackerFromBuilder) { - RequestTracker requestTrackerFromConfig = - (requestTrackerFromBuilder != null) - ? requestTrackerFromBuilder - : Reflection.buildFromConfig( - this, - DefaultDriverOption.REQUEST_TRACKER_CLASS, - RequestTracker.class, - "com.datastax.oss.driver.internal.core.tracker") - .orElseThrow( - () -> - new IllegalArgumentException( - String.format( - "Missing request tracker, check your configuration (%s)", - DefaultDriverOption.REQUEST_TRACKER_CLASS))); - - // The default LBP needs to add its own tracker - if (requestTrackerFromConfig instanceof MultiplexingRequestTracker) { - return requestTrackerFromConfig; + List trackers = new ArrayList<>(); + if (requestTrackerFromBuilder != null) { + trackers.add(requestTrackerFromBuilder); + } + for (LoadBalancingPolicy lbp : this.getLoadBalancingPolicies().values()) { + lbp.getRequestTracker().ifPresent(trackers::add); + } + DefaultDriverOption newOption = DefaultDriverOption.REQUEST_TRACKER_CLASSES; + @SuppressWarnings("deprecation") + DefaultDriverOption legacyOption = DefaultDriverOption.REQUEST_TRACKER_CLASS; + DriverExecutionProfile profile = config.getDefaultProfile(); + if (profile.isDefined(newOption)) { + trackers.addAll( + Reflection.buildFromConfigList( + this, + newOption, + RequestTracker.class, + "com.datastax.oss.driver.internal.core.tracker")); + } + if (profile.isDefined(legacyOption)) { + LOG.warn( + "Option {} has been deprecated and will be removed in a future release; please use option {} instead.", + legacyOption, + newOption); + Reflection.buildFromConfig( + this, + legacyOption, + RequestTracker.class, + "com.datastax.oss.driver.internal.core.tracker") + .ifPresent(trackers::add); + } + if (trackers.isEmpty()) { + return new NoopRequestTracker(this); + } else if (trackers.size() == 1) { + return trackers.get(0); } else { - MultiplexingRequestTracker multiplexingRequestTracker = new MultiplexingRequestTracker(); - if (!(requestTrackerFromConfig instanceof NoopRequestTracker)) { - multiplexingRequestTracker.register(requestTrackerFromConfig); - } - return multiplexingRequestTracker; + return new MultiplexingRequestTracker(trackers); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java index 175f9556eaf..f79fa55b520 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java @@ -18,7 +18,6 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.context.DriverContext; @@ -105,11 +104,13 @@ public DefaultLoadBalancingPolicy(@NonNull DriverContext context, @NonNull Strin profile.getBoolean(DefaultDriverOption.LOAD_BALANCING_POLICY_SLOW_AVOIDANCE, true); } + @NonNull @Override - public void init(@NonNull Map nodes, @NonNull DistanceReporter distanceReporter) { - super.init(nodes, distanceReporter); + public Optional getRequestTracker() { if (avoidSlowReplicas) { - ((MultiplexingRequestTracker) context.getRequestTracker()).register(this); + return Optional.of(this); + } else { + return Optional.empty(); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListener.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListener.java new file mode 100644 index 00000000000..b57e05c152e --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListener.java @@ -0,0 +1,125 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.internal.core.util.Loggers; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Combines multiple node state listeners into a single one. + * + *

    Any exception thrown by a child listener is caught and logged. + */ +@ThreadSafe +public class MultiplexingNodeStateListener implements NodeStateListener { + + private static final Logger LOG = LoggerFactory.getLogger(MultiplexingNodeStateListener.class); + + private final List listeners = new CopyOnWriteArrayList<>(); + + public MultiplexingNodeStateListener() {} + + public MultiplexingNodeStateListener(NodeStateListener... listeners) { + this(Arrays.asList(listeners)); + } + + public MultiplexingNodeStateListener(Collection listeners) { + addListeners(listeners); + } + + private void addListeners(Collection source) { + for (NodeStateListener listener : source) { + addListener(listener); + } + } + + private void addListener(NodeStateListener toAdd) { + Objects.requireNonNull(toAdd, "listener cannot be null"); + if (toAdd instanceof MultiplexingNodeStateListener) { + addListeners(((MultiplexingNodeStateListener) toAdd).listeners); + } else { + listeners.add(toAdd); + } + } + + public void register(@NonNull NodeStateListener listener) { + addListener(listener); + } + + @Override + public void onAdd(@NonNull Node node) { + invokeListeners(listener -> listener.onAdd(node), "onAdd"); + } + + @Override + public void onUp(@NonNull Node node) { + invokeListeners(listener -> listener.onUp(node), "onUp"); + } + + @Override + public void onDown(@NonNull Node node) { + invokeListeners(listener -> listener.onDown(node), "onDown"); + } + + @Override + public void onRemove(@NonNull Node node) { + invokeListeners(listener -> listener.onRemove(node), "onRemove"); + } + + @Override + public void onSessionReady(@NonNull Session session) { + invokeListeners(listener -> listener.onSessionReady(session), "onSessionReady"); + } + + @Override + public void close() throws Exception { + for (NodeStateListener listener : listeners) { + try { + listener.close(); + } catch (Exception e) { + Loggers.warnWithException( + LOG, "Unexpected error while closing node state listener {}.", listener, e); + } + } + } + + private void invokeListeners(@NonNull Consumer action, String event) { + for (NodeStateListener listener : listeners) { + try { + action.accept(listener); + } catch (Exception e) { + Loggers.warnWithException( + LOG, + "Unexpected error while notifying node state listener {} of an {} event.", + listener, + event, + e); + } + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NoopNodeStateListener.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NoopNodeStateListener.java index 2e70d8efb6a..8c9c97fd915 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NoopNodeStateListener.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NoopNodeStateListener.java @@ -16,29 +16,12 @@ package com.datastax.oss.driver.internal.core.metadata; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import com.datastax.oss.driver.api.core.metadata.NodeStateListenerBase; -import com.datastax.oss.driver.api.core.session.SessionBuilder; import net.jcip.annotations.ThreadSafe; /** - * Default node state listener implementation with empty methods. - * - *

    To activate this listener, modify the {@code advanced.node-state-listener} section in the - * driver configuration, for example: - * - *

    - * datastax-java-driver {
    - *   advanced.node-state-listener {
    - *     class = NoopNodeStateListener
    - *   }
    - * }
    - * 
    - * - * See {@code reference.conf} (in the manual or core driver JAR) for more details. - * - *

    Note that if a listener is specified programmatically with {@link - * SessionBuilder#withNodeStateListener(NodeStateListener)}, the configuration is ignored. + * Default node state listener implementation with empty methods. This implementation is used when + * no listeners were registered, neither programmatically nor through the configuration. */ @ThreadSafe public class NoopNodeStateListener extends NodeStateListenerBase { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListener.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListener.java new file mode 100644 index 00000000000..e7c277a29e0 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListener.java @@ -0,0 +1,209 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata.schema; + +import com.datastax.oss.driver.api.core.metadata.schema.AggregateMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.FunctionMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.ViewMetadata; +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.api.core.type.UserDefinedType; +import com.datastax.oss.driver.internal.core.util.Loggers; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Combines multiple schema change listeners into a single one. + * + *

    Any exception thrown by a child listener is caught and logged. + */ +@ThreadSafe +public class MultiplexingSchemaChangeListener implements SchemaChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(MultiplexingSchemaChangeListener.class); + + private final List listeners = new CopyOnWriteArrayList<>(); + + public MultiplexingSchemaChangeListener() {} + + public MultiplexingSchemaChangeListener(SchemaChangeListener... listeners) { + this(Arrays.asList(listeners)); + } + + public MultiplexingSchemaChangeListener(Collection listeners) { + addListeners(listeners); + } + + private void addListeners(Collection source) { + for (SchemaChangeListener listener : source) { + addListener(listener); + } + } + + private void addListener(SchemaChangeListener toAdd) { + Objects.requireNonNull(toAdd, "listener cannot be null"); + if (toAdd instanceof MultiplexingSchemaChangeListener) { + addListeners(((MultiplexingSchemaChangeListener) toAdd).listeners); + } else { + listeners.add(toAdd); + } + } + + public void register(@NonNull SchemaChangeListener listener) { + addListener(listener); + } + + @Override + public void onKeyspaceCreated(@NonNull KeyspaceMetadata keyspace) { + invokeListeners(listener -> listener.onKeyspaceCreated(keyspace), "onKeyspaceCreated"); + } + + @Override + public void onKeyspaceDropped(@NonNull KeyspaceMetadata keyspace) { + invokeListeners(listener -> listener.onKeyspaceDropped(keyspace), "onKeyspaceDropped"); + } + + @Override + public void onKeyspaceUpdated( + @NonNull KeyspaceMetadata current, @NonNull KeyspaceMetadata previous) { + invokeListeners(listener -> listener.onKeyspaceUpdated(current, previous), "onKeyspaceUpdated"); + } + + @Override + public void onTableCreated(@NonNull TableMetadata table) { + invokeListeners(listener -> listener.onTableCreated(table), "onTableCreated"); + } + + @Override + public void onTableDropped(@NonNull TableMetadata table) { + invokeListeners(listener -> listener.onTableDropped(table), "onTableDropped"); + } + + @Override + public void onTableUpdated(@NonNull TableMetadata current, @NonNull TableMetadata previous) { + invokeListeners(listener -> listener.onTableUpdated(current, previous), "onTableUpdated"); + } + + @Override + public void onUserDefinedTypeCreated(@NonNull UserDefinedType type) { + invokeListeners( + listener -> listener.onUserDefinedTypeCreated(type), "onUserDefinedTypeCreated"); + } + + @Override + public void onUserDefinedTypeDropped(@NonNull UserDefinedType type) { + invokeListeners( + listener -> listener.onUserDefinedTypeDropped(type), "onUserDefinedTypeDropped"); + } + + @Override + public void onUserDefinedTypeUpdated( + @NonNull UserDefinedType current, @NonNull UserDefinedType previous) { + invokeListeners( + listener -> listener.onUserDefinedTypeUpdated(current, previous), + "onUserDefinedTypeUpdated"); + } + + @Override + public void onFunctionCreated(@NonNull FunctionMetadata function) { + invokeListeners(listener -> listener.onFunctionCreated(function), "onFunctionCreated"); + } + + @Override + public void onFunctionDropped(@NonNull FunctionMetadata function) { + invokeListeners(listener -> listener.onFunctionDropped(function), "onFunctionDropped"); + } + + @Override + public void onFunctionUpdated( + @NonNull FunctionMetadata current, @NonNull FunctionMetadata previous) { + invokeListeners(listener -> listener.onFunctionUpdated(current, previous), "onFunctionUpdated"); + } + + @Override + public void onAggregateCreated(@NonNull AggregateMetadata aggregate) { + invokeListeners(listener -> listener.onAggregateCreated(aggregate), "onAggregateCreated"); + } + + @Override + public void onAggregateDropped(@NonNull AggregateMetadata aggregate) { + invokeListeners(listener -> listener.onAggregateDropped(aggregate), "onAggregateDropped"); + } + + @Override + public void onAggregateUpdated( + @NonNull AggregateMetadata current, @NonNull AggregateMetadata previous) { + invokeListeners( + listener -> listener.onAggregateUpdated(current, previous), "onAggregateUpdated"); + } + + @Override + public void onViewCreated(@NonNull ViewMetadata view) { + invokeListeners(listener -> listener.onViewCreated(view), "onViewCreated"); + } + + @Override + public void onViewDropped(@NonNull ViewMetadata view) { + invokeListeners(listener -> listener.onViewDropped(view), "onViewDropped"); + } + + @Override + public void onViewUpdated(@NonNull ViewMetadata current, @NonNull ViewMetadata previous) { + invokeListeners(listener -> listener.onViewUpdated(current, previous), "onViewUpdated"); + } + + @Override + public void onSessionReady(@NonNull Session session) { + invokeListeners(listener -> listener.onSessionReady(session), "onSessionReady"); + } + + @Override + public void close() throws Exception { + for (SchemaChangeListener listener : listeners) { + try { + listener.close(); + } catch (Exception e) { + Loggers.warnWithException( + LOG, "Unexpected error while closing schema change listener {}.", listener, e); + } + } + } + + private void invokeListeners(@NonNull Consumer action, String event) { + for (SchemaChangeListener listener : listeners) { + try { + action.accept(listener); + } catch (Exception e) { + Loggers.warnWithException( + LOG, + "Unexpected error while notifying schema change listener {} of an {} event.", + listener, + event, + e); + } + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/NoopSchemaChangeListener.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/NoopSchemaChangeListener.java index 2df3935a80f..46d9226a7f7 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/NoopSchemaChangeListener.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/NoopSchemaChangeListener.java @@ -16,29 +16,12 @@ package com.datastax.oss.driver.internal.core.metadata.schema; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListenerBase; -import com.datastax.oss.driver.api.core.session.SessionBuilder; import net.jcip.annotations.ThreadSafe; /** - * Default schema change listener implementation with empty methods. - * - *

    To activate this listener, modify the {@code advanced.schema-change-listener} section in the - * driver configuration, for example: - * - *

    - * datastax-java-driver {
    - *   advanced.schema-change-listener {
    - *     class = NoopSchemaChangeListener
    - *   }
    - * }
    - * 
    - * - * See {@code reference.conf} (in the manual or core driver JAR) for more details. - * - *

    Note that if a listener is specified programmatically with {@link - * SessionBuilder#withSchemaChangeListener(SchemaChangeListener)}, the configuration is ignored. + * Default schema change listener implementation with empty methods. This implementation is used + * when no listeners were registered, neither programmatically nor through the configuration. */ @ThreadSafe public class NoopSchemaChangeListener extends SchemaChangeListenerBase { diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/tracker/MultiplexingRequestTracker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java similarity index 53% rename from core/src/main/java/com/datastax/dse/driver/internal/core/tracker/MultiplexingRequestTracker.java rename to core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java index 694748f9965..8bce9840e2f 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/tracker/MultiplexingRequestTracker.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java @@ -13,36 +13,65 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.datastax.dse.driver.internal.core.tracker; +package com.datastax.oss.driver.internal.core.tracker; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.core.tracker.RequestTracker; +import com.datastax.oss.driver.internal.core.util.Loggers; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Combines multiple request trackers into a single one. * - *

    The default context always wraps any user-provided tracker into this, in case other internal - * components need to add their own trackers later (see InternalDriverContext.buildRequestTracker). - * - *

    We also use it to catch and log any unexpected exception thrown by a tracker. + *

    Any exception thrown by a child tracker is caught and logged. */ +@ThreadSafe public class MultiplexingRequestTracker implements RequestTracker { private static final Logger LOG = LoggerFactory.getLogger(MultiplexingRequestTracker.class); private final List trackers = new CopyOnWriteArrayList<>(); - public void register(RequestTracker tracker) { - trackers.add(tracker); + public MultiplexingRequestTracker() {} + + public MultiplexingRequestTracker(RequestTracker... trackers) { + this(Arrays.asList(trackers)); + } + + public MultiplexingRequestTracker(Collection trackers) { + addTrackers(trackers); + } + + private void addTrackers(Collection source) { + for (RequestTracker tracker : source) { + addTracker(tracker); + } + } + + private void addTracker(RequestTracker toAdd) { + Objects.requireNonNull(toAdd, "tracker cannot be null"); + if (toAdd instanceof MultiplexingRequestTracker) { + addTrackers(((MultiplexingRequestTracker) toAdd).trackers); + } else { + trackers.add(toAdd); + } + } + + public void register(@NonNull RequestTracker tracker) { + addTracker(tracker); } @Override @@ -52,13 +81,10 @@ public void onSuccess( @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, @NonNull String logPrefix) { - for (RequestTracker tracker : trackers) { - try { - tracker.onSuccess(request, latencyNanos, executionProfile, node, logPrefix); - } catch (Throwable t) { - LOG.error("[{}] Unexpected error while invoking request tracker", logPrefix, t); - } - } + invokeTrackers( + tracker -> tracker.onSuccess(request, latencyNanos, executionProfile, node, logPrefix), + logPrefix, + "onSuccess"); } @Override @@ -69,13 +95,10 @@ public void onError( @NonNull DriverExecutionProfile executionProfile, @Nullable Node node, @NonNull String logPrefix) { - for (RequestTracker tracker : trackers) { - try { - tracker.onError(request, error, latencyNanos, executionProfile, node, logPrefix); - } catch (Throwable t) { - LOG.error("[{}] Unexpected error while invoking request tracker", logPrefix, t); - } - } + invokeTrackers( + tracker -> tracker.onError(request, error, latencyNanos, executionProfile, node, logPrefix), + logPrefix, + "onError"); } @Override @@ -85,13 +108,10 @@ public void onNodeSuccess( @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, @NonNull String logPrefix) { - for (RequestTracker tracker : trackers) { - try { - tracker.onNodeSuccess(request, latencyNanos, executionProfile, node, logPrefix); - } catch (Throwable t) { - LOG.error("[{}] Unexpected error while invoking request tracker", logPrefix, t); - } - } + invokeTrackers( + tracker -> tracker.onNodeSuccess(request, latencyNanos, executionProfile, node, logPrefix), + logPrefix, + "onNodeSuccess"); } @Override @@ -102,42 +122,44 @@ public void onNodeError( @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, @NonNull String logPrefix) { - for (RequestTracker tracker : trackers) { - try { - tracker.onNodeError(request, error, latencyNanos, executionProfile, node, logPrefix); - } catch (Throwable t) { - LOG.error("[{}] Unexpected error while invoking request tracker", logPrefix, t); - } - } + invokeTrackers( + tracker -> + tracker.onNodeError(request, error, latencyNanos, executionProfile, node, logPrefix), + logPrefix, + "onNodeError"); } @Override public void onSessionReady(@NonNull Session session) { - for (RequestTracker tracker : trackers) { - try { - tracker.onSessionReady(session); - } catch (Throwable t) { - LOG.error("[{}] Unexpected error while invoking request tracker", session.getName(), t); - } - } + invokeTrackers(tracker -> tracker.onSessionReady(session), session.getName(), "onSessionReady"); } @Override public void close() throws Exception { - Exception toThrow = null; for (RequestTracker tracker : trackers) { try { tracker.close(); } catch (Exception e) { - if (toThrow == null) { - toThrow = e; - } else { - toThrow.addSuppressed(e); - } + Loggers.warnWithException( + LOG, "Unexpected error while closing request tracker {}.", tracker, e); } } - if (toThrow != null) { - throw toThrow; + } + + private void invokeTrackers( + @NonNull Consumer action, String logPrefix, String event) { + for (RequestTracker tracker : trackers) { + try { + action.accept(tracker); + } catch (Exception e) { + Loggers.warnWithException( + LOG, + "[{}] Unexpected error while notifying request tracker {} of an {} event.", + logPrefix, + tracker, + event, + e); + } } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java index 0cec5dd2691..6297f51e789 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java @@ -19,29 +19,13 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.session.Request; -import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import edu.umd.cs.findbugs.annotations.NonNull; import net.jcip.annotations.ThreadSafe; /** - * A no-op request tracker. - * - *

    To activate this tracker, modify the {@code advanced.request-tracker} section in the driver - * configuration, for example: - * - *

    - * datastax-java-driver {
    - *   advanced.request-tracker {
    - *     class = NoopRequestTracker
    - *   }
    - * }
    - * 
    - * - * See {@code reference.conf} (in the manual or core driver JAR) for more details. - * - *

    Note that if a tracker is specified programmatically with {@link - * SessionBuilder#withRequestTracker(RequestTracker)}, the configuration is ignored. + * Default request tracker implementation with empty methods. This implementation is used when no + * trackers were registered, neither programmatically nor through the configuration. */ @ThreadSafe public class NoopRequestTracker implements RequestTracker { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java index bdd99fc5ab7..489c4e61cbe 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java @@ -38,7 +38,7 @@ *

      * datastax-java-driver {
      *   advanced.request-tracker {
    - *     class = RequestLogger
    + *     classes = [RequestLogger]
      *     logs {
      *       success { enabled = true }
      *       slow { enabled = true, threshold = 1 second }
    @@ -56,7 +56,7 @@
      * See {@code reference.conf} (in the manual or core driver JAR) for more details.
      *
      * 

    Note that if a tracker is specified programmatically with {@link - * SessionBuilder#withRequestTracker(RequestTracker)}, the configuration is ignored. + * SessionBuilder#addRequestTracker(RequestTracker)}, the configuration is ignored. */ @ThreadSafe public class RequestLogger implements RequestTracker { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Reflection.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Reflection.java index 9526a144536..ea371f6ddb8 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Reflection.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Reflection.java @@ -21,6 +21,7 @@ import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.shaded.guava.common.base.Joiner; import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ListMultimap; import com.datastax.oss.driver.shaded.guava.common.collect.MultimapBuilder; @@ -29,6 +30,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Optional; import org.slf4j.Logger; @@ -108,6 +110,36 @@ public static Optional buildFromConfig( return buildFromConfig(context, null, classNameOption, expectedSuperType, defaultPackages); } + /** + * Tries to create a list of instances, given an option defined in the driver configuration. + * + *

    For example: + * + *

    +   * my-policy.classes = [my.package.MyPolicyImpl1,my.package.MyPolicyImpl2]
    +   * 
    + * + * Each class will be instantiated via reflection, and must have a constructor that takes a {@link + * DriverContext} argument. + * + * @param context the driver context. + * @param classNamesOption the option that indicates the class list. It will be looked up in the + * default profile of the configuration stored in the context. + * @param expectedSuperType a super-type that the classes are expected to implement/extend. + * @param defaultPackages the default packages to prepend to the class names if they are not + * qualified. They will be tried in order, the first one that matches an existing class will + * be used. + * @return the list of new instances, or an empty list if {@code classNamesOption} is not defined + * in the configuration. + */ + public static ImmutableList buildFromConfigList( + InternalDriverContext context, + DriverOption classNamesOption, + Class expectedSuperType, + String... defaultPackages) { + return buildFromConfigList(context, null, classNamesOption, expectedSuperType, defaultPackages); + } + /** * Tries to create multiple instances of a class, given options defined in the driver * configuration and possibly overridden in profiles. @@ -199,6 +231,57 @@ public static Optional buildFromConfig( } String className = config.getString(classNameOption); + return Optional.of( + resolveClass( + context, profileName, expectedSuperType, configPath, className, defaultPackages)); + } + + /** + * @param profileName if null, this is a global policy, use the default profile and look for a + * one-arg constructor. If not null, this is a per-profile policy, look for a two-arg + * constructor. + */ + public static ImmutableList buildFromConfigList( + InternalDriverContext context, + String profileName, + DriverOption classNamesOption, + Class expectedSuperType, + String... defaultPackages) { + + DriverExecutionProfile config = + (profileName == null) + ? context.getConfig().getDefaultProfile() + : context.getConfig().getProfile(profileName); + + String configPath = classNamesOption.getPath(); + LOG.debug( + "Creating a list of {} from config option {}", + expectedSuperType.getSimpleName(), + configPath); + + if (!config.isDefined(classNamesOption)) { + LOG.debug("Option is not defined, skipping"); + return ImmutableList.of(); + } + + List classNames = config.getStringList(classNamesOption); + ImmutableList.Builder components = ImmutableList.builder(); + for (String className : classNames) { + components.add( + resolveClass( + context, profileName, expectedSuperType, configPath, className, defaultPackages)); + } + return components.build(); + } + + @NonNull + private static ComponentT resolveClass( + InternalDriverContext context, + String profileName, + Class expectedSuperType, + String configPath, + String className, + String[] defaultPackages) { Class clazz = null; if (className.contains(".")) { LOG.debug("Building from fully-qualified name {}", className); @@ -245,7 +328,7 @@ public static Optional buildFromConfig( (profileName == null) ? constructor.newInstance(context) : constructor.newInstance(context, profileName); - return Optional.of(instance); + return instance; } catch (Exception e) { // ITE just wraps an exception thrown by the constructor, get rid of it: Throwable cause = (e instanceof InvocationTargetException) ? e.getCause() : e; diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index ab5a33a028d..44e454fe42d 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -818,23 +818,29 @@ datastax-java-driver { force-java-clock = false } - # A session-wide component that tracks the outcome of requests. - # - # Required: yes - # Modifiable at runtime: no (but custom implementations may elect to watch configuration changes - # and allow child options to be changed at runtime). - # Overridable in a profile: no + # Request trackers are session-wide components that get notified of the outcome of requests. advanced.request-tracker { - # The class of the tracker. If it is not qualified, the driver assumes that it resides in the - # package com.datastax.oss.driver.internal.core.tracker. + # The list of trackers to register. # - # The driver provides the following implementations out of the box: - # - NoopRequestTracker: does nothing. + # This must be a list of class names, either fully-qualified or non-qualified; if the latter, + # the driver assumes that the class resides in the package + # com.datastax.oss.driver.internal.core.tracker. + # + # All classes specified here must implement + # com.datastax.oss.driver.api.core.tracker.RequestTracker and have a public constructor with a + # DriverContext argument. + # + # The driver provides the following implementation out of the box: # - RequestLogger: logs requests (see the parameters below). # - # You can also specify a custom class that implements RequestTracker and has a public - # constructor with a DriverContext argument. - class = NoopRequestTracker + # You can also pass instances of your trackers programmatically with + # CqlSession.builder().addRequestTracker(). + # + # Required: no + # Modifiable at runtime: no (but custom implementations may elect to watch configuration changes + # and allow child options to be changed at runtime). + # Overridable in a profile: no + #classes = [RequestLogger,com.example.app.MyTracker] # Parameters for RequestLogger. All of them can be overridden in a profile, and changed at # runtime (the new values will be taken into account for requests logged after the change). @@ -937,39 +943,37 @@ datastax-java-driver { // drain-interval = 10 milliseconds } - # A session-wide component that listens for node state changes. If it is not qualified, the driver - # assumes that it resides in the package com.datastax.oss.driver.internal.core.metadata. + # The list of node state listeners to register. Node state listeners are session-wide + # components that listen for node state changes (e.g., when nodes go down or back up). # - # The driver provides a single no-op implementation out of the box: NoopNodeStateListener. - # - # You can also specify a custom class that implements NodeStateListener and has a public + # This must be a list of fully-qualified class names; classes specified here must implement + # com.datastax.oss.driver.api.core.metadata.NodeStateListener and have a public # constructor with a DriverContext argument. # - # Alternatively, you can pass an instance of your listener programmatically with - # CqlSession.builder().withNodeStateListener(). In that case, this option will be ignored. + # You can also pass instances of your listeners programmatically with + # CqlSession.builder().addNodeStateListener(). # - # Required: unless a listener has been provided programmatically + # Required: no # Modifiable at runtime: no (but custom implementations may elect to watch configuration changes # and allow child options to be changed at runtime). # Overridable in a profile: no - advanced.node-state-listener.class = NoopNodeStateListener + #advanced.node-state-listener.classes = [com.example.app.MyListener1,com.example.app.MyListener2] - # A session-wide component that listens for node state changes. If it is not qualified, the driver - # assumes that it resides in the package com.datastax.oss.driver.internal.core.metadata.schema. + # The list of schema change listeners to register. Schema change listeners are session-wide + # components that listen for schema changes (e.g., when tables are created or dropped). # - # The driver provides a single no-op implementation out of the box: NoopSchemaChangeListener. - # - # You can also specify a custom class that implements SchemaChangeListener and has a public + # This must be a list of fully-qualified class names; classes specified here must implement + # com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener and have a public # constructor with a DriverContext argument. # - # Alternatively, you can pass an instance of your listener programmatically with - # CqlSession.builder().withSchemaChangeListener(). In that case, this option will be ignored. + # You can also pass instances of your listeners programmatically with + # CqlSession.builder().addSchemaChangeListener(). # - # Required: unless a listener has been provided programmatically + # Required: no # Modifiable at runtime: no (but custom implementations may elect to watch configuration changes # and allow child options to be changed at runtime). # Overridable in a profile: no - advanced.schema-change-listener.class = NoopSchemaChangeListener + #advanced.schema-change-listener.classes = [com.example.app.MyListener1,com.example.app.MyListener2] # The address translator to use to convert the addresses sent by Cassandra nodes into ones that # the driver uses to connect. diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java index 38faf7d1beb..25a4e4f1686 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDcFailoverTest.java @@ -17,17 +17,14 @@ import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.util.Map; import java.util.UUID; -import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @@ -36,13 +33,6 @@ public class DcInferringLoadBalancingPolicyDcFailoverTest extends BasicLoadBalancingPolicyDcFailoverTest { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Override protected DcInferringLoadBalancingPolicy createAndInitPolicy() { when(node4.getDatacenter()).thenReturn("dc2"); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java index 6d644edcf2a..7207d3a057d 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyDistanceTest.java @@ -17,12 +17,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.BDDMockito.given; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import edu.umd.cs.findbugs.annotations.NonNull; -import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @@ -31,13 +28,6 @@ public class DcInferringLoadBalancingPolicyDistanceTest extends BasicLoadBalancingPolicyDistanceTest { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Override public void should_report_LOCAL_when_dc_agnostic() { // This policy cannot operate when contact points are from different DCs diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java index aa01ff08acf..f87a1524301 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyEventsTest.java @@ -17,24 +17,14 @@ import static com.datastax.oss.driver.Assertions.assertThat; import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.reset; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.UUID; -import org.junit.Before; public class DcInferringLoadBalancingPolicyEventsTest extends BasicLoadBalancingPolicyEventsTest { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Override @NonNull protected BasicLoadBalancingPolicy createAndInitPolicy() { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java index e58d0e8b6bd..4cf355d59ee 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DcInferringLoadBalancingPolicyInitTest.java @@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.filter; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -26,7 +25,6 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; @@ -35,18 +33,10 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.UUID; -import org.junit.Before; import org.junit.Test; public class DcInferringLoadBalancingPolicyInitTest extends LoadBalancingPolicyTestBase { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Test public void should_use_local_dc_if_provided_via_config() { // Given diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java index 34302a196e7..d002b8e475f 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDcFailoverTest.java @@ -17,17 +17,14 @@ import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.util.Map; import java.util.UUID; -import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @@ -36,13 +33,6 @@ public class DefaultLoadBalancingPolicyDcFailoverTest extends BasicLoadBalancingPolicyDcFailoverTest { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Override protected DefaultLoadBalancingPolicy createAndInitPolicy() { when(node4.getDatacenter()).thenReturn("dc2"); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java index 8db9d0d1019..a859c7b1f09 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyDistanceTest.java @@ -17,12 +17,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.BDDMockito.given; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import edu.umd.cs.findbugs.annotations.NonNull; -import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @@ -30,13 +27,6 @@ @RunWith(MockitoJUnitRunner.Silent.class) public class DefaultLoadBalancingPolicyDistanceTest extends BasicLoadBalancingPolicyDistanceTest { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Override public void should_report_LOCAL_when_dc_agnostic() { // This policy cannot operate in dc-agnostic mode diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java index 22f80b1f36d..b4b48da25ba 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyEventsTest.java @@ -17,24 +17,14 @@ import static com.datastax.oss.driver.Assertions.assertThat; import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.reset; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.UUID; -import org.junit.Before; public class DefaultLoadBalancingPolicyEventsTest extends BasicLoadBalancingPolicyEventsTest { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Override @NonNull protected DefaultLoadBalancingPolicy createAndInitPolicy() { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java index 6efe9661d89..e9fd5c68944 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyInitTest.java @@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.filter; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -26,7 +25,6 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; @@ -35,18 +33,10 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.UUID; -import org.junit.Before; import org.junit.Test; public class DefaultLoadBalancingPolicyInitTest extends LoadBalancingPolicyTestBase { - @Override - @Before - public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); - super.setup(); - } - @Test public void should_use_local_dc_if_provided_via_config() { // Given diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java index 207a5b409b7..22cfc3a76d9 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.internal.core.pool.ChannelPool; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; @@ -59,7 +58,6 @@ public class DefaultLoadBalancingPolicyQueryPlanTest extends BasicLoadBalancingP @Before @Override public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); nanoTime = T1; diceRoll = 4; given(node4.getDatacenter()).willReturn("dc1"); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java index f87f5b38f43..6dfad480708 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java @@ -19,7 +19,6 @@ import static com.datastax.oss.driver.api.core.config.DriverExecutionProfile.DEFAULT_NAME; import static org.mockito.BDDMockito.given; -import com.datastax.dse.driver.internal.core.tracker.MultiplexingRequestTracker; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; @@ -41,7 +40,6 @@ public class DefaultLoadBalancingPolicyRequestTrackerTest extends LoadBalancingP @Before @Override public void setup() { - given(context.getRequestTracker()).willReturn(new MultiplexingRequestTracker()); super.setup(); given(metadataManager.getContactPoints()).willReturn(ImmutableSet.of(node1)); policy = diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListenerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListenerTest.java new file mode 100644 index 00000000000..4d868e4afce --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MultiplexingNodeStateListenerTest.java @@ -0,0 +1,194 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.verify; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.api.core.session.Session; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.LoggerFactory; + +@RunWith(MockitoJUnitRunner.Strict.class) +public class MultiplexingNodeStateListenerTest { + + @Mock private NodeStateListener child1; + @Mock private NodeStateListener child2; + @Mock private Node node; + @Mock private Session session; + + @Mock private Appender appender; + @Captor private ArgumentCaptor loggingEventCaptor; + + private Logger logger; + private Level initialLogLevel; + + @Before + public void addAppenders() { + logger = (Logger) LoggerFactory.getLogger(MultiplexingNodeStateListener.class); + initialLogLevel = logger.getLevel(); + logger.setLevel(Level.WARN); + logger.addAppender(appender); + } + + @After + public void removeAppenders() { + logger.detachAppender(appender); + logger.setLevel(initialLogLevel); + } + + @Test + public void should_register() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(); + // when + listener.register(child1); + listener.register(child2); + // then + assertThat(listener).extracting("listeners").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_flatten_child_multiplexing_listener_via_constructor() { + // given + MultiplexingNodeStateListener listener = + new MultiplexingNodeStateListener(new MultiplexingNodeStateListener(child1, child2)); + // when + // then + assertThat(listener).extracting("listeners").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_flatten_child_multiplexing_listener_via_register() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(); + // when + listener.register(new MultiplexingNodeStateListener(child1, child2)); + // then + assertThat(listener).extracting("listeners").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_notify_onUp() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onUp(node); + // when + listener.onUp(node); + // then + verify(child1).onUp(node); + verify(child2).onUp(node); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying node state listener child1 of an onUp event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onDown() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onDown(node); + // when + listener.onDown(node); + // then + verify(child1).onDown(node); + verify(child2).onDown(node); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying node state listener child1 of an onDown event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onAdd() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onAdd(node); + // when + listener.onAdd(node); + // then + verify(child1).onAdd(node); + verify(child2).onAdd(node); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying node state listener child1 of an onAdd event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onRemove() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onRemove(node); + // when + listener.onRemove(node); + // then + verify(child1).onRemove(node); + verify(child2).onRemove(node); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying node state listener child1 of an onRemove event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onSessionReady() { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onSessionReady(session); + // when + listener.onSessionReady(session); + // then + verify(child1).onSessionReady(session); + verify(child2).onSessionReady(session); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying node state listener child1 of an onSessionReady event. (NullPointerException: null)"); + } + + @Test + public void should_notify_close() throws Exception { + // given + MultiplexingNodeStateListener listener = new MultiplexingNodeStateListener(child1, child2); + Exception child1Error = new NullPointerException(); + willThrow(child1Error).given(child1).close(); + // when + listener.close(); + // then + verify(child1).close(); + verify(child2).close(); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while closing node state listener child1. (NullPointerException: null)"); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListenerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListenerTest.java new file mode 100644 index 00000000000..440c7035394 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/MultiplexingSchemaChangeListenerTest.java @@ -0,0 +1,450 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata.schema; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.verify; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import com.datastax.oss.driver.api.core.metadata.schema.AggregateMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.FunctionMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.ViewMetadata; +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.api.core.type.UserDefinedType; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.LoggerFactory; + +@RunWith(MockitoJUnitRunner.Strict.class) +public class MultiplexingSchemaChangeListenerTest { + + @Mock private SchemaChangeListener child1; + @Mock private SchemaChangeListener child2; + @Mock private Session session; + @Mock private KeyspaceMetadata keyspace1, keyspace2; + @Mock private TableMetadata table1, table2; + @Mock private UserDefinedType userDefinedType1, userDefinedType2; + @Mock private FunctionMetadata function1, function2; + @Mock private AggregateMetadata aggregate1, aggregate2; + @Mock private ViewMetadata view1, view2; + + @Mock private Appender appender; + @Captor private ArgumentCaptor loggingEventCaptor; + + private Logger logger; + private Level initialLogLevel; + + @Before + public void addAppenders() { + logger = (Logger) LoggerFactory.getLogger(MultiplexingSchemaChangeListener.class); + initialLogLevel = logger.getLevel(); + logger.setLevel(Level.WARN); + logger.addAppender(appender); + } + + @After + public void removeAppenders() { + logger.detachAppender(appender); + logger.setLevel(initialLogLevel); + } + + @Test + public void should_register() { + // given + MultiplexingSchemaChangeListener listener = new MultiplexingSchemaChangeListener(); + // when + listener.register(child1); + listener.register(child2); + // then + assertThat(listener).extracting("listeners").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_flatten_child_multiplexing_listener_via_constructor() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(new MultiplexingSchemaChangeListener(child1, child2)); + // when + // then + assertThat(listener).extracting("listeners").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_flatten_child_multiplexing_listener_via_register() { + // given + MultiplexingSchemaChangeListener listener = new MultiplexingSchemaChangeListener(); + // when + listener.register(new MultiplexingSchemaChangeListener(child1, child2)); + // then + assertThat(listener).extracting("listeners").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_notify_onKeyspaceCreated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onKeyspaceCreated(keyspace1); + // when + listener.onKeyspaceCreated(keyspace1); + // then + verify(child1).onKeyspaceCreated(keyspace1); + verify(child2).onKeyspaceCreated(keyspace1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onKeyspaceCreated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onKeyspaceDropped() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onKeyspaceDropped(keyspace1); + // when + listener.onKeyspaceDropped(keyspace1); + // then + verify(child1).onKeyspaceDropped(keyspace1); + verify(child2).onKeyspaceDropped(keyspace1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onKeyspaceDropped event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onKeyspaceUpdated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onKeyspaceUpdated(keyspace1, keyspace2); + // when + listener.onKeyspaceUpdated(keyspace1, keyspace2); + // then + verify(child1).onKeyspaceUpdated(keyspace1, keyspace2); + verify(child2).onKeyspaceUpdated(keyspace1, keyspace2); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onKeyspaceUpdated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onTableCreated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onTableCreated(table1); + // when + listener.onTableCreated(table1); + // then + verify(child1).onTableCreated(table1); + verify(child2).onTableCreated(table1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onTableCreated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onTableDropped() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onTableDropped(table1); + // when + listener.onTableDropped(table1); + // then + verify(child1).onTableDropped(table1); + verify(child2).onTableDropped(table1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onTableDropped event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onTableUpdated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onTableUpdated(table1, table2); + // when + listener.onTableUpdated(table1, table2); + // then + verify(child1).onTableUpdated(table1, table2); + verify(child2).onTableUpdated(table1, table2); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onTableUpdated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onUserDefinedTypeCreated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onUserDefinedTypeCreated(userDefinedType1); + // when + listener.onUserDefinedTypeCreated(userDefinedType1); + // then + verify(child1).onUserDefinedTypeCreated(userDefinedType1); + verify(child2).onUserDefinedTypeCreated(userDefinedType1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onUserDefinedTypeCreated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onUserDefinedTypeDropped() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onUserDefinedTypeDropped(userDefinedType1); + // when + listener.onUserDefinedTypeDropped(userDefinedType1); + // then + verify(child1).onUserDefinedTypeDropped(userDefinedType1); + verify(child2).onUserDefinedTypeDropped(userDefinedType1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onUserDefinedTypeDropped event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onUserDefinedTypeUpdated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()) + .given(child1) + .onUserDefinedTypeUpdated(userDefinedType1, userDefinedType2); + // when + listener.onUserDefinedTypeUpdated(userDefinedType1, userDefinedType2); + // then + verify(child1).onUserDefinedTypeUpdated(userDefinedType1, userDefinedType2); + verify(child2).onUserDefinedTypeUpdated(userDefinedType1, userDefinedType2); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onUserDefinedTypeUpdated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onFunctionCreated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onFunctionCreated(function1); + // when + listener.onFunctionCreated(function1); + // then + verify(child1).onFunctionCreated(function1); + verify(child2).onFunctionCreated(function1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onFunctionCreated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onFunctionDropped() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onFunctionDropped(function1); + // when + listener.onFunctionDropped(function1); + // then + verify(child1).onFunctionDropped(function1); + verify(child2).onFunctionDropped(function1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onFunctionDropped event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onFunctionUpdated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onFunctionUpdated(function1, function2); + // when + listener.onFunctionUpdated(function1, function2); + // then + verify(child1).onFunctionUpdated(function1, function2); + verify(child2).onFunctionUpdated(function1, function2); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onFunctionUpdated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onAggregateCreated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onAggregateCreated(aggregate1); + // when + listener.onAggregateCreated(aggregate1); + // then + verify(child1).onAggregateCreated(aggregate1); + verify(child2).onAggregateCreated(aggregate1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onAggregateCreated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onAggregateDropped() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onAggregateDropped(aggregate1); + // when + listener.onAggregateDropped(aggregate1); + // then + verify(child1).onAggregateDropped(aggregate1); + verify(child2).onAggregateDropped(aggregate1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onAggregateDropped event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onAggregateUpdated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onAggregateUpdated(aggregate1, aggregate2); + // when + listener.onAggregateUpdated(aggregate1, aggregate2); + // then + verify(child1).onAggregateUpdated(aggregate1, aggregate2); + verify(child2).onAggregateUpdated(aggregate1, aggregate2); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onAggregateUpdated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onViewCreated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onViewCreated(view1); + // when + listener.onViewCreated(view1); + // then + verify(child1).onViewCreated(view1); + verify(child2).onViewCreated(view1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onViewCreated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onViewDropped() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onViewDropped(view1); + // when + listener.onViewDropped(view1); + // then + verify(child1).onViewDropped(view1); + verify(child2).onViewDropped(view1); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onViewDropped event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onViewUpdated() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onViewUpdated(view1, view2); + // when + listener.onViewUpdated(view1, view2); + // then + verify(child1).onViewUpdated(view1, view2); + verify(child2).onViewUpdated(view1, view2); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onViewUpdated event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onSessionReady() { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + willThrow(new NullPointerException()).given(child1).onSessionReady(session); + // when + listener.onSessionReady(session); + // then + verify(child1).onSessionReady(session); + verify(child2).onSessionReady(session); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while notifying schema change listener child1 of an onSessionReady event. (NullPointerException: null)"); + } + + @Test + public void should_notify_close() throws Exception { + // given + MultiplexingSchemaChangeListener listener = + new MultiplexingSchemaChangeListener(child1, child2); + Exception child1Error = new NullPointerException(); + willThrow(child1Error).given(child1).close(); + // when + listener.close(); + // then + verify(child1).close(); + verify(child2).close(); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while closing schema change listener child1. (NullPointerException: null)"); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTrackerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTrackerTest.java new file mode 100644 index 00000000000..6e65aeafb5f --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTrackerTest.java @@ -0,0 +1,211 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.tracker; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.verify; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import com.datastax.oss.driver.api.core.DriverExecutionException; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.api.core.tracker.RequestTracker; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.LoggerFactory; + +@RunWith(MockitoJUnitRunner.Strict.class) +public class MultiplexingRequestTrackerTest { + + @Mock private RequestTracker child1; + @Mock private RequestTracker child2; + @Mock private Request request; + @Mock private DriverExecutionProfile profile; + @Mock private Node node; + @Mock private Session session; + + @Mock private Appender appender; + @Captor private ArgumentCaptor loggingEventCaptor; + + private Logger logger; + private Level initialLogLevel; + + private final Exception error = new DriverExecutionException(new NullPointerException()); + + @Before + public void addAppenders() { + logger = (Logger) LoggerFactory.getLogger(MultiplexingRequestTracker.class); + initialLogLevel = logger.getLevel(); + logger.setLevel(Level.WARN); + logger.addAppender(appender); + } + + @After + public void removeAppenders() { + logger.detachAppender(appender); + logger.setLevel(initialLogLevel); + } + + @Test + public void should_register() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(); + // when + tracker.register(child1); + tracker.register(child2); + // then + assertThat(tracker).extracting("trackers").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_flatten_child_multiplexing_tracker_via_constructor() { + // given + MultiplexingRequestTracker tracker = + new MultiplexingRequestTracker(new MultiplexingRequestTracker(child1, child2)); + // when + // then + assertThat(tracker).extracting("trackers").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_flatten_child_multiplexing_tracker_via_register() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(); + // when + tracker.register(new MultiplexingRequestTracker(child1, child2)); + // then + assertThat(tracker).extracting("trackers").asList().hasSize(2).contains(child1, child2); + } + + @Test + public void should_notify_onSuccess() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(child1, child2); + willThrow(new NullPointerException()) + .given(child1) + .onSuccess(request, 123456L, profile, node, "test"); + // when + tracker.onSuccess(request, 123456L, profile, node, "test"); + // then + verify(child1).onSuccess(request, 123456L, profile, node, "test"); + verify(child2).onSuccess(request, 123456L, profile, node, "test"); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "[test] Unexpected error while notifying request tracker child1 of an onSuccess event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onError() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(child1, child2); + willThrow(new NullPointerException()) + .given(child1) + .onError(request, error, 123456L, profile, node, "test"); + // when + tracker.onError(request, error, 123456L, profile, node, "test"); + // then + verify(child1).onError(request, error, 123456L, profile, node, "test"); + verify(child2).onError(request, error, 123456L, profile, node, "test"); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "[test] Unexpected error while notifying request tracker child1 of an onError event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onNodeSuccess() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(child1, child2); + willThrow(new NullPointerException()) + .given(child1) + .onNodeSuccess(request, 123456L, profile, node, "test"); + // when + tracker.onNodeSuccess(request, 123456L, profile, node, "test"); + // then + verify(child1).onNodeSuccess(request, 123456L, profile, node, "test"); + verify(child2).onNodeSuccess(request, 123456L, profile, node, "test"); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "[test] Unexpected error while notifying request tracker child1 of an onNodeSuccess event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onNodeError() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(child1, child2); + willThrow(new NullPointerException()) + .given(child1) + .onNodeError(request, error, 123456L, profile, node, "test"); + // when + tracker.onNodeError(request, error, 123456L, profile, node, "test"); + // then + verify(child1).onNodeError(request, error, 123456L, profile, node, "test"); + verify(child2).onNodeError(request, error, 123456L, profile, node, "test"); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "[test] Unexpected error while notifying request tracker child1 of an onNodeError event. (NullPointerException: null)"); + } + + @Test + public void should_notify_onSessionReady() { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(child1, child2); + willThrow(new NullPointerException()).given(child1).onSessionReady(session); + given(session.getName()).willReturn("test"); + // when + tracker.onSessionReady(session); + // then + verify(child1).onSessionReady(session); + verify(child2).onSessionReady(session); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "[test] Unexpected error while notifying request tracker child1 of an onSessionReady event. (NullPointerException: null)"); + } + + @Test + public void should_notify_close() throws Exception { + // given + MultiplexingRequestTracker tracker = new MultiplexingRequestTracker(child1, child2); + Exception child1Error = new NullPointerException(); + willThrow(child1Error).given(child1).close(); + // when + tracker.close(); + // then + verify(child1).close(); + verify(child2).close(); + verify(appender).doAppend(loggingEventCaptor.capture()); + assertThat(loggingEventCaptor.getAllValues().stream().map(ILoggingEvent::getFormattedMessage)) + .contains( + "Unexpected error while closing request tracker child1. (NullPointerException: null)"); + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java index db3c56bceac..fcafd262a91 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/config/DriverConfigValidationIT.java @@ -24,6 +24,7 @@ import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import java.util.Collections; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -44,27 +45,43 @@ public void should_fail_to_init_with_invalid_policy() { should_fail_to_init_with_invalid_policy(DefaultDriverOption.AUTH_PROVIDER_CLASS); should_fail_to_init_with_invalid_policy(DefaultDriverOption.SSL_ENGINE_FACTORY_CLASS); should_fail_to_init_with_invalid_policy(DefaultDriverOption.TIMESTAMP_GENERATOR_CLASS); - should_fail_to_init_with_invalid_policy(DefaultDriverOption.REQUEST_TRACKER_CLASS); should_fail_to_init_with_invalid_policy(DefaultDriverOption.REQUEST_THROTTLER_CLASS); - should_fail_to_init_with_invalid_policy(DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASS); - should_fail_to_init_with_invalid_policy( - DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASS); should_fail_to_init_with_invalid_policy(DefaultDriverOption.ADDRESS_TRANSLATOR_CLASS); } + @Test + public void should_fail_to_init_with_invalid_components() { + should_fail_to_init_with_invalid_components(DefaultDriverOption.REQUEST_TRACKER_CLASSES); + should_fail_to_init_with_invalid_components( + DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASSES); + should_fail_to_init_with_invalid_components( + DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASSES); + } + private void should_fail_to_init_with_invalid_policy(DefaultDriverOption option) { DriverConfigLoader loader = SessionUtils.configLoaderBuilder().withString(option, "AClassThatDoesNotExist").build(); + assertConfigError(option, loader); + } + + private void should_fail_to_init_with_invalid_components(DefaultDriverOption option) { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withStringList(option, Collections.singletonList("AClassThatDoesNotExist")) + .build(); + assertConfigError(option, loader); + } + + private void assertConfigError(DefaultDriverOption option, DriverConfigLoader loader) { assertThatThrownBy(() -> SessionUtils.newSession(SIMULACRON_RULE, loader)) .satisfies( - error -> { - assertThat(error) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining( - "Can't find class AClassThatDoesNotExist " - + "(specified by " - + option.getPath() - + ")"); - }); + error -> + assertThat(error) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining( + "Can't find class AClassThatDoesNotExist " + + "(specified by " + + option.getPath() + + ")")); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java index 0c6bbe3e061..690c00a0e9b 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java @@ -20,15 +20,22 @@ import static org.mockito.Mockito.verify; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.api.core.metadata.NodeStateListenerBase; import com.datastax.oss.driver.api.core.metadata.SafeInitNodeStateListener; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; +import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListenerBase; +import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Collections; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -47,30 +54,146 @@ public class ListenersIT { public static final SimulacronRule SIMULACRON_RULE = new SimulacronRule(ClusterSpec.builder().withNodes(1)); - @Mock private NodeStateListener nodeListener; - @Mock private SchemaChangeListener schemaListener; - @Mock private RequestTracker requestTracker; - @Captor private ArgumentCaptor nodeCaptor; + @Mock private NodeStateListener nodeListener1; + @Mock private NodeStateListener nodeListener2; + @Mock private SchemaChangeListener schemaListener1; + @Mock private SchemaChangeListener schemaListener2; + @Mock private RequestTracker requestTracker1; + @Mock private RequestTracker requestTracker2; + + @Captor private ArgumentCaptor nodeCaptor1; + @Captor private ArgumentCaptor nodeCaptor2; @Test - public void should_inject_session_in_listeners() { + public void should_inject_session_in_listeners() throws Exception { try (CqlSession session = (CqlSession) SessionUtils.baseBuilder() .addContactEndPoints(SIMULACRON_RULE.getContactPoints()) - .withNodeStateListener(new SafeInitNodeStateListener(nodeListener, true)) - .withSchemaChangeListener(schemaListener) - .withRequestTracker(requestTracker) + .addNodeStateListener(new SafeInitNodeStateListener(nodeListener1, true)) + .addNodeStateListener(new SafeInitNodeStateListener(nodeListener2, true)) + .addSchemaChangeListener(schemaListener1) + .addSchemaChangeListener(schemaListener2) + .addRequestTracker(requestTracker1) + .addRequestTracker(requestTracker2) + .withConfigLoader( + SessionUtils.configLoaderBuilder() + .withClassList( + DefaultDriverOption.METADATA_NODE_STATE_LISTENER_CLASSES, + Collections.singletonList(MyNodeStateListener.class)) + .withClassList( + DefaultDriverOption.METADATA_SCHEMA_CHANGE_LISTENER_CLASSES, + Collections.singletonList(MySchemaChangeListener.class)) + .withClassList( + DefaultDriverOption.REQUEST_TRACKER_CLASSES, + Collections.singletonList(MyRequestTracker.class)) + .build()) .build()) { - InOrder inOrder = inOrder(nodeListener); - inOrder.verify(nodeListener).onSessionReady(session); - inOrder.verify(nodeListener).onUp(nodeCaptor.capture()); - assertThat(nodeCaptor.getValue().getEndPoint()) + InOrder inOrder1 = inOrder(nodeListener1); + inOrder1.verify(nodeListener1).onSessionReady(session); + inOrder1.verify(nodeListener1).onUp(nodeCaptor1.capture()); + + InOrder inOrder2 = inOrder(nodeListener2); + inOrder2.verify(nodeListener2).onSessionReady(session); + inOrder2.verify(nodeListener2).onUp(nodeCaptor2.capture()); + + assertThat(nodeCaptor1.getValue().getEndPoint()) + .isEqualTo(SIMULACRON_RULE.getContactPoints().iterator().next()); + + assertThat(nodeCaptor2.getValue().getEndPoint()) .isEqualTo(SIMULACRON_RULE.getContactPoints().iterator().next()); - verify(schemaListener).onSessionReady(session); - verify(requestTracker).onSessionReady(session); + verify(schemaListener1).onSessionReady(session); + verify(schemaListener2).onSessionReady(session); + + verify(requestTracker1).onSessionReady(session); + verify(requestTracker2).onSessionReady(session); + + assertThat(MyNodeStateListener.onSessionReadyCalled).isTrue(); + assertThat(MyNodeStateListener.onUpCalled).isTrue(); + + assertThat(MySchemaChangeListener.onSessionReadyCalled).isTrue(); + + assertThat(MyRequestTracker.onSessionReadyCalled).isTrue(); + } + + verify(nodeListener1).close(); + verify(nodeListener2).close(); + + verify(schemaListener1).close(); + verify(schemaListener2).close(); + + verify(requestTracker1).close(); + verify(requestTracker2).close(); + + assertThat(MyNodeStateListener.closeCalled).isTrue(); + assertThat(MySchemaChangeListener.closeCalled).isTrue(); + assertThat(MyRequestTracker.closeCalled).isTrue(); + } + + public static class MyNodeStateListener extends SafeInitNodeStateListener { + + private static volatile boolean onSessionReadyCalled = false; + private static volatile boolean onUpCalled = false; + private static volatile boolean closeCalled = false; + + public MyNodeStateListener(@SuppressWarnings("unused") DriverContext ignored) { + super( + new NodeStateListenerBase() { + + @Override + public void onSessionReady(@NonNull Session session) { + onSessionReadyCalled = true; + } + + @Override + public void onUp(@NonNull Node node) { + onUpCalled = true; + } + + @Override + public void close() { + closeCalled = true; + } + }, + true); + } + } + + public static class MySchemaChangeListener extends SchemaChangeListenerBase { + + private static volatile boolean onSessionReadyCalled = false; + private static volatile boolean closeCalled = false; + + public MySchemaChangeListener(@SuppressWarnings("unused") DriverContext ignored) {} + + @Override + public void onSessionReady(@NonNull Session session) { + onSessionReadyCalled = true; + } + + @Override + public void close() throws Exception { + closeCalled = true; + } + } + + public static class MyRequestTracker implements RequestTracker { + + private static volatile boolean onSessionReadyCalled = false; + private static volatile boolean closeCalled = false; + + public MyRequestTracker(@SuppressWarnings("unused") DriverContext ignored) {} + + @Override + public void onSessionReady(@NonNull Session session) { + onSessionReadyCalled = true; + } + + @Override + public void close() throws Exception { + closeCalled = true; } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java index e67d0fdc462..41a462ae1c8 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java @@ -45,6 +45,7 @@ import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import com.datastax.oss.simulacron.common.codec.ConsistencyLevel; import java.time.Duration; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; @@ -88,7 +89,9 @@ public class RequestLoggerIT { private final DriverConfigLoader requestLoader = SessionUtils.configLoaderBuilder() - .withClass(DefaultDriverOption.REQUEST_TRACKER_CLASS, RequestLogger.class) + .withClassList( + DefaultDriverOption.REQUEST_TRACKER_CLASSES, + Collections.singletonList(RequestLogger.class)) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_SUCCESS_ENABLED, true) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_SLOW_ENABLED, true) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_ERROR_ENABLED, true) @@ -115,12 +118,14 @@ public class RequestLoggerIT { .withBoolean(DefaultDriverOption.REQUEST_LOGGER_STACK_TRACES, false) .build(); - private SessionRule sessionRuleRequest = + private final SessionRule sessionRuleRequest = SessionRule.builder(simulacronRule).withConfigLoader(requestLoader).build(); private final DriverConfigLoader nodeLoader = SessionUtils.configLoaderBuilder() - .withClass(DefaultDriverOption.REQUEST_TRACKER_CLASS, RequestNodeLoggerExample.class) + .withClassList( + DefaultDriverOption.REQUEST_TRACKER_CLASSES, + Collections.singletonList(RequestNodeLoggerExample.class)) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_SUCCESS_ENABLED, true) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_SLOW_ENABLED, true) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_ERROR_ENABLED, true) @@ -150,14 +155,16 @@ public class RequestLoggerIT { DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS, SortingLoadBalancingPolicy.class) .build(); - private SessionRule sessionRuleNode = + private final SessionRule sessionRuleNode = SessionRule.builder(simulacronRule).withConfigLoader(nodeLoader).build(); - private SessionRule sessionRuleDefaults = + private final SessionRule sessionRuleDefaults = SessionRule.builder(simulacronRule) .withConfigLoader( SessionUtils.configLoaderBuilder() - .withClass(DefaultDriverOption.REQUEST_TRACKER_CLASS, RequestLogger.class) + .withClassList( + DefaultDriverOption.REQUEST_TRACKER_CLASSES, + Collections.singletonList(RequestLogger.class)) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_SUCCESS_ENABLED, true) .withBoolean(DefaultDriverOption.REQUEST_LOGGER_ERROR_ENABLED, true) .startProfile("low-threshold") diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index fb5780a30ff..455313758c6 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -7,7 +7,7 @@ actively connected). * [Node] instances are mutable, the fields will update in real time. * getting notifications: - [CqlSession.builder().withNodeStateListener][SessionBuilder.withNodeStateListener]. + [CqlSession.builder().addNodeStateListener][SessionBuilder.addNodeStateListener]. ----- @@ -59,8 +59,10 @@ Object rawDseVersion = node.getExtras().get(DseNodeProperties.DSE_VERSION); Version dseVersion = (rawDseVersion == null) ? null : (Version) rawDseVersion; ``` +### Notifications + If you need to follow node state changes, you don't need to poll the metadata manually; instead, -you can register a listener to get notified when changes occur: +you can register one or more listeners to get notified when changes occur: ```java NodeStateListener listener = @@ -71,13 +73,28 @@ NodeStateListener listener = } }; CqlSession session = CqlSession.builder() - .withNodeStateListener(listener) + .addNodeStateListener(listener) .build(); ``` See [NodeStateListener] for the list of available methods. [NodeStateListenerBase] is a convenience implementation with empty methods, for when you only need to override a few of them. +It is also possible to register one or more listeners via the configuration: + +```hocon +datastax-java-driver { + advanced { + node-state-listener.classes = [com.example.app.MyNodeStateListener1,com.example.app.MyNodeStateListener2] + } +} +``` + +Listeners registered via configuration will be instantiated with reflection; they must have a public +constructor taking a `DriverContext` argument. + +The two registration methods (programmatic and via the configuration) can be used simultaneously. + ### Advanced topics #### Forcing a node down @@ -124,5 +141,5 @@ the source code. [NodeState]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeState.html [NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html [NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.withNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- [DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index 43a3ec1880a..f9e1f762a23 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -6,7 +6,7 @@ * immutable (must invoke again to observe changes). * getting notifications: - [CqlSession.builder().withSchemaChangeListener][SessionBuilder#withSchemaChangeListener]. + [CqlSession.builder().addSchemaChangeListener][SessionBuilder#addSchemaChangeListener]. * enabling/disabling: `advanced.metadata.schema.enabled` in the configuration, or [session.setSchemaMetadataEnabled()][Session#setSchemaMetadataEnabled]. * filtering: `advanced.metadata.schema.refreshed-keyspaces` in the configuration. @@ -70,7 +70,7 @@ All other types (keyspaces, tables, etc.) are identical to their OSS counterpart ### Notifications If you need to follow schema changes, you don't need to poll the metadata manually; instead, -you can register a listener to get notified when changes occur: +you can register one or more listeners to get notified when changes occur: ```java SchemaChangeListener listener = @@ -81,7 +81,7 @@ SchemaChangeListener listener = } }; CqlSession session = CqlSession.builder() - .withSchemaChangeListener(listener) + .addSchemaChangeListener(listener) .build(); session.execute("CREATE TABLE test.foo (k int PRIMARY KEY)"); @@ -90,6 +90,20 @@ session.execute("CREATE TABLE test.foo (k int PRIMARY KEY)"); See [SchemaChangeListener] for the list of available methods. [SchemaChangeListenerBase] is a convenience implementation with empty methods, for when you only need to override a few of them. +It is also possible to register one or more listeners via the configuration: + +```hocon +datastax-java-driver { + advanced { + schema-change-listener.classes = [com.example.app.MySchemaChangeListener1,com.example.app.MySchemaChangeListener2] + } +} +``` + +Listeners registered via configuration will be instantiated with reflection; they must have a public +constructor taking a `DriverContext` argument. + +The two registration methods (programmatic and via the configuration) can be used simultaneously. ### Configuration @@ -312,7 +326,7 @@ take a look at the [Performance](../../performance/#schema-updates) page for a f [SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html [Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- [Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#withSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- [ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- [com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html [DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index 4aa9fff0404..e1c9c1d6345 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -7,7 +7,7 @@ Callback that gets invoked for every request: success or error, globally and for * `advanced.request-tracker` in the configuration; defaults to none, also available: request logger, or write your own. * or programmatically: - [CqlSession.builder().withRequestTracker()][SessionBuilder.withRequestTracker]. + [CqlSession.builder().addRequestTracker()][SessionBuilder.addRequestTracker]. ----- @@ -16,28 +16,34 @@ every application request. The driver comes with an optional implementation that ### Configuration -The tracker is enabled in the [configuration](../configuration/). The default implementation does -nothing: +Request trackers can be declared in the [configuration](../configuration/) as follows: ``` datastax-java-driver.advanced.request-tracker { - class = NoopRequestTracker + classes = [com.example.app.MyTracker1,com.example.app.MyTracker2] } ``` -To use a different tracker, specify the name of a class that implements [RequestTracker]. One such -class is the built-in request logger (see the next section), you can also create your own -implementation. +By default, no tracker is registered. To register your own trackers, specify the name of a class +that implements [RequestTracker]. One such class is the built-in request logger (see the next +section), but you can also create your own implementation. + +Also, trackers registered via configuration will be instantiated with reflection; they must have a +public constructor taking a `DriverContext` argument. Sometimes you have a tracker instance already in your code, and need to pass it programmatically instead of referencing a class. The session builder has a method for that: ```java -RequestTracker myTracker = ...; -CqlSession session = CqlSession.builder().withRequestTracker(myTracker).build(); +RequestTracker myTracker1 = ...; +RequestTracker myTracker2 = ...; +CqlSession session = CqlSession.builder() + .addRequestTracker(myTracker1) + .addRequestTracker(myTracker2) + .build(); ``` -When you provide the tracker in this manner, the configuration will be ignored. +The two registration methods (programmatic and via the configuration) can be used simultaneously. ### Request logger @@ -46,7 +52,7 @@ requests as "slow" above a given threshold, limit the line size for large querie ``` datastax-java-driver.advanced.request-tracker { - class = RequestLogger + classes = [RequestLogger] logs { # Whether to log successful requests. @@ -118,4 +124,4 @@ com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined c ``` [RequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.withRequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 4e0de35703c..c2fc9c13981 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,68 @@ ## Upgrade guide +### 4.13.0 + +#### Registration of multiple listeners and trackers + +[JAVA-2951](https://datastax-oss.atlassian.net/browse/JAVA-2951) introduced the ability to register +more than one instance of the following interfaces: + +* [RequestTracker](https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/tracker/RequestTracker.html) +* [NodeStateListener](https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html) +* [SchemaChangeListener](https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html) + +Multiple components can now be registered both programmatically and through the configuration. _If +both approaches are used, components will add up and will all be registered_ (whereas previously, +the programmatic approach would take precedence over the configuration one). + +When using the programmatic approach to register multiple components, you should use the new +`SessionBuilder` methods `addRequestTracker`, `addNodeStateListener` and `addSchemaChangeListener`: + +```java +CqlSessionBuilder builder = CqlSession.builder(); +builder + .addRequestTracker(tracker1) + .addRequestTracker(tracker2); +builder + .addNodeStateListener(nodeStateListener1) + .addNodeStateListener(nodeStateListener2); +builder + .addSchemaChangeListener(schemaChangeListener1) + .addSchemaChangeListener(schemaChangeListener2); +``` + +To support registration of multiple components through the configuration, the following +configuration options were deprecated because they only allow one component to be declared: + +* `advanced.request-tracker.class` +* `advanced.node-state-listener.class` +* `advanced.schema-change-listener.class` + +They are still honored, but the driver will log a warning if they are used. They should now be +replaced with the following ones, that accept a list of classes to instantiate, instead of just +one: + +* `advanced.request-tracker.classes` +* `advanced.node-state-listener.classes` +* `advanced.schema-change-listener.classes` + +Example: + +```hocon +datastax-java-driver { + advanced { + # RequestLogger is a driver built-in tracker + request-tracker.classes = [RequestLogger,com.example.app.MyRequestTracker] + node-state-listener.classes = [com.example.app.MyNodeStateListener1,com.example.app.MyNodeStateListener2] + schema-change-listener.classes = [com.example.app.MySchemaChangeListener] + } +} +``` + +When more than one component of the same type is registered, the driver will distribute received +signals to all components in sequence, by order of their registration, starting with the +programmatically-provided ones. If a component throws an error, the error is intercepted and logged. + ### 4.12.0 #### MicroProfile Metrics upgraded to 3.0 From 7e74450ebe9d70136b164a5679ba8e40b8cc0b9e Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 29 Jul 2021 18:51:28 +0200 Subject: [PATCH 171/395] JAVA-2953: Promote ProgrammaticPlainTextAuthProvider to the public API and add credentials hot-reload (#1564) --- changelog/README.md | 2 + .../DseProgrammaticPlainTextAuthProvider.java | 32 ----- .../core/auth/PlainTextAuthProviderBase.java | 6 +- .../ProgrammaticPlainTextAuthProvider.java | 134 ++++++++++++++++++ .../api/core/session/SessionBuilder.java | 2 +- .../core/auth/PlainTextAuthProvider.java | 6 +- .../ProgrammaticPlainTextAuthProvider.java | 66 --------- .../driver/internal/core/util/Strings.java | 16 +++ ...ProgrammaticPlainTextAuthProviderTest.java | 99 +++++++++++++ .../core/auth/PlainTextAuthProviderIT.java | 52 ++++++- manual/core/authentication/README.md | 23 ++- 11 files changed, 330 insertions(+), 108 deletions(-) delete mode 100644 core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseProgrammaticPlainTextAuthProvider.java create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/auth/ProgrammaticPlainTextAuthProvider.java create mode 100644 core/src/test/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProviderTest.java diff --git a/changelog/README.md b/changelog/README.md index ed90fea7c97..014d4f97835 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,8 @@ ### 4.13.0 (in progress) +- [improvement] JAVA-2953: Promote ProgrammaticPlainTextAuthProvider to the public API and add + credentials hot-reload - [improvement] JAVA-2951: Accept multiple node state listeners, schema change listeners and request trackers Merged from 4.12.x: diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseProgrammaticPlainTextAuthProvider.java b/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseProgrammaticPlainTextAuthProvider.java deleted file mode 100644 index a8feb1cd2ba..00000000000 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/auth/DseProgrammaticPlainTextAuthProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.dse.driver.internal.core.auth; - -import com.datastax.oss.driver.internal.core.auth.ProgrammaticPlainTextAuthProvider; - -/** - * @deprecated The driver's default plain text providers now support both Apache Cassandra and DSE. - * This type was preserved for backward compatibility, but {@link - * ProgrammaticPlainTextAuthProvider} should be used instead. - */ -@Deprecated -public class DseProgrammaticPlainTextAuthProvider extends ProgrammaticPlainTextAuthProvider { - - public DseProgrammaticPlainTextAuthProvider( - String username, String password, String authorizationId) { - super(username, password, authorizationId); - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java b/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java index e3869ba8319..c9241577d6b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java @@ -36,7 +36,8 @@ * Common infrastructure for plain text auth providers. * *

    This can be reused to write an implementation that retrieves the credentials from another - * source than the configuration. + * source than the configuration. The driver offers one built-in implementation: {@link + * ProgrammaticPlainTextAuthProvider}. */ @ThreadSafe public abstract class PlainTextAuthProviderBase implements AuthProvider { @@ -58,6 +59,9 @@ protected PlainTextAuthProviderBase(@NonNull String logPrefix) { * Retrieves the credentials from the underlying source. * *

    This is invoked every time the driver opens a new connection. + * + * @param endPoint The endpoint being contacted. + * @param serverAuthenticator The authenticator class sent by the endpoint. */ @NonNull protected abstract Credentials getCredentials( diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java b/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java new file mode 100644 index 00000000000..7166e72b1f5 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java @@ -0,0 +1,134 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.auth; + +import com.datastax.oss.driver.api.core.metadata.EndPoint; +import com.datastax.oss.driver.api.core.session.SessionBuilder; +import com.datastax.oss.driver.internal.core.util.Strings; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Objects; +import net.jcip.annotations.ThreadSafe; + +/** + * A simple plaintext {@link AuthProvider} that receives the credentials programmatically instead of + * pulling them from the configuration. + * + *

    To use this class, create an instance with the appropriate credentials to use and pass it to + * your session builder: + * + *

    + * AuthProvider authProvider = new ProgrammaticPlainTextAuthProvider("...", "...");
    + * CqlSession session =
    + *     CqlSession.builder()
    + *         .addContactEndPoints(...)
    + *         .withAuthProvider(authProvider)
    + *         .build();
    + * 
    + * + *

    It also offers the possibility of changing the credentials at runtime. The new credentials + * will be used for all connections initiated after the change. + * + *

    Implementation Note: this implementation is not particularly suited for highly-sensitive + * applications: it stores the credentials to use as private fields, and even if the fields are char + * arrays rather than strings to make it difficult to dump their contents, they are never cleared + * until the provider itself is garbage-collected, which typically only happens when the session is + * closed. + * + * @see SessionBuilder#withAuthProvider(AuthProvider) + * @see SessionBuilder#withAuthCredentials(String, String) + * @see SessionBuilder#withAuthCredentials(String, String, String) + */ +@ThreadSafe +public class ProgrammaticPlainTextAuthProvider extends PlainTextAuthProviderBase { + + private volatile char[] username; + private volatile char[] password; + private volatile char[] authorizationId; + + /** Builds an instance for simple username/password authentication. */ + public ProgrammaticPlainTextAuthProvider(@NonNull String username, @NonNull String password) { + this(username, password, ""); + } + + /** + * Builds an instance for username/password authentication, and proxy authentication with the + * given authorizationId. + * + *

    This feature is only available with Datastax Enterprise. If the target server is Apache + * Cassandra, use {@link #ProgrammaticPlainTextAuthProvider(String, String)} instead, or set the + * authorizationId to an empty string. + */ + public ProgrammaticPlainTextAuthProvider( + @NonNull String username, @NonNull String password, @NonNull String authorizationId) { + // This will typically be built before the session so we don't know the log prefix yet. Pass an + // empty string, it's only used in one log message. + super(""); + this.username = Strings.requireNotEmpty(username, "username").toCharArray(); + this.password = Strings.requireNotEmpty(password, "password").toCharArray(); + this.authorizationId = + Objects.requireNonNull(authorizationId, "authorizationId cannot be null").toCharArray(); + } + + /** + * Changes the username. + * + *

    The new credentials will be used for all connections initiated after this method was called. + * + * @param username the new name. + */ + public void setUsername(@NonNull String username) { + this.username = Strings.requireNotEmpty(username, "username").toCharArray(); + } + + /** + * Changes the password. + * + *

    The new credentials will be used for all connections initiated after this method was called. + * + * @param password the new password. + */ + public void setPassword(@NonNull String password) { + this.password = Strings.requireNotEmpty(password, "password").toCharArray(); + } + + /** + * Changes the authorization id. + * + *

    The new credentials will be used for all connections initiated after this method was called. + * + *

    This feature is only available with Datastax Enterprise. If the target server is Apache + * Cassandra, this method should not be used. + * + * @param authorizationId the new authorization id. + */ + public void setAuthorizationId(@NonNull String authorizationId) { + this.authorizationId = + Objects.requireNonNull(authorizationId, "authorizationId cannot be null").toCharArray(); + } + + /** + * {@inheritDoc} + * + *

    This implementation disregards the endpoint being connected to as well as the authenticator + * class sent by the server, and always returns the same credentials. + */ + @NonNull + @Override + protected Credentials getCredentials( + @NonNull EndPoint endPoint, @NonNull String serverAuthenticator) { + return new Credentials(username.clone(), password.clone(), authorizationId.clone()); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index 02070063d3b..966372fa20d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.auth.AuthProvider; import com.datastax.oss.driver.api.core.auth.PlainTextAuthProviderBase; +import com.datastax.oss.driver.api.core.auth.ProgrammaticPlainTextAuthProvider; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; @@ -37,7 +38,6 @@ import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.internal.core.ContactPoints; -import com.datastax.oss.driver.internal.core.auth.ProgrammaticPlainTextAuthProvider; import com.datastax.oss.driver.internal.core.config.cloud.CloudConfig; import com.datastax.oss.driver.internal.core.config.cloud.CloudConfigFactory; import com.datastax.oss.driver.internal.core.config.typesafe.DefaultDriverConfigLoader; diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java b/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java index de951b881f1..73f320bbcdf 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java @@ -46,7 +46,11 @@ * } *

    * - * See {@code reference.conf} (in the manual or core driver JAR) for more details. + * The authentication provider cannot be changed at runtime; however, the credentials can be changed + * at runtime: the new ones will be used for new connection attempts once the configuration gets + * {@linkplain com.datastax.oss.driver.api.core.config.DriverConfigLoader#reload() reloaded}. + * + *

    See {@code reference.conf} (in the manual or core driver JAR) for more details. */ @ThreadSafe public class PlainTextAuthProvider extends PlainTextAuthProviderBase { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/auth/ProgrammaticPlainTextAuthProvider.java b/core/src/main/java/com/datastax/oss/driver/internal/core/auth/ProgrammaticPlainTextAuthProvider.java deleted file mode 100644 index ba0bc4b41db..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/auth/ProgrammaticPlainTextAuthProvider.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.internal.core.auth; - -import com.datastax.oss.driver.api.core.auth.PlainTextAuthProviderBase; -import com.datastax.oss.driver.api.core.metadata.EndPoint; -import com.datastax.oss.driver.api.core.session.SessionBuilder; -import edu.umd.cs.findbugs.annotations.NonNull; -import net.jcip.annotations.ThreadSafe; - -/** - * Alternative plaintext auth provider that receives the credentials programmatically instead of - * pulling them from the configuration. - * - * @see SessionBuilder#withAuthCredentials(String, String) - * @see SessionBuilder#withAuthCredentials(String, String, String) - */ -@ThreadSafe -public class ProgrammaticPlainTextAuthProvider extends PlainTextAuthProviderBase { - private final String username; - private final String password; - private final String authorizationId; - - /** Builds an instance for simple username/password authentication. */ - public ProgrammaticPlainTextAuthProvider(String username, String password) { - this(username, password, ""); - } - - /** - * Builds an instance for username/password authentication, and proxy authentication with the - * given authorizationId. - * - *

    This feature is only available with Datastax Enterprise. If the target server is Apache - * Cassandra, the authorizationId will be ignored. - */ - public ProgrammaticPlainTextAuthProvider( - String username, String password, String authorizationId) { - // This will typically be built before the session so we don't know the log prefix yet. Pass an - // empty string, it's only used in one log message. - super(""); - this.username = username; - this.password = password; - this.authorizationId = authorizationId; - } - - @NonNull - @Override - protected Credentials getCredentials( - @NonNull EndPoint endPoint, @NonNull String serverAuthenticator) { - return new Credentials( - username.toCharArray(), password.toCharArray(), authorizationId.toCharArray()); - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java index b0aa9128c76..7d7aa454971 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Strings.java @@ -18,6 +18,7 @@ import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import java.util.Locale; +import java.util.Objects; public class Strings { @@ -255,6 +256,21 @@ public static boolean isLongLiteral(String str) { return true; } + /** + * Checks whether the given text is not null and not empty. + * + * @param text The text to check. + * @param name The name of the argument. + * @return The text (for method chaining). + */ + public static String requireNotEmpty(String text, String name) { + Objects.requireNonNull(text, name + " cannot be null"); + if (text.isEmpty()) { + throw new IllegalArgumentException(name + " cannot be empty"); + } + return text; + } + private Strings() {} private static final ImmutableSet RESERVED_KEYWORDS = diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProviderTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProviderTest.java new file mode 100644 index 00000000000..d12b2fe1b3a --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProviderTest.java @@ -0,0 +1,99 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.auth; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.auth.PlainTextAuthProviderBase.Credentials; +import com.datastax.oss.driver.api.core.metadata.EndPoint; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.Strict.class) +public class ProgrammaticPlainTextAuthProviderTest { + + @Mock private EndPoint endpoint; + + @Test + public void should_return_correct_credentials_without_authorization_id() { + // given + ProgrammaticPlainTextAuthProvider provider = + new ProgrammaticPlainTextAuthProvider("user", "pass"); + // when + Credentials credentials = provider.getCredentials(endpoint, "irrelevant"); + // then + assertThat(credentials.getUsername()).isEqualTo("user".toCharArray()); + assertThat(credentials.getPassword()).isEqualTo("pass".toCharArray()); + assertThat(credentials.getAuthorizationId()).isEqualTo(new char[0]); + } + + @Test + public void should_return_correct_credentials_with_authorization_id() { + // given + ProgrammaticPlainTextAuthProvider provider = + new ProgrammaticPlainTextAuthProvider("user", "pass", "proxy"); + // when + Credentials credentials = provider.getCredentials(endpoint, "irrelevant"); + // then + assertThat(credentials.getUsername()).isEqualTo("user".toCharArray()); + assertThat(credentials.getPassword()).isEqualTo("pass".toCharArray()); + assertThat(credentials.getAuthorizationId()).isEqualTo("proxy".toCharArray()); + } + + @Test + public void should_change_username() { + // given + ProgrammaticPlainTextAuthProvider provider = + new ProgrammaticPlainTextAuthProvider("user", "pass"); + // when + provider.setUsername("user2"); + Credentials credentials = provider.getCredentials(endpoint, "irrelevant"); + // then + assertThat(credentials.getUsername()).isEqualTo("user2".toCharArray()); + assertThat(credentials.getPassword()).isEqualTo("pass".toCharArray()); + assertThat(credentials.getAuthorizationId()).isEqualTo(new char[0]); + } + + @Test + public void should_change_password() { + // given + ProgrammaticPlainTextAuthProvider provider = + new ProgrammaticPlainTextAuthProvider("user", "pass"); + // when + provider.setPassword("pass2"); + Credentials credentials = provider.getCredentials(endpoint, "irrelevant"); + // then + assertThat(credentials.getUsername()).isEqualTo("user".toCharArray()); + assertThat(credentials.getPassword()).isEqualTo("pass2".toCharArray()); + assertThat(credentials.getAuthorizationId()).isEqualTo(new char[0]); + } + + @Test + public void should_change_authorization_id() { + // given + ProgrammaticPlainTextAuthProvider provider = + new ProgrammaticPlainTextAuthProvider("user", "pass", "proxy"); + // when + provider.setAuthorizationId("proxy2"); + Credentials credentials = provider.getCredentials(endpoint, "irrelevant"); + // then + assertThat(credentials.getUsername()).isEqualTo("user".toCharArray()); + assertThat(credentials.getPassword()).isEqualTo("pass".toCharArray()); + assertThat(credentials.getAuthorizationId()).isEqualTo("proxy2".toCharArray()); + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/auth/PlainTextAuthProviderIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/auth/PlainTextAuthProviderIT.java index 8558f1d650c..4ff36a44755 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/auth/PlainTextAuthProviderIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/auth/PlainTextAuthProviderIT.java @@ -18,13 +18,15 @@ import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.core.auth.AuthProvider; +import com.datastax.oss.driver.api.core.auth.ProgrammaticPlainTextAuthProvider; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.auth.PlainTextAuthProvider; -import com.google.common.util.concurrent.Uninterruptibles; +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import java.util.concurrent.TimeUnit; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -63,7 +65,7 @@ public void should_connect_with_credentials() { @Test public void should_connect_with_programmatic_credentials() { - SessionBuilder builder = + SessionBuilder builder = SessionUtils.baseBuilder() .addContactEndPoints(CCM_RULE.getContactPoints()) .withAuthCredentials("cassandra", "cassandra"); @@ -73,6 +75,26 @@ public void should_connect_with_programmatic_credentials() { } } + @Test + public void should_connect_with_programmatic_provider() { + + AuthProvider authProvider = new ProgrammaticPlainTextAuthProvider("cassandra", "cassandra"); + SessionBuilder builder = + SessionUtils.baseBuilder() + .addContactEndPoints(CCM_RULE.getContactPoints()) + // Open more than one connection in order to validate that the provider is creating + // valid Credentials for every invocation of PlainTextAuthProviderBase.getCredentials. + .withConfigLoader( + SessionUtils.configLoaderBuilder() + .withInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE, 4) + .build()) + .withAuthProvider(authProvider); + + try (CqlSession session = (CqlSession) builder.build()) { + session.execute("select * from system.local"); + } + } + @Test(expected = AllNodesFailedException.class) public void should_not_connect_with_invalid_credentials() { DriverConfigLoader loader = @@ -86,6 +108,32 @@ public void should_not_connect_with_invalid_credentials() { } } + @Test(expected = AllNodesFailedException.class) + public void should_not_connect_with_invalid_programmatic_credentials() { + SessionBuilder builder = + SessionUtils.baseBuilder() + .addContactEndPoints(CCM_RULE.getContactPoints()) + .withAuthCredentials("baduser", "badpass"); + + try (CqlSession session = (CqlSession) builder.build()) { + session.execute("select * from system.local"); + } + } + + @Test(expected = AllNodesFailedException.class) + public void should_not_connect_with_invalid_programmatic_provider() { + + AuthProvider authProvider = new ProgrammaticPlainTextAuthProvider("baduser", "badpass"); + SessionBuilder builder = + SessionUtils.baseBuilder() + .addContactEndPoints(CCM_RULE.getContactPoints()) + .withAuthProvider(authProvider); + + try (CqlSession session = (CqlSession) builder.build()) { + session.execute("select * from system.local"); + } + } + @Test(expected = AllNodesFailedException.class) public void should_not_connect_without_credentials() { try (CqlSession session = SessionUtils.newSession(CCM_RULE)) { diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 9a11ad0a8e0..2a5ee302e09 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -108,8 +108,20 @@ CqlSession session = .build(); ``` -For convenience, there are shortcuts that take the credentials directly. This is equivalent to -using `PlainTextAuthProvider` in the configuration: +The driver also offers a simple, built-in plain text authentication provider: +[ProgrammaticPlainTextAuthProvider]. The following is equivalent to using `PlainTextAuthProvider` in +the configuration: + +```java +AuthProvider authProvider = new ProgrammaticPlainTextAuthProvider("user", "pass"); + +CqlSession session = + CqlSession.builder() + .withAuthProvider(authProvider) + .build(); +``` + +For convenience, there are shortcuts that take the credentials directly: ```java CqlSession session = @@ -124,9 +136,9 @@ CqlSession session = .build(); ``` -One downside of `withAuthCredentials` is that the credentials are stored in clear text in memory; -this means they are vulnerable to an attacker who is able to perform memory dumps. If this is not -acceptable for you, consider writing your own [AuthProvider] implementation; +One downside of the driver's built-in authentication providers is that the credentials are stored in +clear text in memory; this means they are vulnerable to an attacker who is able to perform memory +dumps. If this is not acceptable for you, consider writing your own [AuthProvider] implementation; [PlainTextAuthProviderBase] is a good starting point. Similarly, [ProgrammaticDseGssApiAuthProvider] lets you configure GSSAPI programmatically: @@ -218,6 +230,7 @@ session.execute(statement); [AuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/auth/AuthProvider.html [DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html [PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[ProgrammaticPlainTextAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.html [DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html [ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html [ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- From 7aaa0a2065bad86cb32537dc58f08af1854fc9f0 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 15:12:57 +0200 Subject: [PATCH 172/395] Update changelog for 4.11.3 release --- changelog/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 8f994136575..d08774824c1 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,7 +2,7 @@ -### 4.11.3 (in progress) +### 4.11.3 - [bug] JAVA-2949: Provide mapper support for CompletionStage> - [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck From dd4a6b6628202ea3f4381073fbb7d6a35493ab9f Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 15:16:43 +0200 Subject: [PATCH 173/395] [maven-release-plugin] prepare release 4.11.3 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index f107d8bb9b5..6b4f118624a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-core-shaded - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-mapper-processor - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-mapper-runtime - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-query-builder - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-test-infra - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-metrics-micrometer - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss java-driver-metrics-microprofile - 4.11.3-SNAPSHOT + 4.11.3 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 2dc72176cce..c6ac9e401e2 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 9fcd5642208..d3187f82856 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index b7e5bd41edb..0dc408aa030 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index c2b3a76164f..6587a5d050e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.3-SNAPSHOT + 4.11.3 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index d306d17b365..3c7d2f957ec 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index a8d29a6154f..6cd2206e545 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index dbfda81840e..fc7063ecffb 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 0c4c444bf17..49c35d751b3 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index e5946089c8f..1a7b087473f 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index bb094c7c158..1013e668376 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 2abaa6ce103..c16cc4c10f9 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.11.3 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 601a40ee9d8..405a18d5b59 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 2b23d248516..d0a0c1bd054 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3-SNAPSHOT + 4.11.3 java-driver-test-infra bundle From 508726b9af2d0d7a60ff6ffa5fb7a48c53932e46 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 15:16:53 +0200 Subject: [PATCH 174/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 6b4f118624a..5a6b74123dd 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.11.3 + 4.11.4-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index c6ac9e401e2..e54646d2481 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index d3187f82856..ba63f6d5d86 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 0dc408aa030..fc94a248875 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 6587a5d050e..8838521df56 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.11.3 + 4.11.4-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 3c7d2f957ec..ed859be608d 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 6cd2206e545..327f4ae114b 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index fc7063ecffb..e76da145a0f 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 49c35d751b3..3228a2f962f 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 1a7b087473f..e0e6c6bbde9 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 1013e668376..cb620c33c30 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index c16cc4c10f9..b2406e29c33 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.11.3 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 405a18d5b59..67bc6192b07 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index d0a0c1bd054..12faa3ac8e6 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.11.3 + 4.11.4-SNAPSHOT java-driver-test-infra bundle From 59e7647b98501ae5a88f97d8d4404c89cecd1371 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 15:26:41 +0200 Subject: [PATCH 175/395] Update changelog for 4.12.1 release --- changelog/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 18e34c8591c..c74d6293a3b 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,7 +2,7 @@ -### 4.12.1 (in progress) +### 4.12.1 Merged from 4.11.x: @@ -25,7 +25,7 @@ Merged from 4.11.x: - [bug] JAVA-2943: Prevent session leak with wrong keyspace name - [bug] JAVA-2938: OverloadedException message is misleading -### 4.11.3 (in progress) +### 4.11.3 - [bug] JAVA-2949: Provide mapper support for CompletionStage> - [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck From 57d7abd0707011f794cd0e91acd1c0901d922297 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 15:30:29 +0200 Subject: [PATCH 176/395] [maven-release-plugin] prepare release 4.12.1 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index e47c97e29e3..78b6ec22679 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-core-shaded - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-mapper-processor - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-mapper-runtime - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-query-builder - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-test-infra - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-metrics-micrometer - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss java-driver-metrics-microprofile - 4.13.0-SNAPSHOT + 4.12.1 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 076dbfa6918..a1eab3ebb40 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 34d1b7478b6..fc7abebf8bc 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 2a579b0440a..c5c6e450caf 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index b95827307ad..cad5b2d0df9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.13.0-SNAPSHOT + 4.12.1 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index c5b6cc77594..ef0cb58b58f 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index cc14f3d2e8b..351e591ac4b 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 68d76446bf1..dd55163b126 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 8c2755c7c62..78bfef51110 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 78c04909c55..987eeb739c6 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 12e8b9641dc..75cbab65ce2 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index aa72a4c7c0f..c0c20c8cd08 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.12.1 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 3ae527917a1..a1d378b47ed 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index d29046b4934..0e70ff32d6d 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.12.1 java-driver-test-infra bundle From f9e0d4b08ef0c882c6a6f2ef606303c3ed3912b3 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 15:30:39 +0200 Subject: [PATCH 177/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 78b6ec22679..8d0c87a8760 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.12.1 + 4.12.2-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index a1eab3ebb40..2fd0c88b588 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index fc7abebf8bc..9dac054760c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index c5c6e450caf..8c3b8789f59 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index cad5b2d0df9..8cd1d67153e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.12.1 + 4.12.2-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index ef0cb58b58f..2858b60ab69 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 351e591ac4b..ccfaed89f67 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index dd55163b126..7a73250d3a4 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 78bfef51110..fe0be368d73 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 987eeb739c6..dc51e51c5b4 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 75cbab65ce2..e037bab5b9e 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index c0c20c8cd08..a5d2e268b8a 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -954,7 +954,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.12.1 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index a1d378b47ed..eb4ac4c809f 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 0e70ff32d6d..76b95bef301 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.12.1 + 4.12.2-SNAPSHOT java-driver-test-infra bundle From 4270f93277249abb513bc2abf2ff7a7c481b1d0d Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 30 Jul 2021 09:40:43 -0500 Subject: [PATCH 178/395] JAVA-2940: Add GraalVM native image build configurations (#1560) --- changelog/README.md | 1 + core-shaded/pom.xml | 33 +- .../internal/core/channel/ChannelFactory.java | 197 ++++++----- .../java-driver-core/native-image.properties | 7 + .../java-driver-core/proxy.json | 3 + .../java-driver-core/reflection.json | 154 +++++++++ manual/core/compression/README.md | 3 +- manual/core/graalvm/README.md | 315 ++++++++++++++++++ manual/core/integration/README.md | 2 + .../native-image.properties | 1 + .../reflection.json | 6 + .../native-image.properties | 1 + .../reflection.json | 6 + pom.xml | 1 + 14 files changed, 641 insertions(+), 89 deletions(-) create mode 100644 core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties create mode 100644 core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/proxy.json create mode 100644 core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/reflection.json create mode 100644 manual/core/graalvm/README.md create mode 100644 metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties create mode 100644 metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/reflection.json create mode 100644 metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties create mode 100644 metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/reflection.json diff --git a/changelog/README.md b/changelog/README.md index 014d4f97835..7bae766a602 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,6 +4,7 @@ ### 4.13.0 (in progress) +- [improvement] JAVA-2940: Add GraalVM native image build configurations - [improvement] JAVA-2953: Promote ProgrammaticPlainTextAuthProvider to the public API and add credentials hot-reload - [improvement] JAVA-2951: Accept multiple node state listeners, schema change listeners and request trackers diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 076dbfa6918..ad368ee9259 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -148,6 +148,10 @@ + io.netty com.datastax.oss.driver.shaded.netty @@ -174,7 +178,9 @@ com.datastax.oss:* - META-INF/** + + META-INF/MANIFEST.MF + META-INF/maven/** @@ -253,6 +259,31 @@ + + + com.google.code.maven-replacer-plugin + replacer + 1.5.3 + + + shade-graalvm-files + package + + replace + + + + + false + ${project.build.directory}/classes/META-INF/native-image/com.datastax.oss/java-driver-core/reflection.json,${project.build.directory}/shaded-sources/META-INF/native-image/com.datastax.oss/java-driver-core/reflection.json + + + io.netty + com.datastax.oss.driver.shaded.netty + + + + maven-javadoc-plugin diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java index 4e2defdce49..f2363cbd29c 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java @@ -272,98 +272,121 @@ ChannelInitializer initializer( DriverChannelOptions options, NodeMetricUpdater nodeMetricUpdater, CompletableFuture resultFuture) { - return new ChannelInitializer() { - @Override - protected void initChannel(Channel channel) { - try { - DriverExecutionProfile defaultConfig = context.getConfig().getDefaultProfile(); - - long setKeyspaceTimeoutMillis = - defaultConfig - .getDuration(DefaultDriverOption.CONNECTION_SET_KEYSPACE_TIMEOUT) - .toMillis(); - int maxFrameLength = - (int) defaultConfig.getBytes(DefaultDriverOption.PROTOCOL_MAX_FRAME_LENGTH); - int maxRequestsPerConnection = - defaultConfig.getInt(DefaultDriverOption.CONNECTION_MAX_REQUESTS); - int maxOrphanRequests = - defaultConfig.getInt(DefaultDriverOption.CONNECTION_MAX_ORPHAN_REQUESTS); - if (maxOrphanRequests >= maxRequestsPerConnection) { - if (LOGGED_ORPHAN_WARNING.compareAndSet(false, true)) { - LOG.warn( - "[{}] Invalid value for {}: {}. It must be lower than {}. " - + "Defaulting to {} (1/4 of max-requests) instead.", - logPrefix, - DefaultDriverOption.CONNECTION_MAX_ORPHAN_REQUESTS.getPath(), - maxOrphanRequests, - DefaultDriverOption.CONNECTION_MAX_REQUESTS.getPath(), - maxRequestsPerConnection / 4); - } - maxOrphanRequests = maxRequestsPerConnection / 4; - } + return new ChannelFactoryInitializer( + endPoint, protocolVersion, options, nodeMetricUpdater, resultFuture); + }; + + class ChannelFactoryInitializer extends ChannelInitializer { + + private final EndPoint endPoint; + private final ProtocolVersion protocolVersion; + private final DriverChannelOptions options; + private final NodeMetricUpdater nodeMetricUpdater; + private final CompletableFuture resultFuture; + + ChannelFactoryInitializer( + EndPoint endPoint, + ProtocolVersion protocolVersion, + DriverChannelOptions options, + NodeMetricUpdater nodeMetricUpdater, + CompletableFuture resultFuture) { + + this.endPoint = endPoint; + this.protocolVersion = protocolVersion; + this.options = options; + this.nodeMetricUpdater = nodeMetricUpdater; + this.resultFuture = resultFuture; + } - InFlightHandler inFlightHandler = - new InFlightHandler( - protocolVersion, - new StreamIdGenerator(maxRequestsPerConnection), - maxOrphanRequests, - setKeyspaceTimeoutMillis, - channel.newPromise(), - options.eventCallback, - options.ownerLogPrefix); - HeartbeatHandler heartbeatHandler = new HeartbeatHandler(defaultConfig); - ProtocolInitHandler initHandler = - new ProtocolInitHandler( - context, - protocolVersion, - clusterName, - endPoint, - options, - heartbeatHandler, - productType == null); - - ChannelPipeline pipeline = channel.pipeline(); - context - .getSslHandlerFactory() - .map(f -> f.newSslHandler(channel, endPoint)) - .map(h -> pipeline.addLast(SSL_HANDLER_NAME, h)); - - // Only add meter handlers on the pipeline if metrics are enabled. - SessionMetricUpdater sessionMetricUpdater = - context.getMetricsFactory().getSessionUpdater(); - if (nodeMetricUpdater.isEnabled(DefaultNodeMetric.BYTES_RECEIVED, null) - || sessionMetricUpdater.isEnabled(DefaultSessionMetric.BYTES_RECEIVED, null)) { - pipeline.addLast( - INBOUND_TRAFFIC_METER_NAME, - new InboundTrafficMeter(nodeMetricUpdater, sessionMetricUpdater)); + @Override + protected void initChannel(Channel channel) { + try { + DriverExecutionProfile defaultConfig = context.getConfig().getDefaultProfile(); + + long setKeyspaceTimeoutMillis = + defaultConfig + .getDuration(DefaultDriverOption.CONNECTION_SET_KEYSPACE_TIMEOUT) + .toMillis(); + int maxFrameLength = + (int) defaultConfig.getBytes(DefaultDriverOption.PROTOCOL_MAX_FRAME_LENGTH); + int maxRequestsPerConnection = + defaultConfig.getInt(DefaultDriverOption.CONNECTION_MAX_REQUESTS); + int maxOrphanRequests = + defaultConfig.getInt(DefaultDriverOption.CONNECTION_MAX_ORPHAN_REQUESTS); + if (maxOrphanRequests >= maxRequestsPerConnection) { + if (LOGGED_ORPHAN_WARNING.compareAndSet(false, true)) { + LOG.warn( + "[{}] Invalid value for {}: {}. It must be lower than {}. " + + "Defaulting to {} (1/4 of max-requests) instead.", + logPrefix, + DefaultDriverOption.CONNECTION_MAX_ORPHAN_REQUESTS.getPath(), + maxOrphanRequests, + DefaultDriverOption.CONNECTION_MAX_REQUESTS.getPath(), + maxRequestsPerConnection / 4); } + maxOrphanRequests = maxRequestsPerConnection / 4; + } - if (nodeMetricUpdater.isEnabled(DefaultNodeMetric.BYTES_SENT, null) - || sessionMetricUpdater.isEnabled(DefaultSessionMetric.BYTES_SENT, null)) { - pipeline.addLast( - OUTBOUND_TRAFFIC_METER_NAME, - new OutboundTrafficMeter(nodeMetricUpdater, sessionMetricUpdater)); - } + InFlightHandler inFlightHandler = + new InFlightHandler( + protocolVersion, + new StreamIdGenerator(maxRequestsPerConnection), + maxOrphanRequests, + setKeyspaceTimeoutMillis, + channel.newPromise(), + options.eventCallback, + options.ownerLogPrefix); + HeartbeatHandler heartbeatHandler = new HeartbeatHandler(defaultConfig); + ProtocolInitHandler initHandler = + new ProtocolInitHandler( + context, + protocolVersion, + clusterName, + endPoint, + options, + heartbeatHandler, + productType == null); + + ChannelPipeline pipeline = channel.pipeline(); + context + .getSslHandlerFactory() + .map(f -> f.newSslHandler(channel, endPoint)) + .map(h -> pipeline.addLast(SSL_HANDLER_NAME, h)); + + // Only add meter handlers on the pipeline if metrics are enabled. + SessionMetricUpdater sessionMetricUpdater = context.getMetricsFactory().getSessionUpdater(); + if (nodeMetricUpdater.isEnabled(DefaultNodeMetric.BYTES_RECEIVED, null) + || sessionMetricUpdater.isEnabled(DefaultSessionMetric.BYTES_RECEIVED, null)) { + pipeline.addLast( + INBOUND_TRAFFIC_METER_NAME, + new InboundTrafficMeter(nodeMetricUpdater, sessionMetricUpdater)); + } - pipeline - .addLast( - FRAME_TO_BYTES_ENCODER_NAME, - new FrameEncoder(context.getFrameCodec(), maxFrameLength)) - .addLast( - BYTES_TO_FRAME_DECODER_NAME, - new FrameDecoder(context.getFrameCodec(), maxFrameLength)) - // Note: HeartbeatHandler is inserted here once init completes - .addLast(INFLIGHT_HANDLER_NAME, inFlightHandler) - .addLast(INIT_HANDLER_NAME, initHandler); - - context.getNettyOptions().afterChannelInitialized(channel); - } catch (Throwable t) { - // If the init handler throws an exception, Netty swallows it and closes the channel. We - // want to propagate it instead, so fail the outer future (the result of connect()). - resultFuture.completeExceptionally(t); - throw t; + if (nodeMetricUpdater.isEnabled(DefaultNodeMetric.BYTES_SENT, null) + || sessionMetricUpdater.isEnabled(DefaultSessionMetric.BYTES_SENT, null)) { + pipeline.addLast( + OUTBOUND_TRAFFIC_METER_NAME, + new OutboundTrafficMeter(nodeMetricUpdater, sessionMetricUpdater)); } + + pipeline + .addLast( + FRAME_TO_BYTES_ENCODER_NAME, + new FrameEncoder(context.getFrameCodec(), maxFrameLength)) + .addLast( + BYTES_TO_FRAME_DECODER_NAME, + new FrameDecoder(context.getFrameCodec(), maxFrameLength)) + // Note: HeartbeatHandler is inserted here once init completes + .addLast(INFLIGHT_HANDLER_NAME, inFlightHandler) + .addLast(INIT_HANDLER_NAME, initHandler); + + context.getNettyOptions().afterChannelInitialized(channel); + } catch (Throwable t) { + // If the init handler throws an exception, Netty swallows it and closes the channel. We + // want to propagate it instead, so fail the outer future (the result of connect()). + resultFuture.completeExceptionally(t); + throw t; } - }; + } } } diff --git a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties new file mode 100644 index 00000000000..b2fb10d32c8 --- /dev/null +++ b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties @@ -0,0 +1,7 @@ +Args=-H:IncludeResources=reference\\.conf \ + -H:IncludeResources=application\\.conf \ + -H:IncludeResources=application\\.json \ + -H:IncludeResources=application\\.properties \ + -H:IncludeResources=.*Driver\\.properties \ + -H:DynamicProxyConfigurationResources=${.}/proxy.json \ + -H:ReflectionConfigurationResources=${.}/reflection.json diff --git a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/proxy.json b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/proxy.json new file mode 100644 index 00000000000..37cf6fcf805 --- /dev/null +++ b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/proxy.json @@ -0,0 +1,3 @@ +[ + ["java.lang.reflect.TypeVariable"] +] diff --git a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/reflection.json b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/reflection.json new file mode 100644 index 00000000000..6082b853611 --- /dev/null +++ b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/reflection.json @@ -0,0 +1,154 @@ +[ + { + "name": "com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.loadbalancing.DcInferringLoadBalancingPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.loadbalancing.BasicLoadBalancingPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.connection.ExponentialReconnectionPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.connection.ConstantReconnectionPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.retry.DefaultRetryPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.retry.ConsistencyDowngradingRetryPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.specex.NoSpeculativeExecutionPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.specex.ConstantSpeculativeExecutionPolicy", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext", "java.lang.String" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.time.AtomicTimestampGenerator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.time.ThreadLocalTimestampGenerator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.time.ServerSideTimestampGenerator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.tracker.NoopRequestTracker", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.tracker.RequestLogger", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.session.throttling.PassThroughRequestThrottler", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metadata.NoopNodeStateListener", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metadata.schema.NoopSchemaChangeListener", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.addresstranslation.PassThroughAddressTranslator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.addresstranslation.Ec2MultiRegionAddressTranslator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.auth.PlainTextAuthProvider", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.dse.driver.internal.core.auth.DseGssApiAuthProvider", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.ssl.DefaultSslEngineFactory", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metrics.DefaultMetricsFactory", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metrics.NoopMetricsFactory", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metrics.DropwizardMetricsFactory", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metrics.DefaultMetricIdGenerator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "com.datastax.oss.driver.internal.core.metrics.TaggingMetricIdGenerator", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + }, + { + "name": "io.netty.channel.socket.nio.NioSocketChannel", + "methods": [ { "name": "", "parameterTypes": [] } ] + }, + { + "name": "io.netty.buffer.AbstractByteBufAllocator", + "methods": [ { "name": "toLeakAwareBuffer", "parameterTypes": ["io.netty.buffer.ByteBuf" ] } ] + }, + { + "name": "io.netty.util.ReferenceCountUtil", + "methods": [ { "name": "touch", "parameterTypes": ["java.lang.Object", "java.lang.Object" ] } ] + }, + { + "name" : "io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerIndexField", + "fields": [ {"name": "producerIndex", "allowUnsafeAccess": true} ] + }, + { + "name" : "io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerLimitField", + "fields": [ {"name": "producerLimit", "allowUnsafeAccess": true} ] + }, + { + "name" : "io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueConsumerIndexField", + "fields": [ {"name": "consumerIndex", "allowUnsafeAccess": true} ] + }, + { + "name" : "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields", + "fields": [ {"name": "producerIndex", "allowUnsafeAccess": true} ] + }, + { + "name" : "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields", + "fields": [ {"name": "producerLimit", "allowUnsafeAccess": true} ] + }, + { + "name" : "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields", + "fields": [ {"name": "consumerIndex", "allowUnsafeAccess": true} ] + } +] diff --git a/manual/core/compression/README.md b/manual/core/compression/README.md index 32d18a8ac2f..0697ea1737b 100644 --- a/manual/core/compression/README.md +++ b/manual/core/compression/README.md @@ -27,7 +27,6 @@ datastax-java-driver { Compression must be set before opening a session, it cannot be changed at runtime. - Two algorithms are supported out of the box: [LZ4](https://github.com/jpountz/lz4-java) and [Snappy](http://google.github.io/snappy/). The LZ4 implementation is a good first choice; it offers fallback implementations in case native libraries fail to load and @@ -79,6 +78,8 @@ Dependency: ``` +**Important: Snappy is not supported when building a [GraalVM native image](../graalvm).** + Always double-check the exact Snappy version needed; you can find it in the driver's [parent POM]. [parent POM]: https://search.maven.org/search?q=g:com.datastax.oss%20AND%20a:java-driver-parent&core=gav \ No newline at end of file diff --git a/manual/core/graalvm/README.md b/manual/core/graalvm/README.md new file mode 100644 index 00000000000..04983f46ecc --- /dev/null +++ b/manual/core/graalvm/README.md @@ -0,0 +1,315 @@ +## Using the driver in GraalVM native images + +### Quick overview + +* [GraalVM Native images](https://www.graalvm.org/reference-manual/native-image/) using the driver + can be built with no additional configuration starting with driver 4.13.0. +* But extra configurations are required in a few cases: + * When using [reactive programming](../reactive); + * When using [Jackson](../integration#Jackson); + * When using LZ4 [compression](../compression/); + * Depending on the [logging backend](../logging) in use. +* DSE-specific features: + * [Geospatial types](../dse/geotypes) are supported. + * [DSE Graph](../dse/graph) is not officially supported, although it may work. +* The [shaded jar](../shaded_jar) is not officially supported, although it may work. + +----- + +### Concepts + +Starting with version 4.13.0, the driver ships with [embedded GraalVM configuration files] that +allow GraalVM native images including the driver to be built without hassle, barring a few +exceptions and caveats listed below. + +[embedded GraalVM configuration files]:https://www.graalvm.org/reference-manual/native-image/BuildConfiguration/#embedding-a-configuration-file + +### Classes instantiated by reflection + +The driver instantiates its components by reflection. The actual classes that will be instantiated +in this way need to be registered for reflection. All built-in implementations of various driver +components, such as `LoadBalancingPolicy` or `TimestampGenerator`, are automatically registered for +reflection, along with a few other internal components tha are also instantiated by reflection. +_You don't need to manually register any of these built-in implementations_. + +But if you intend to use a custom implementation in lieu of a driver built-in class, then it is your +responsibility to register that custom implementation for reflection. + +For example, assuming that you have the following load balancing policy implementation: + +```java + +package com.example.app; + +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class CustomLoadBalancingPolicy extends DefaultLoadBalancingPolicy { + + public CustomLoadBalancingPolicy(DriverContext context, String profileName) { + super(context, profileName); + } + // rest of class omitted for brevity +} +``` + +And assuming that you declared the above class in your application.conf file as follows: + +```hocon +datastax-java-driver.basic{ + load-balancing-policy.class = com.example.app.CustomLoadBalancingPolicy +} +``` + +Then you will have to register that class for reflection: + +1. Create the following reflection.json file, or add the entry to an existing file: + +```json +[ + { "name": "com.example.app.CustomLoadBalancingPolicy", "allPublicConstructors": true } +] +``` + +2. When invoking the native image builder, add a `-H:ReflectionConfigurationFiles=reflection.json` + flag and point it to the file created above. + +Note: some frameworks allow you to simplify the registration process. For example, Quarkus offers +the `io.quarkus.runtime.annotations.RegisterForReflection` annotation that you can use to annotate +your class: + +```java +@RegisterForReflection +public class CustomLoadBalancingPolicy extends DefaultLoadBalancingPolicy { + //... +} +``` + +In this case, no other manual configuration is required for the above class to be correctly +registered for reflection. + +### Configuration resources + +The default driver [configuration](../configuration) mechanism is based on the TypeSafe Config +library. TypeSafe Config looks for a few classpath resources when initializing the configuration: +`reference.conf`, `application.conf`, `application.json`, `application.properties`. _These classpath +resources are all automatically included in the native image: you should not need to do it +manually_. See [Accessing Resources in Native Images] for more information on how classpath +resources are handled in native images. + +[Accessing Resources in Native Images]: https://www.graalvm.org/reference-manual/native-image/Resources/ + +### Configuring the logging backend + +When configuring [logging](../logging), the choice of a backend must be considered carefully, as +most logging backends resort to reflection during their configuration phase. + +By default, GraalVM native images provide support for the java.util.logging (JUL) backend. See +[this page](https://www.graalvm.org/reference-manual/native-image/Logging/) for more information. + +For other logging backends, please refer to the logging library documentation to find out if GraalVM +native images are supported. + +### Using reactive-style programming + +The [reactive execution model](../reactive) is compatible with GraalVM native images, but the +following configurations must be added: + +1. Create the following reflection.json file, or add the entry to an existing file: + +```json +[ + { "name": "org.reactivestreams.Publisher" } +] +``` + +2. When invoking the native image builder, add a `-H:ReflectionConfigurationFiles=reflection.json` + flag and point it to the file created above. + +### Using the Jackson JSON library + +[Jackson](https://github.com/FasterXML/jackson) is used in [a few places](../integration#Jackson) in +the driver, but is an optional dependency; if you intend to use Jackson, the following +configurations must be added: + +1. Create the following reflection.json file, or add these entries to an existing file: + +```json +[ + { "name": "com.fasterxml.jackson.core.JsonParser" }, + { "name": "com.fasterxml.jackson.databind.ObjectMapper" } +] +``` + +**Important**: when using the shaded jar – which is not officially supported on GraalVM native +images, see below for more details – replace the above entries with the below ones: + +```json +[ + { "name": "com.datastax.oss.driver.shaded.fasterxml.jackson.core.JsonParser" }, + { "name": "com.datastax.oss.driver.shaded.fasterxml.jackson.databind.ObjectMapper" } +] +``` +2. When invoking the native image builder, add a `-H:ReflectionConfigurationFiles=reflection.json` + flag and point it to the file created above. + +### Enabling compression + +When using [compression](../compression/), only LZ4 can be enabled in native images. **Snappy +compression is not supported.** + +In order for LZ4 compression to work in a native image, the following additional GraalVM +configuration is required: + +1. Create the following reflection.json file, or add these entries to an existing file: + +```json +[ + { "name" : "net.jpountz.lz4.LZ4Compressor" }, + { + "name" : "net.jpountz.lz4.LZ4JNICompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4JavaSafeCompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4JavaUnsafeCompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4HCJavaSafeCompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4HCJavaUnsafeCompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4JavaSafeSafeDecompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4JavaSafeFastDecompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4JavaUnsafeSafeDecompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + }, + { + "name" : "net.jpountz.lz4.LZ4JavaUnsafeFastDecompressor", + "allDeclaredConstructors": true, + "allPublicFields": true + } +] +``` + +2. When invoking the native image builder, add a `-H:ReflectionConfigurationFiles=reflection.json` + flag and point it to the file created above. + +### Native calls + +The driver performs a few [native calls](../integration#Native-libraries) using +[JNR](https://github.com/jnr). + +Starting with driver 4.7.0, native calls are also possible in a GraalVM native image, without any +extra configuration. + +### Using DataStax Enterprise (DSE) features + +#### DSE Geospatial types + +DSE [Geospatial types](../dse/geotypes) are supported on GraalVM native images; the following +configurations must be added: + +1. Create the following reflection.json file, or add the entry to an existing file: + +```json +[ + { "name": "com.esri.core.geometry.ogc.OGCGeometry" } +] +``` + +**Important**: when using the shaded jar – which is not officially supported on GraalVM native +images, as stated above – replace the above entry with the below one: + +```json +[ + { "name": "com.datastax.oss.driver.shaded.esri.core.geometry.ogc.OGCGeometry" } +] +``` + +2. When invoking the native image builder, add a `-H:ReflectionConfigurationFiles=reflection.json` + flag and point it to the file created above. + +#### DSE Graph + +**[DSE Graph](../dse/graph) is not officially supported on GraalVM native images.** + +The following configuration can be used as a starting point for users wishing to build a native +image for a DSE Graph application. DataStax does not guarantee however that the below configuration +will work in all cases. If the native image build fails, a good option is to use GraalVM's +[Tracing Agent](https://www.graalvm.org/reference-manual/native-image/Agent/) to understand why. + +1. Create the following reflection.json file, or add these entries to an existing file: + +```json +[ + { "name": "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0" }, + { "name": "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal" }, + { "name": "org.apache.tinkerpop.gremlin.structure.Graph", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredMethods": true, + "allPublicMethods": true + }, + { "name": "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredMethods": true, + "allPublicMethods": true + }, + { "name": " org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredMethods": true, + "allPublicMethods": true + }, + { "name": "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredMethods": true, + "allPublicMethods": true + } +] +``` + +2. When invoking the native image builder, add the following flags: + +``` +-H:ReflectionConfigurationFiles=reflection.json +--initialize-at-build-time=org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0 +--initialize-at-build-time=org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer +``` + +### Using the shaded jar + +**The [shaded jar](../shaded_jar) is not officially supported in a GraalVM native image.** + +However, it has been reported that the shaded jar can be included in a GraalVM native image as a +drop-in replacement for the regular driver jar for simple applications, without any extra GraalVM +configuration. diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 6a41fa4751d..6faf87cf4ad 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -6,6 +6,8 @@ * explanations about [driver dependencies](#driver-dependencies) and when they can be manually excluded. +Note: guidelines to build a GraalVM native image can be found [here](../graalvm). + ----- ### Which artifact(s) should I use? diff --git a/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties b/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties new file mode 100644 index 00000000000..4971c6cb7ee --- /dev/null +++ b/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties @@ -0,0 +1 @@ +Args = -H:ReflectionConfigurationResources=${.}/reflection.json diff --git a/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/reflection.json b/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/reflection.json new file mode 100644 index 00000000000..638cac60af1 --- /dev/null +++ b/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/reflection.json @@ -0,0 +1,6 @@ +[ + { + "name": "com.datastax.oss.driver.internal.metrics.micrometer.MicrometerMetricsFactory", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + } +] diff --git a/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties b/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties new file mode 100644 index 00000000000..4971c6cb7ee --- /dev/null +++ b/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties @@ -0,0 +1 @@ +Args = -H:ReflectionConfigurationResources=${.}/reflection.json diff --git a/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/reflection.json b/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/reflection.json new file mode 100644 index 00000000000..6d408897551 --- /dev/null +++ b/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/reflection.json @@ -0,0 +1,6 @@ +[ + { + "name": "com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileMetricsFactory", + "methods": [ { "name": "", "parameterTypes": [ "com.datastax.oss.driver.api.core.context.DriverContext" ] } ] + } +] diff --git a/pom.xml b/pom.xml index aa72a4c7c0f..ac1097f76b3 100644 --- a/pom.xml +++ b/pom.xml @@ -664,6 +664,7 @@ limitations under the License.]]> **/pom.xml + src/**/native-image.properties **/src/main/config/ide/** From 5009dc8607d5eef843c21a845e96af863f76527a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 16:41:51 +0200 Subject: [PATCH 179/395] Update changelog for 4.13.0 release --- changelog/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 7bae766a602..48a16bc6f28 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,19 +2,20 @@ -### 4.13.0 (in progress) +### 4.13.0 - [improvement] JAVA-2940: Add GraalVM native image build configurations - [improvement] JAVA-2953: Promote ProgrammaticPlainTextAuthProvider to the public API and add credentials hot-reload -- [improvement] JAVA-2951: Accept multiple node state listeners, schema change listeners and request trackers +- [improvement] JAVA-2951: Accept multiple node state listeners, schema change listeners and request + trackers Merged from 4.12.x: - [bug] JAVA-2949: Provide mapper support for CompletionStage> - [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck -### 4.12.1 (in progress) +### 4.12.1 Merged from 4.11.x: @@ -37,7 +38,7 @@ Merged from 4.11.x: - [bug] JAVA-2943: Prevent session leak with wrong keyspace name - [bug] JAVA-2938: OverloadedException message is misleading -### 4.11.3 (in progress) +### 4.11.3 - [bug] JAVA-2949: Provide mapper support for CompletionStage> - [bug] JAVA-2950: Remove reference to Reflection class from DependencyCheck From 706e03c5b46d5c1de801c0228e409ff6727bc045 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 16:48:00 +0200 Subject: [PATCH 180/395] Update manual for 4.13.0 release --- README.md | 4 +- manual/case_sensitivity/README.md | 10 +-- manual/core/README.md | 26 +++---- manual/core/address_resolution/README.md | 2 +- manual/core/async/README.md | 2 +- manual/core/authentication/README.md | 16 ++-- manual/core/bom/README.md | 4 +- manual/core/configuration/README.md | 20 ++--- manual/core/control_connection/README.md | 2 +- manual/core/custom_codecs/README.md | 74 +++++++++---------- manual/core/detachable_types/README.md | 14 ++-- manual/core/dse/geotypes/README.md | 6 +- manual/core/dse/graph/README.md | 4 +- manual/core/dse/graph/fluent/README.md | 4 +- .../core/dse/graph/fluent/explicit/README.md | 12 +-- manual/core/dse/graph/results/README.md | 6 +- manual/core/dse/graph/script/README.md | 6 +- manual/core/idempotence/README.md | 4 +- manual/core/integration/README.md | 7 +- manual/core/load_balancing/README.md | 12 +-- manual/core/metadata/README.md | 6 +- manual/core/metadata/node/README.md | 28 +++---- manual/core/metadata/schema/README.md | 20 ++--- manual/core/metadata/token/README.md | 4 +- manual/core/native_protocol/README.md | 6 +- manual/core/non_blocking/README.md | 44 +++++------ manual/core/paging/README.md | 12 +-- manual/core/performance/README.md | 10 +-- manual/core/pooling/README.md | 2 +- manual/core/query_timestamps/README.md | 4 +- manual/core/reactive/README.md | 24 +++--- manual/core/reconnection/README.md | 8 +- manual/core/request_tracker/README.md | 4 +- manual/core/retries/README.md | 36 ++++----- manual/core/speculative_execution/README.md | 2 +- manual/core/ssl/README.md | 6 +- manual/core/statements/README.md | 8 +- manual/core/statements/batch/README.md | 6 +- .../statements/per_query_keyspace/README.md | 2 +- manual/core/statements/prepared/README.md | 8 +- manual/core/statements/simple/README.md | 6 +- manual/core/temporal_types/README.md | 8 +- manual/core/throttling/README.md | 6 +- manual/core/tracing/README.md | 12 +-- manual/core/tuples/README.md | 4 +- manual/core/udts/README.md | 4 +- manual/developer/common/concurrency/README.md | 4 +- manual/mapper/config/kotlin/README.md | 2 +- manual/mapper/config/record/README.md | 2 +- manual/mapper/config/scala/README.md | 2 +- manual/mapper/daos/README.md | 8 +- manual/mapper/daos/custom_types/README.md | 10 +-- manual/mapper/daos/delete/README.md | 18 ++--- manual/mapper/daos/getentity/README.md | 18 ++--- manual/mapper/daos/increment/README.md | 12 +-- manual/mapper/daos/insert/README.md | 14 ++-- manual/mapper/daos/null_saving/README.md | 10 +-- manual/mapper/daos/query/README.md | 24 +++--- manual/mapper/daos/queryprovider/README.md | 16 ++-- manual/mapper/daos/select/README.md | 28 +++---- manual/mapper/daos/setentity/README.md | 10 +-- .../daos/statement_attributes/README.md | 2 +- manual/mapper/daos/update/README.md | 12 +-- manual/mapper/entities/README.md | 36 ++++----- manual/mapper/mapper/README.md | 10 +-- manual/osgi/README.md | 6 +- manual/query_builder/README.md | 10 +-- manual/query_builder/condition/README.md | 2 +- manual/query_builder/delete/README.md | 4 +- manual/query_builder/insert/README.md | 2 +- manual/query_builder/relation/README.md | 4 +- manual/query_builder/schema/README.md | 2 +- .../query_builder/schema/aggregate/README.md | 2 +- .../query_builder/schema/function/README.md | 2 +- manual/query_builder/schema/index/README.md | 2 +- .../query_builder/schema/keyspace/README.md | 2 +- .../schema/materialized_view/README.md | 4 +- manual/query_builder/schema/table/README.md | 6 +- manual/query_builder/schema/type/README.md | 2 +- manual/query_builder/select/README.md | 4 +- manual/query_builder/term/README.md | 4 +- manual/query_builder/truncate/README.md | 2 +- manual/query_builder/update/README.md | 4 +- 83 files changed, 409 insertions(+), 408 deletions(-) diff --git a/README.md b/README.md index 19b09697684..b61f2464900 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.12.0](https://github.com/datastax/java-driver/tree/4.12.0).* +[4.13.0](https://github.com/datastax/java-driver/tree/4.13.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol @@ -82,7 +82,7 @@ See the [upgrade guide](upgrade_guide/) for details. * [Changelog] * [FAQ] -[API docs]: https://docs.datastax.com/en/drivers/java/4.12 +[API docs]: https://docs.datastax.com/en/drivers/java/4.13 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [@dsJavaDriver]: https://twitter.com/dsJavaDriver diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index 7e85cd2d091..947502cd5b0 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -106,11 +106,11 @@ For "consuming" methods, string overloads are also provided for convenience, for * in other cases, the string is always assumed to be in CQL form, and converted on the fly with `CqlIdentifier.fromCql`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html -[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html +[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/AccessibleByName.html ### Good practices diff --git a/manual/core/README.md b/manual/core/README.md index 4648e53f4bd..f6418b2739f 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -314,18 +314,18 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { } ``` -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html -[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html#builder-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/TupleValue.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html -[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- -[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html#builder-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/TupleValue.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html +[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- +[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index 2407f589f78..11194b92e6b 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -124,7 +124,7 @@ Cassandra node: domain name of the target instance. Then it performs a forward DNS lookup of the domain name; the EC2 DNS does the private/public switch automatically based on location). -[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html +[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html [cassandra.yaml]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html [rpc_address]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html?scroll=configCassandra_yaml__rpc_address diff --git a/manual/core/async/README.md b/manual/core/async/README.md index 50005ffb7a8..e2bac78d755 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -207,4 +207,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 2a5ee302e09..7843ae2d1f8 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -227,13 +227,13 @@ session.execute(statement); [SASL]: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer -[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/auth/AuthProvider.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html -[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/AuthProvider.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html +[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html [ProgrammaticPlainTextAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.html -[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html -[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html -[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- -[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- -[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- +[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html +[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html +[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- +[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- +[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- [reference.conf]: ../configuration/reference/ \ No newline at end of file diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index 357bd6c58b7..c31df62a3d6 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.12.0 + 4.13.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.12.0 + 4.13.0 diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index 656115b18a3..ef1c6e801b2 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -520,16 +520,16 @@ config.getDefaultProfile().getString(MyCustomOption.ADMIN_EMAIL); config.getDefaultProfile().getInt(MyCustomOption.AWESOMENESS_FACTOR); ``` -[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfig.html -[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html -[DriverOption]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverOption.html -[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html -[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- -[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- -[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- -[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- +[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfig.html +[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html +[DriverOption]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverOption.html +[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html +[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- +[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- +[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- +[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- [Typesafe Config]: https://github.com/typesafehub/config [config standard behavior]: https://github.com/typesafehub/config#standard-behavior diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index 2cb88323cd1..3b33639059e 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -23,4 +23,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index 3413f9d5934..ca3c20d7538 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -660,13 +660,13 @@ private static String formatRow(Row row) { } ``` -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html -[format()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- -[parse()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- -[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html -[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html +[format()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- +[parse()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- +[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html +[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- [Enums]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html [Enum.name()]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#name-- @@ -680,36 +680,36 @@ private static String formatRow(Row row) { [java.time.LocalDateTime]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html [java.time.ZoneId]: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html -[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html -[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY -[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY -[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY -[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY -[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY -[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY -[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY -[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY -[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC -[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- -[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM -[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC -[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC -[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC -[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED -[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- -[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- -[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- -[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- - -[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB -[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP +[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html +[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY +[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY +[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY +[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY +[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY +[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY +[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY +[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY +[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC +[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- +[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM +[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC +[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC +[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC +[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED +[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- +[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- +[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- +[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- + +[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB +[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index 927cb3e372d..4a0cc9044dc 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -137,13 +137,13 @@ Even then, the defaults used by detached objects might be good enough for you: Otherwise, just make sure you reattach objects any time you deserialize them or create them from scratch. -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT -[DataType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/DataType.html -[Detachable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/detach/Detachable.html -[Session]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html -[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html -[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT +[DataType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/DataType.html +[Detachable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/detach/Detachable.html +[Session]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html +[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html +[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html [Java serialization]: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html [protocol specifications]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index ad081b246c4..7116ff79886 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -166,9 +166,9 @@ All geospatial types interoperate with three standard formats: [ESRI]: https://github.com/Esri/geometry-api-java -[LineString]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/data/geometry/LineString.html -[Point]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/data/geometry/Point.html -[Polygon]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/data/geometry/Polygon.html +[LineString]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/data/geometry/LineString.html +[Point]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/data/geometry/Point.html +[Polygon]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/data/geometry/Polygon.html [Well-known text]: https://en.wikipedia.org/wiki/Well-known_text [Well-known binary]: https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index aa8409db760..19d5312b6df 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -74,8 +74,8 @@ fluent API returns Apache TinkerPop™ types directly. [Apache TinkerPop™]: http://tinkerpop.apache.org/ -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html -[GraphSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/GraphSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html +[GraphSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/GraphSession.html [DSE developer guide]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphTOC.html [Gremlin]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dseGraphAbout.html#dseGraphAbout__what-is-cql diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index 15784ba833a..443841b09ba 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -109,8 +109,8 @@ All the DSE predicates are available on the driver side: .values("name"); ``` -[Search]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/predicates/Search.html -[Geo]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/predicates/Geo.html +[Search]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/predicates/Search.html +[Geo]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/predicates/Geo.html [Apache TinkerPop™]: http://tinkerpop.apache.org/ [TinkerPop DSL]: http://tinkerpop.apache.org/docs/current/reference/#dsl diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index bef059fe467..3157f46d01a 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -105,9 +105,9 @@ added in a future version. See also the [parent page](../) for topics common to all fluent traversals. -[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html -[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html -[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- -[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- +[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html +[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html +[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- +[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index 1d3891b0994..6be3bed590b 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -137,8 +137,8 @@ If a type doesn't have a corresponding `asXxx()` method, use the variant that ta UUID uuid = graphNode.as(UUID.class); ``` -[GraphNode]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/GraphNode.html -[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/GraphResultSet.html -[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html +[GraphNode]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/GraphNode.html +[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/GraphResultSet.html +[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html [DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index 8bdf9799b63..58173506349 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -101,6 +101,6 @@ Note however that some types of queries can only be performed through the script * configuration; * DSE graph schema queries. -[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html -[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html +[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index f10bcae0721..0c24efda673 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -60,5 +60,5 @@ assert bs.isIdempotent(); The query builder tries to infer idempotence automatically; refer to [its manual](../../query_builder/idempotence/) for more details. -[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- -[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- +[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- +[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 6faf87cf4ad..23380063cdf 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -545,6 +545,7 @@ Here are the recommended TinkerPop versions for each driver version:

    Driver versionTinkerPop version
    4.12.03.4.10
    4.11.03.4.10
    4.10.03.4.9
    4.9.03.4.8
    + @@ -644,6 +645,6 @@ The remaining core driver dependencies are the only ones that are truly mandator [guava]: https://github.com/google/guava/issues/2721 [annotation processing]: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#sthref65 -[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- -[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[Uuids]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/uuid/Uuids.html +[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- +[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[Uuids]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/uuid/Uuids.html diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index d74546d6e99..2997d427106 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -426,12 +426,12 @@ Then it uses the "closest" distance for any given node. For example: * policy1 changes its suggestion to IGNORED. node1 is set to REMOTE; * policy1 changes its suggestion to REMOTE. node1 stays at REMOTE. -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html -[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html +[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html [BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java -[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- -[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- -[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- -[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html +[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- +[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- +[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index 117c802c966..f160575729a 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -56,6 +56,6 @@ new keyspace in the schema metadata before the token metadata was updated. Schema and node state events are debounced. This allows you to control how often the metadata gets refreshed. See the [Performance](../performance/#debouncing) page for more details. -[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- -[Metadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- +[Metadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html +[Node]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 455313758c6..4548f95aeee 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -129,17 +129,17 @@ beyond the scope of this document; if you're interested, study the `TopologyMoni the source code. -[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- -[Node]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html -[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- -[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- -[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- -[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- -[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- -[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- -[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- -[NodeState]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeState.html -[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html -[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file +[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- +[Node]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html +[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- +[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- +[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- +[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- +[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- +[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- +[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- +[NodeState]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/NodeState.html +[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html +[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html +[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index f9e1f762a23..52711d11bd1 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -321,16 +321,16 @@ unavailable for the excluded keyspaces. If you issue schema-altering requests from the driver (e.g. `session.execute("CREATE TABLE ..")`), take a look at the [Performance](../../performance/#schema-updates) page for a few tips. -[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html -[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html -[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- -[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- -[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- -[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html -[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html -[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html +[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html +[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html +[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- +[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- +[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- +[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html +[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html +[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html [JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 [java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index db830c64bae..ea9f4a99832 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -169,5 +169,5 @@ on [schema metadata](../schema/). If schema metadata is disabled or filtered, to also be unavailable for the excluded keyspaces. -[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 4d43687f792..08d551765dc 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -135,6 +135,6 @@ If you want to see the details of mixed cluster negotiation, enable `DEBUG` leve [protocol spec]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources [driver3]: https://docs.datastax.com/en/developer/java-driver/3.10/manual/native_protocol/ -[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- -[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- -[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- +[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- +[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- +[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 61a6618f757..dbffcff1fdb 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -49,22 +49,22 @@ For example, calling any synchronous method declared in [`SyncCqlSession`], such will block until the result is available. These methods should never be used in non-blocking applications. -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` -[`execute`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all safe for use in non-blocking applications; the statement execution and asynchronous result delivery is guaranteed to never block. -[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html -[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the returned publisher will never block when subscribed to, until the final results are delivered to the subscriber. -[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- There is one exception though: continuous paging queries (a feature specific to DSE) have a special execution model which uses internal locks for coordination. Although such locks are only held for @@ -77,10 +77,10 @@ reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactiv though, continuous paging is extremely efficient and can safely be used in most non-blocking contexts, unless they require strict lock-freedom. -[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html -[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html -[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- -[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- #### Driver lock-free guarantees per session lifecycle phases @@ -110,8 +110,8 @@ Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` should be avoided in non-blocking applications. -[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- -[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- Once the session is initialized, however, the driver is guaranteed to be non-blocking during the session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. @@ -121,8 +121,8 @@ during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseab asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is shut down and lock-freedom enforcement is disabled. -[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html -[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- #### Driver lock-free guarantees for specific components @@ -131,7 +131,7 @@ Certain driver components are not implemented in lock-free algorithms. For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It should not be used if strict lock-freedom is enforced. -[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html The same is valid for both built-in [request throttlers]: @@ -143,7 +143,7 @@ use locks internally, and depending on how many requests are being executed in p contention on these locks can be high: in short, if your application enforces strict lock-freedom, then these components should not be used. -[request throttlers]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html +[request throttlers]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html Other components may be lock-free, *except* for their first invocation. This is the case of the following items: @@ -151,8 +151,8 @@ following items: * All built-in implementations of [`TimestampGenerator`], upon instantiation; * The utility method [`Uuids.timeBased()`]. -[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/time/TimestampGenerator.html -[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- Both components need to access native libraries when they get initialized and this may involve hitting the local filesystem, thus causing the initialization to become a blocking call. @@ -172,7 +172,7 @@ One component, the codec registry, can block when its [`register`] method is cal therefore advised that codecs should be registered during application startup exclusively. See the [custom codecs](../custom_codecs) section for more details about registering codecs. -[`register`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[`register`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- Finally, a few internal components also use locks, but only during session initialization; once the session is ready, they are either discarded, or don't use locks anymore for the rest of the @@ -213,7 +213,7 @@ lock-freedom enforcement tools could report calls to that method, but it was imp these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a non-blocking call and random UUIDs can now be safely generated in non-blocking applications. -[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- [JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 #### Driver lock-free guarantees when reloading the configuration @@ -228,8 +228,8 @@ detectors. If that is the case, it is advised to disable hot-reloading by settin `datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on [configuration](../configuration) for more information. -[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- #### Driver lock-free guarantees when connecting to DSE diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index 7c33aa5b43a..9f753a77181 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -253,12 +253,12 @@ protocol page size and the logical page size to the same value. The [driver examples] include two complete web service implementations demonstrating forward-only and offset paging. -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- -[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- -[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/paging/OffsetPager.html -[PagingState]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/PagingState.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- +[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- +[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/paging/OffsetPager.html +[PagingState]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/PagingState.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index 46bd567aa0f..a26067dbed5 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -345,8 +345,8 @@ possible to reuse the same event loop group for I/O, admin tasks, and even your (the driver's internal code is fully asynchronous so it will never block any thread). The timer is the only one that will have to stay on a separate thread. -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html -[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- -[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html +[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index c57808c692a..84dee0ec80e 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -170,5 +170,5 @@ you experience the issue, here's what to look out for: Try adding more connections per node. Thanks to the driver's hot-reload mechanism, you can do that at runtime and see the effects immediately. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html [CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index 6851fdd7e57..bde4b0722e9 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -187,9 +187,9 @@ Here is the order of precedence of all the methods described so far: 3. otherwise, if the timestamp generator assigned a timestamp, use it; 4. otherwise, let the server assign the timestamp. -[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/time/TimestampGenerator.html [gettimeofday]: http://man7.org/linux/man-pages/man2/settimeofday.2.html [JNR]: https://github.com/jnr/jnr-posix [Lightweight transactions]: https://docs.datastax.com/en/dse/6.0/cql/cql/cql_using/useInsertLWT.html -[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- +[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index d70a9bd4094..bd32969f3c0 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -367,18 +367,18 @@ Note that the driver already has a [built-in retry mechanism] that can transpare queries; the above example should be seen as a demonstration of application-level retries, when a more fine-grained control of what should be retried, and how, is required. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html -[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html -[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html -[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- -[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- -[wasApplied]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- -[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- -[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- -[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html +[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html +[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html +[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- +[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- +[wasApplied]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- +[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- +[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- +[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- [built-in retry mechanism]: ../retries/ [request throttling]: ../throttling/ diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index 3ec3c8ef3cc..b5b6b3e10b4 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -84,7 +84,7 @@ Note that the session is not accessible until it is fully ready: the `CqlSession call — or the future returned by `buildAsync()` — will not complete until the connection was established. -[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/context/DriverContext.html -[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html +[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index e1c9c1d6345..af66851c748 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -123,5 +123,5 @@ all FROM users WHERE user_id=? [v0=42] com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined column name all ``` -[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/tracker/RequestTracker.html +[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index eb24ead3ad1..ec07dc2cea2 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -231,21 +231,21 @@ configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html -[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/DriverTimeoutException.html -[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html -[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/HeartbeatException.html -[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html -[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html -[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html -[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html -[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html -[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/retry/RetryDecision.html -[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/retry/RetryPolicy.html -[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/retry/RetryVerdict.html -[ServerError]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/ServerError.html -[TruncateException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/TruncateException.html -[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html -[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html -[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html +[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/DriverTimeoutException.html +[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html +[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/HeartbeatException.html +[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html +[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html +[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html +[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html +[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html +[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/retry/RetryDecision.html +[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/retry/RetryPolicy.html +[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[ServerError]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ServerError.html +[TruncateException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/TruncateException.html +[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html +[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html +[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index 6e0e86f8606..fe044e93df7 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -250,4 +250,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index d21bf0e7839..91bf0fc1878 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -204,6 +204,6 @@ the box, but with a bit of custom development it is fairly easy to add. See [dsClientToNode]: https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html [pickle]: http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html [JSSE system properties]: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization -[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- -[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- -[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html +[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- +[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- +[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index b8a0621bc1d..156933f6649 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -59,7 +59,7 @@ the [configuration](../configuration/). Namely, these are: idempotent flag, quer consistency levels and page size. We recommended the configuration approach whenever possible (you can create execution profiles to capture common combinations of those options). -[Statement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html -[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/StatementBuilder.html -[execute]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- -[executeAsync]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[Statement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html +[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/StatementBuilder.html +[execute]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[executeAsync]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index 1cb479ce2bc..917482cae3e 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -61,8 +61,8 @@ In addition, simple statements with named parameters are currently not supported due to a [protocol limitation][CASSANDRA-10246] that will be fixed in a future version). If you try to execute such a batch, an `IllegalArgumentException` is thrown. -[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BatchStatement.html -[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- -[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BatchStatement.html +[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- [batch_dse]: http://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/useBatch.html [CASSANDRA-10246]: https://issues.apache.org/jira/browse/CASSANDRA-10246 diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index cd5295805f4..03c2584e2c9 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -124,6 +124,6 @@ SimpleStatement statement = At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we'll probably deprecate `setRoutingKeyspace()`. -[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index e7e7d4007d4..b795e5f138f 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -330,10 +330,10 @@ With Cassandra 4 and [native protocol](../../native_protocol/) v5, this issue is new version with the response; the driver updates its local cache transparently, and the client can observe the new columns in the result set. -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [CASSANDRA-10786]: https://issues.apache.org/jira/browse/CASSANDRA-10786 [CASSANDRA-10813]: https://issues.apache.org/jira/browse/CASSANDRA-10813 [guava eviction]: https://github.com/google/guava/wiki/CachesExplained#reference-based-eviction -[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- -[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- +[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- +[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index a07fa66126b..3b87d7521f3 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -182,6 +182,6 @@ session.execute( Or you could also use [prepared statements](../prepared/), which don't have this limitation since parameter types are known in advance. -[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SimpleStatement.html -[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- -[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- +[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SimpleStatement.html +[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- +[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index cf5273b4e0f..5b35bfd1750 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -146,7 +146,7 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]" ``` -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index eb69b160a99..ced51bca1a5 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -145,6 +145,6 @@ datastax-java-driver { If you enable `throttling.delay`, make sure to also check the associated extra options to correctly size the underlying histograms (`metrics.session.throttling.delay.*`). -[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/RequestThrottlingException.html -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/RequestThrottlingException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index 7864ac147a1..f15dc0c69d9 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -113,9 +113,9 @@ for (TraceEvent event : trace.getEvents()) { If you call `getQueryTrace()` for a statement that didn't have tracing enabled, an exception is thrown. -[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html -[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/QueryTrace.html -[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- -[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- -[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- -[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html +[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/QueryTrace.html +[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- +[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- +[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- +[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index cfecdf3f8f8..b6222f65439 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -139,5 +139,5 @@ BoundStatement bs = [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html -[TupleType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/TupleType.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/TupleValue.html +[TupleType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/TupleType.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/TupleValue.html diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index 90f7bff59ff..06c6006a903 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -135,5 +135,5 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index c0697d439c8..981c1e7292b 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -101,8 +101,8 @@ public interface ExecutionInfo { When a public API method is blocking, this is generally clearly stated in its javadocs. -[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index e016cfec768..a583718a16e 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -106,4 +106,4 @@ before compilation: [build.gradle]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/build.gradle [UserDao.kt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/src/main/kotlin/com/datastax/examples/mapper/killrvideo/user/UserDao.kt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index 520eeb773b7..89363b45bf0 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -27,7 +27,7 @@ You need to build with Java 14, and pass the `--enable-preview` flag to both the runtime JVM. See [pom.xml] in the example. -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html [DataStax-Examples/object-mapper-jvm/record]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/record [pom.xml]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/record/pom.xml diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index 6d2ed670fc8..6174c274fb7 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -54,4 +54,4 @@ mapper builder. [DataStax-Examples/object-mapper-jvm/scala]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/scala [build.sbt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/scala/build.sbt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index 9a15815acb0..6ee6dfc0aab 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -148,8 +148,8 @@ In this case, any annotations declared in `Dao1` would be chosen over `Dao2`. To control how the hierarchy is scanned, annotate interfaces with [@HierarchyScanStrategy]. -[@Dao]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html [Entity Inheritance]: ../entities/#inheritance diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index 7d39e8b7038..179f61a0b22 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -236,8 +236,8 @@ flag: With this configuration, if a DAO method declares a non built-in return type, it will be surfaced as a compiler error. -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/MapperContext.html -[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html -[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/MapperContext.html +[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html +[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index 290180038e1..c067d049106 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -151,15 +151,15 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@Delete]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Delete.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@Delete]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Delete.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index 63a82e96e14..9995e073ef8 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -130,15 +130,15 @@ If the return type doesn't match the parameter type (for example [PagingIterable [AsyncResultSet]), the mapper processor will issue a compile-time error. -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[GettableByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/GettableByName.html -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[GettableByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/GettableByName.html +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html [Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index c8680e9b6ab..2445490b8a1 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -75,12 +75,12 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[@Increment]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Increment.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Increment]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Increment.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/CqlName.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index 79337a093a9..624cf20f311 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -108,13 +108,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Insert]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Insert]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index 80be5c17652..e94fed266c1 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -93,10 +93,10 @@ public interface UserDao extends InventoryDao { } ``` -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[MapperException]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/MapperException.html -[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET -[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[MapperException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/MapperException.html +[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET +[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL [CASSANDRA-7304]: https://issues.apache.org/jira/browse/CASSANDRA-7304 diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index bde13b37a41..1ccc0f8e7b7 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -113,18 +113,18 @@ Then: query succeeds or not depends on whether the session that the mapper was built with has a [default keyspace]. -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Query]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Query.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[Row]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/Row.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Query]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Query.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index 61e2212079e..acf9de0fea4 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -137,11 +137,11 @@ Here is the full implementation: the desired [PagingIterable][PagingIterable]. -[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html -[providerClass]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- -[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- -[providerMethod]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/MapperContext.html -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/EntityHelper.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html +[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html +[providerClass]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- +[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- +[providerMethod]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/MapperContext.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/EntityHelper.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index f5a3e8d33f4..f42b41e4632 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -160,20 +160,20 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html -[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- -[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- -[groupBy()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- -[limit()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- -[orderBy()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- -[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html +[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- +[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- +[groupBy()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- +[limit()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- +[orderBy()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- +[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index 5fc441b9bf8..0929daaf847 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -112,8 +112,8 @@ BoundStatement bind(Product product, BoundStatement statement); If you use a void method with [BoundStatement], the mapper processor will issue a compile-time warning. -[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html -[SettableByName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/SettableByName.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/data/UdtValue.html +[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html +[SettableByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/SettableByName.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index 4ca17cfbb96..57d73956e64 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -60,4 +60,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 8ffa06a1b4c..8920e8f75f7 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -143,13 +143,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Update]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Update.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Update]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Update.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html [Boolean]: https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Boolean.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/ResultSet.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index 41f8a2a2a4f..2d584bed282 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -555,22 +555,22 @@ the same level. To control how the class hierarchy is scanned, annotate classes with [@HierarchyScanStrategy]. -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/CqlName.html -[@Dao]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@Entity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Entity.html -[NameConverter]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html -[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html -[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Computed]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Computed.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Select.html -[@Insert]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[@Update]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Update.html -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[@Query]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Query.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@Entity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Entity.html +[NameConverter]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html +[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html +[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Computed]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Computed.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html +[@Insert]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[@Update]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Update.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[@Query]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Query.html [aliases]: http://cassandra.apache.org/doc/latest/cql/dml.html?#aliases -[@Transient]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Transient.html -[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@Transient]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Transient.html +[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 032381e39bf..3c723aacb73 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -230,8 +230,8 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) You can also permanently disable validation of an individual entity by annotating it with `@SchemaHint(targetElement = NONE)`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html -[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html -[@Mapper]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/mapper/annotations/Mapper.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html +[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html +[@Mapper]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Mapper.html diff --git a/manual/osgi/README.md b/manual/osgi/README.md index 670625960cb..d0ee00538ad 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -138,7 +138,7 @@ starting the driver: [driver configuration]: ../core/configuration [OSGi]:https://www.osgi.org [JNR]: https://github.com/jnr/jnr-posix -[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- [JAVA-1127]:https://datastax-oss.atlassian.net/browse/JAVA-1127 -[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- -[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- +[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- +[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index 6f2e6e2afd6..fe508fca68b 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -212,8 +212,8 @@ For a complete tour of the API, browse the child pages in this manual: * [Terms](term/) * [Idempotence](idempotence/) -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/CqlIdentifier.html -[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html -[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html +[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html +[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index 3d8682c32cf..1517b5a106a 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -132,4 +132,4 @@ It is mutually exclusive with column conditions: if you previously specified col the statement, they will be ignored; conversely, adding a column condition cancels a previous IF EXISTS clause. -[Condition]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/condition/Condition.html +[Condition]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/condition/Condition.html diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index 0fbcf27ea77..c39d97869cb 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -141,5 +141,5 @@ deleteFrom("user") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index 2d2c66fd526..74f87c5b204 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -114,4 +114,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index 6e6cb03829e..9f0193825d5 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -201,5 +201,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Relation]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/relation/Relation.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Relation]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/relation/Relation.html diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index b285a68acef..ea012439f11 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -44,4 +44,4 @@ element type: * [function](function/) * [aggregate](aggregate/) -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index a2aea551f47..99d7b893b22 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -76,4 +76,4 @@ dropAggregate("average").ifExists(); // DROP AGGREGATE IF EXISTS average ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index f9dfc5d0af8..508ff737eac 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -92,4 +92,4 @@ dropFunction("log").ifExists(); // DROP FUNCTION IF EXISTS log ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index 8e1ed2d8125..ecbd9c4559c 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -99,4 +99,4 @@ dropIndex("my_idx").ifExists(); // DROP INDEX IF EXISTS my_idx ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index b772b9b0d6d..ccdbcea3d1f 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -83,6 +83,6 @@ dropKeyspace("cycling").ifExists(); // DROP KEYSPACE IF EXISTS cycling ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index 54354907a5e..89c0a687801 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -85,5 +85,5 @@ dropTable("cyclist_by_age").ifExists(); // DROP MATERIALIZED VIEW IF EXISTS cyclist_by_age ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index 12b2577e21c..da5ea6ff015 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -107,6 +107,6 @@ dropTable("cyclist_name").ifExists(); // DROP TABLE IF EXISTS cyclist_name ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html -[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html +[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index fe0791c970d..734bcf65d8e 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -88,4 +88,4 @@ dropTable("address").ifExists(); // DROP TYPE IF EXISTS address ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index b0c13bc438f..1ca33a1c2f5 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -391,5 +391,5 @@ selectFrom("user").all().allowFiltering(); // SELECT * FROM user ALLOW FILTERING ``` -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index a0995a4b516..28169a31d9f 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -105,5 +105,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index 88ffcf47de8..3a6c7609b5d 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -17,4 +17,4 @@ Truncate truncate2 = truncate(CqlIdentifier.fromCql("mytable")); Note that, at this stage, the query is ready to build. After creating a TRUNCATE query it does not take any values. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index 4771641e40b..0d6c8a40644 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -251,5 +251,5 @@ update("foo") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Assignment]: https://docs.datastax.com/en/drivers/java/4.12/com/datastax/oss/driver/api/querybuilder/update/Assignment.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Assignment]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/update/Assignment.html From ab58fae478442cc3b0bb9cf814e456c106355103 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 16:51:34 +0200 Subject: [PATCH 181/395] Update upgrade guide for 4.13.0 release --- upgrade_guide/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index c2fc9c13981..0be2af16a1e 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -2,6 +2,17 @@ ### 4.13.0 +#### Enhanced support for GraalVM native images + +[JAVA-2940](https://datastax-oss.atlassian.net/browse/JAVA-2940) introduced an enhanced support for +building GraalVM native images. + +If you were building a native image for your application, please verify your native image builder +configuration. Most of the extra configuration required until now is likely to not be necessary +anymore. + +Refer to this [manual page](../manual/core/graalvm) for details. + #### Registration of multiple listeners and trackers [JAVA-2951](https://datastax-oss.atlassian.net/browse/JAVA-2951) introduced the ability to register From abd011c795a99a9401b7c15380f371aaa541b94c Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 16:55:46 +0200 Subject: [PATCH 182/395] [maven-release-plugin] prepare release 4.13.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index e47c97e29e3..2f0b8dca529 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-core-shaded - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-mapper-processor - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-mapper-runtime - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-query-builder - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-test-infra - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-metrics-micrometer - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss java-driver-metrics-microprofile - 4.13.0-SNAPSHOT + 4.13.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index ad368ee9259..cfe61ce8327 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 34d1b7478b6..7be614c5be2 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 2a579b0440a..45f971071ed 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index b95827307ad..95ffacf5e38 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.13.0-SNAPSHOT + 4.13.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index c5b6cc77594..bf9cae4d6ec 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index cc14f3d2e8b..064faf59375 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 68d76446bf1..5038565cad2 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 8c2755c7c62..02b556a4770 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 78c04909c55..30e8c909b4c 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 12e8b9641dc..719bba02ef8 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index ac1097f76b3..18c7eb6d79a 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.13.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 3ae527917a1..c44abaeaec8 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index d29046b4934..21cb1c93a4c 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0-SNAPSHOT + 4.13.0 java-driver-test-infra bundle From 522df5ab020b285206f50231aac1511181d078bd Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 30 Jul 2021 16:55:57 +0200 Subject: [PATCH 183/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 2f0b8dca529..a228074bf7a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.13.0 + 4.13.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index cfe61ce8327..b84dd855234 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 7be614c5be2..13dfaca11fa 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 45f971071ed..0da803804e4 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 95ffacf5e38..130204c6918 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.13.0 + 4.13.1-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index bf9cae4d6ec..20fd13ea85d 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 064faf59375..84b0e39d825 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 5038565cad2..bf9be82718c 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 02b556a4770..82b113dd1a8 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 30e8c909b4c..af31fdc5fc2 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 719bba02ef8..7cf7adf20bc 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 18c7eb6d79a..9de5ceb0e30 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.13.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index c44abaeaec8..069af2819e9 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 21cb1c93a4c..6578516f10e 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.0 + 4.13.1-SNAPSHOT java-driver-test-infra bundle From 2e1250635f0713d523f14bb50e8cd6f21bebc9fc Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 10 Aug 2021 11:57:56 +0200 Subject: [PATCH 184/395] Minor fixes to doc pages --- manual/core/graalvm/README.md | 10 +++++----- manual/core/non_blocking/README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/manual/core/graalvm/README.md b/manual/core/graalvm/README.md index 04983f46ecc..6ee713a2b30 100644 --- a/manual/core/graalvm/README.md +++ b/manual/core/graalvm/README.md @@ -1,9 +1,9 @@ -## Using the driver in GraalVM native images +## GraalVM native images ### Quick overview -* [GraalVM Native images](https://www.graalvm.org/reference-manual/native-image/) using the driver - can be built with no additional configuration starting with driver 4.13.0. +* [GraalVM native images](https://www.graalvm.org/reference-manual/native-image/) can be built with + no additional configuration starting with driver 4.13.0. * But extra configurations are required in a few cases: * When using [reactive programming](../reactive); * When using [Jackson](../integration#Jackson); @@ -132,7 +132,7 @@ following configurations must be added: ### Using the Jackson JSON library -[Jackson](https://github.com/FasterXML/jackson) is used in [a few places](../integration#Jackson) in +[Jackson](https://github.com/FasterXML/jackson) is used in [a few places](../integration#jackson) in the driver, but is an optional dependency; if you intend to use Jackson, the following configurations must be added: @@ -223,7 +223,7 @@ configuration is required: ### Native calls -The driver performs a few [native calls](../integration#Native-libraries) using +The driver performs a few [native calls](../integration#native-libraries) using [JNR](https://github.com/jnr). Starting with driver 4.7.0, native calls are also possible in a GraalVM native image, without any diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index dbffcff1fdb..8876022f2f0 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -29,7 +29,7 @@ primitives such as atomic variables and CAS (compare-and-swap) instructions. A further distinction is generally established between "lock-free" and "wait-free" algorithms: the former ones allow progress of the overall system, while the latter ones allow each thread to make -progress at any time. This distinction is however rather theoretical and is outside of the scope of +progress at any time. This distinction is however rather theoretical and is outside the scope of this document. [lock-free]: https://www.baeldung.com/lock-free-programming From 85b527faffa3fafca16a05d763a7be6de9e0a58a Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 10 Aug 2021 11:58:44 +0200 Subject: [PATCH 185/395] Wait until metrics are asserted --- .../continuous/ContinuousPagingITBase.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java index c2bc7de9791..58a76fe1c61 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingITBase.java @@ -16,6 +16,7 @@ package com.datastax.dse.driver.api.core.cql.continuous; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import com.codahale.metrics.Timer; import com.datastax.dse.driver.api.core.config.DseDriverOption; @@ -30,6 +31,7 @@ import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; import com.datastax.oss.driver.api.core.metrics.Metrics; import com.tngtech.java.junit.dataprovider.DataProvider; +import java.time.Duration; import java.util.UUID; public abstract class ContinuousPagingITBase { @@ -111,15 +113,33 @@ protected void validateMetrics(CqlSession session) { .as("assert metrics.getNodeMetric(node, DefaultNodeMetric.CQL_MESSAGES) present") .isPresent(); Timer messages = (Timer) metrics.getNodeMetric(node, DefaultNodeMetric.CQL_MESSAGES).get(); - assertThat(messages.getCount()).as("assert messages.getCount() >= 0").isGreaterThan(0); - assertThat(messages.getMeanRate()).as("assert messages.getMeanRate() >= 0").isGreaterThan(0); + await() + .atMost(Duration.ofSeconds(5)) + .untilAsserted( + () -> { + assertThat(messages.getCount()) + .as("assert messages.getCount() >= 0") + .isGreaterThan(0); + assertThat(messages.getMeanRate()) + .as("assert messages.getMeanRate() >= 0") + .isGreaterThan(0); + }); assertThat(metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS)) .as("assert metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS) present") .isPresent(); Timer requests = (Timer) metrics.getSessionMetric(DseSessionMetric.CONTINUOUS_CQL_REQUESTS).get(); - assertThat(requests.getCount()).as("assert requests.getCount() >= 0").isGreaterThan(0); - assertThat(requests.getMeanRate()).as("assert requests.getMeanRate() >= 0").isGreaterThan(0); + await() + .atMost(Duration.ofSeconds(5)) + .untilAsserted( + () -> { + assertThat(requests.getCount()) + .as("assert requests.getCount() >= 0") + .isGreaterThan(0); + assertThat(requests.getMeanRate()) + .as("assert requests.getMeanRate() >= 0") + .isGreaterThan(0); + }); } public static class Options { From ec387044d1a6b77c6b00ac28d90cdff9ad44bb93 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 10 Aug 2021 14:03:48 +0200 Subject: [PATCH 186/395] Raise test timeouts --- .../oss/driver/core/tracker/RequestLoggerIT.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java index 41a462ae1c8..252c22c5f7b 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestLoggerIT.java @@ -214,7 +214,7 @@ public void should_log_successful_request() { sessionRuleRequest.session().execute(QUERY); // Then - verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(5000)).doAppend(loggingEventCaptor.capture()); assertThat(loggingEventCaptor.getValue().getFormattedMessage()) .contains("Success", "[0 values]", QUERY) .matches(WITH_PER_REQUEST_PREFIX); @@ -229,7 +229,7 @@ public void should_log_successful_request_with_defaults() { sessionRuleDefaults.session().execute(QUERY); // Then - verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(5000)).doAppend(loggingEventCaptor.capture()); assertThat(loggingEventCaptor.getValue().getFormattedMessage()) .contains("Success", "[0 values]", QUERY) .matches(WITH_PER_REQUEST_PREFIX); @@ -249,7 +249,7 @@ public void should_log_failed_request_with_stack_trace() { } // Then - verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(5000)).doAppend(loggingEventCaptor.capture()); ILoggingEvent log = loggingEventCaptor.getValue(); assertThat(log.getFormattedMessage()) .contains("Error", "[0 values]", QUERY) @@ -272,7 +272,7 @@ public void should_log_failed_request_with_stack_trace_with_defaults() { } // Then - verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(5000)).doAppend(loggingEventCaptor.capture()); ILoggingEvent log = loggingEventCaptor.getValue(); assertThat(log.getFormattedMessage()) .contains("Error", "[0 values]", QUERY, ServerError.class.getName()) @@ -295,7 +295,7 @@ public void should_log_failed_request_without_stack_trace() { } // Then - verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(5000)).doAppend(loggingEventCaptor.capture()); ILoggingEvent log = loggingEventCaptor.getValue(); assertThat(log.getFormattedMessage()) .contains("Error", "[0 values]", QUERY, ServerError.class.getName()) @@ -314,7 +314,7 @@ public void should_log_slow_request() { .execute(SimpleStatement.builder(QUERY).setExecutionProfileName("low-threshold").build()); // Then - verify(appender, timeout(500)).doAppend(loggingEventCaptor.capture()); + verify(appender, timeout(5000)).doAppend(loggingEventCaptor.capture()); assertThat(loggingEventCaptor.getValue().getFormattedMessage()) .contains("Slow", "[0 values]", QUERY) .matches(WITH_PER_REQUEST_PREFIX); @@ -359,7 +359,7 @@ public void should_log_failed_nodes_on_successful_request() { .execute(SimpleStatement.builder(QUERY).setExecutionProfileName("sorting-lbp").build()); // Then - verify(appender, new Timeout(500, VerificationModeFactory.times(3))) + verify(appender, new Timeout(5000, VerificationModeFactory.times(3))) .doAppend(loggingEventCaptor.capture()); List events = loggingEventCaptor.getAllValues(); assertThat(events.get(0).getFormattedMessage()) @@ -392,7 +392,7 @@ public void should_log_successful_nodes_on_successful_request() { sessionRuleNode.session().execute(QUERY); // Then - verify(appender, new Timeout(500, VerificationModeFactory.times(2))) + verify(appender, new Timeout(5000, VerificationModeFactory.times(2))) .doAppend(loggingEventCaptor.capture()); List events = loggingEventCaptor.getAllValues(); assertThat(events.get(0).getFormattedMessage()) From 2a20841f160aa7fa4d429881bc359b538fc94488 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 10 Aug 2021 14:37:44 +0200 Subject: [PATCH 187/395] Raise server-side timeouts for TokenIT tests --- .../core/metadata/ByteOrderedTokenIT.java | 9 ++++++++- .../core/metadata/ByteOrderedTokenVnodesIT.java | 4 ++++ .../driver/core/metadata/Murmur3TokenIT.java | 9 ++++++++- .../core/metadata/Murmur3TokenVnodesIT.java | 9 ++++++++- .../oss/driver/core/metadata/RandomTokenIT.java | 9 ++++++++- .../core/metadata/RandomTokenVnodesIT.java | 4 ++++ .../oss/driver/core/metadata/TokenITBase.java | 17 ++++++++++++++--- 7 files changed, 54 insertions(+), 7 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java index 63473704c8a..28795b6c4c4 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java @@ -36,7 +36,14 @@ public class ByteOrderedTokenIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = - CustomCcmRule.builder().withNodes(3).withCreateOption("-p ByteOrderedPartitioner").build(); + CustomCcmRule.builder() + .withNodes(3) + .withCreateOption("-p ByteOrderedPartitioner") + .withCassandraConfiguration("range_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("read_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("write_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("request_timeout_in_ms", 45_000) + .build(); private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java index 62fd20719dd..1009013c734 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java @@ -40,6 +40,10 @@ public class ByteOrderedTokenVnodesIT extends TokenITBase { .withNodes(3) .withCreateOption("-p ByteOrderedPartitioner") .withCreateOption("--vnodes") + .withCassandraConfiguration("range_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("read_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("write_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("request_timeout_in_ms", 45_000) .build(); private static final SessionRule SESSION_RULE = diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenIT.java index e3a6faaaa44..9b3e4d77447 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenIT.java @@ -29,7 +29,14 @@ public class Murmur3TokenIT extends TokenITBase { - private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().withNodes(3).build(); + private static final CustomCcmRule CCM_RULE = + CustomCcmRule.builder() + .withNodes(3) + .withCassandraConfiguration("range_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("read_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("write_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("request_timeout_in_ms", 45_000) + .build(); private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java index 28c219e8a91..3dcf8f88b17 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java @@ -35,7 +35,14 @@ public class Murmur3TokenVnodesIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = - CustomCcmRule.builder().withNodes(3).withCreateOption("--vnodes").build(); + CustomCcmRule.builder() + .withNodes(3) + .withCreateOption("--vnodes") + .withCassandraConfiguration("range_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("read_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("write_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("request_timeout_in_ms", 45_000) + .build(); private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenIT.java index 4134fd8c8a2..075679ea1d1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenIT.java @@ -30,7 +30,14 @@ public class RandomTokenIT extends TokenITBase { private static final CustomCcmRule CCM_RULE = - CustomCcmRule.builder().withNodes(3).withCreateOption("-p RandomPartitioner").build(); + CustomCcmRule.builder() + .withNodes(3) + .withCreateOption("-p RandomPartitioner") + .withCassandraConfiguration("range_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("read_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("write_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("request_timeout_in_ms", 45_000) + .build(); private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java index 08b226bdc51..1545bd46104 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java @@ -39,6 +39,10 @@ public class RandomTokenVnodesIT extends TokenITBase { .withNodes(3) .withCreateOption("-p RandomPartitioner") .withCreateOption("--vnodes") + .withCassandraConfiguration("range_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("read_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("write_request_timeout_in_ms", 45_000) + .withCassandraConfiguration("request_timeout_in_ms", 45_000) .build(); private static final SessionRule SESSION_RULE = diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java index 4ebe1bc4e7b..4ca72c94be3 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/TokenITBase.java @@ -102,6 +102,7 @@ public void should_be_consistent_with_range_queries() { int key = 1; ProtocolVersion protocolVersion = session().getContext().getProtocolVersion(); ByteBuffer serializedKey = TypeCodecs.INT.encodePrimitive(key, protocolVersion); + assertThat(serializedKey).isNotNull(); Set replicas = tokenMap.getReplicas(KS1, serializedKey); assertThat(replicas).hasSize(1); Node replica = replicas.iterator().next(); @@ -133,7 +134,7 @@ public void should_be_consistent_with_range_queries() { private List rangeQuery(PreparedStatement rangeStatement, TokenRange range) { List rows = Lists.newArrayList(); for (TokenRange subRange : range.unwrap()) { - Statement statement = rangeStatement.bind(subRange.getStart(), subRange.getEnd()); + Statement statement = rangeStatement.bind(subRange.getStart(), subRange.getEnd()); session().execute(statement).forEach(rows::add); } return rows; @@ -156,10 +157,11 @@ private List rangeQuery(PreparedStatement rangeStatement, TokenRange range) public void should_get_token_from_row_and_set_token_in_query() { ResultSet rs = session().execute("SELECT token(i) FROM foo WHERE i = 1"); Row row = rs.one(); + assertThat(row).isNotNull(); // Get by index: Token token = row.getToken(0); - assertThat(token).isInstanceOf(expectedTokenType); + assertThat(token).isNotNull().isInstanceOf(expectedTokenType); // Get by name: the generated column name depends on the Cassandra version. String tokenColumnName = @@ -173,10 +175,12 @@ public void should_get_token_from_row_and_set_token_in_query() { // Bind with setToken by index row = session().execute(pst.bind().setToken(0, token)).one(); + assertThat(row).isNotNull(); assertThat(row.getInt(0)).isEqualTo(1); // Bind with setToken by name row = session().execute(pst.bind().setToken("partition key token", token)).one(); + assertThat(row).isNotNull(); assertThat(row.getInt(0)).isEqualTo(1); } @@ -190,17 +194,20 @@ public void should_get_token_from_row_and_set_token_in_query() { @Test public void should_get_token_from_row_and_set_token_in_query_with_binding_and_aliasing() { Row row = session().execute("SELECT token(i) AS t FROM foo WHERE i = 1").one(); + assertThat(row).isNotNull(); Token token = row.getToken("t"); - assertThat(token).isInstanceOf(expectedTokenType); + assertThat(token).isNotNull().isInstanceOf(expectedTokenType); PreparedStatement pst = session().prepare("SELECT * FROM foo WHERE token(i) = :myToken"); row = session().execute(pst.bind().setToken("myToken", token)).one(); + assertThat(row).isNotNull(); assertThat(row.getInt(0)).isEqualTo(1); row = session() .execute(SimpleStatement.newInstance("SELECT * FROM foo WHERE token(i) = ?", token)) .one(); + assertThat(row).isNotNull(); assertThat(row.getInt(0)).isEqualTo(1); } @@ -216,6 +223,7 @@ public void should_get_token_from_row_and_set_token_in_query_with_binding_and_al @Test(expected = IllegalArgumentException.class) public void should_raise_exception_when_getting_token_on_non_token_column() { Row row = session().execute("SELECT i FROM foo WHERE i = 1").one(); + assertThat(row).isNotNull(); row.getToken(0); } @@ -237,11 +245,13 @@ public void should_expose_consistent_ranges() { } private void checkRanges(Session session) { + assertThat(session.getMetadata().getTokenMap()).isPresent(); TokenMap tokenMap = session.getMetadata().getTokenMap().get(); checkRanges(tokenMap.getTokenRanges()); } private void checkRanges(Session session, CqlIdentifier keyspace, int replicationFactor) { + assertThat(session.getMetadata().getTokenMap()).isPresent(); TokenMap tokenMap = session.getMetadata().getTokenMap().get(); List allRangesWithDuplicates = Lists.newArrayList(); @@ -347,6 +357,7 @@ public void should_create_token_from_partition_key() { TokenMap tokenMap = getTokenMap(); Row row = session().execute("SELECT token(i) FROM foo WHERE i = 1").one(); + assertThat(row).isNotNull(); Token expected = row.getToken(0); ProtocolVersion protocolVersion = session().getContext().getProtocolVersion(); From ebe7a5e0c2c22c64d429909a7d4f7ca45af7a456 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 10 Aug 2021 14:40:39 +0200 Subject: [PATCH 188/395] Reduce weeknights schedule with JDK 8 --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index cc8e0afc7da..0f9a28265d3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -356,8 +356,8 @@ pipeline { // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) parameterizedCron(branchPatternCron.matcher(env.BRANCH_NAME).matches() ? """ # Every weeknight (Monday - Friday) around 2:00 AM - ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0, DSE 6.7 and DSE 6.8 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7 dse-6.8;CI_SCHEDULE_JABBA_VERSION=1.8 + ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0 and DSE 6.7 + H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7;CI_SCHEDULE_JABBA_VERSION=1.8 ### JDK11 tests against 3.11, 4.0 and DSE 6.8 H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 # Every weekend (Sunday) around 12:00 PM noon From 99f441583854d1a9b7be9b8899170da5f7d1813f Mon Sep 17 00:00:00 2001 From: Madhavan Date: Thu, 12 Aug 2021 07:26:15 -0400 Subject: [PATCH 189/395] Update AstraDB links (#1569) --- manual/cloud/README.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/manual/cloud/README.md b/manual/cloud/README.md index 161a8308c73..f483d9ae918 100644 --- a/manual/cloud/README.md +++ b/manual/cloud/README.md @@ -7,14 +7,13 @@ driver is configured in an application and that you will need to obtain a *secur ### Prerequisites 1. [Download][Download Maven] and [install][Install Maven] Maven. -2. Create an Astra database on [GCP][Create an Astra database - GCP] or - [AWS][Create an Astra database - AWS]; alternatively, have a team member provide access to their - Astra database (instructions for [GCP][Access an Astra database - GCP] and - [AWS][Access an Astra database - AWS]) to obtain database connection details. +2. Create an Astra database on [AWS/Azure/GCP][Create an Astra database - AWS/Azure/GCP]; + alternatively, have a team member provide access to their + Astra database (instructions for [AWS/Azure/GCP][Access an Astra database - AWS/Azure/GCP] to + obtain database connection details. 3. Download the secure connect bundle (instructions for - [GCP][Download the secure connect bundle - GCP] and - [AWS][Download the secure connect bundle - AWS]), that contains connection information such as - contact points and certificates. + [AWS/Azure/GCP][Download the secure connect bundle - AWS/Azure/GCP], that contains connection + information such as contact points and certificates. ### Procedure @@ -125,11 +124,8 @@ public class Main { [Download Maven]: https://maven.apache.org/download.cgi [Install Maven]: https://maven.apache.org/install.html -[Create an Astra database - GCP]: https://docs.datastax.com/en/astra/gcp/doc/dscloud/astra/dscloudGettingStarted.html#dscloudCreateCluster -[Create an Astra database - AWS]: https://docs.datastax.com/en/astra/aws/doc/dscloud/astra/dscloudGettingStarted.html#dscloudCreateCluster -[Access an Astra database - GCP]: https://docs.datastax.com/en/astra/gcp/doc/dscloud/astra/dscloudShareClusterDetails.html -[Access an Astra database - AWS]: https://docs.datastax.com/en/astra/aws/doc/dscloud/astra/dscloudShareClusterDetails.html -[Download the secure connect bundle - GCP]: https://docs.datastax.com/en/astra/gcp/doc/dscloud/astra/dscloudObtainingCredentials.html -[Download the secure connect bundle - AWS]: https://docs.datastax.com/en/astra/aws/doc/dscloud/astra/dscloudObtainingCredentials.html +[Create an Astra database - AWS/Azure/GCP]: https://docs.datastax.com/en/astra/docs/creating-your-astra-database.html +[Access an Astra database - AWS/Azure/GCP]: https://docs.datastax.com/en/astra/docs/obtaining-database-credentials.html#_sharing_your_secure_connect_bundle +[Download the secure connect bundle - AWS/Azure/GCP]: https://docs.datastax.com/en/astra/docs/obtaining-database-credentials.html [minimal project structure]: ../core/integration/#minimal-project-structure [driver documentation]: ../core/configuration/ From 364d9e8b59723201516c3c221085242f0b5d8695 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 13 Aug 2021 14:07:18 +0200 Subject: [PATCH 190/395] Minor javadoc fixes --- .../oss/driver/api/core/connection/BusyConnectionException.java | 2 +- .../driver/internal/core/adminrequest/AdminRequestHandler.java | 2 +- .../com/datastax/oss/driver/internal/core/pool/ChannelPool.java | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/connection/BusyConnectionException.java b/core/src/main/java/com/datastax/oss/driver/api/core/connection/BusyConnectionException.java index bbe513351ba..a215bc3347a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/connection/BusyConnectionException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/connection/BusyConnectionException.java @@ -25,7 +25,7 @@ * requests. * *

    This might happen under heavy load. The driver will automatically try the next node in the - * query plan. Therefore the only way that the client can observe this exception is as part of a + * query plan. Therefore, the only way that the client can observe this exception is as part of a * {@link AllNodesFailedException}. */ public class BusyConnectionException extends DriverException { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/adminrequest/AdminRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/adminrequest/AdminRequestHandler.java index 60e033c344d..148c1099a04 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/adminrequest/AdminRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/adminrequest/AdminRequestHandler.java @@ -47,7 +47,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** Handles the lifecyle of an admin request (such as a node refresh or schema refresh query). */ +/** Handles the lifecycle of an admin request (such as a node refresh or schema refresh query). */ @ThreadSafe public class AdminRequestHandler implements ResponseCallback { private static final Logger LOG = LoggerFactory.getLogger(AdminRequestHandler.class); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/pool/ChannelPool.java b/core/src/main/java/com/datastax/oss/driver/internal/core/pool/ChannelPool.java index 24891972763..42b7c9e90c8 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/pool/ChannelPool.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/pool/ChannelPool.java @@ -143,7 +143,6 @@ public boolean isInvalidKeyspace() { * request path, and we want to avoid complex check-then-act semantics; therefore this might * race and return a channel that is already closed, or {@code null}. In those cases, it is up * to the caller to fail fast and move to the next node. - *

    There is no need to return the channel. */ public DriverChannel next() { return channels.next(); From 4dc7de39a1a88fff52d647a3757238fc672f4ae2 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 13 Aug 2021 14:08:13 +0200 Subject: [PATCH 191/395] Make field final in StreamIdGenerator --- .../oss/driver/internal/core/channel/StreamIdGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/StreamIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/StreamIdGenerator.java index 934eeefc061..451bb7cff6e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/StreamIdGenerator.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/StreamIdGenerator.java @@ -34,7 +34,7 @@ class StreamIdGenerator { private final int maxAvailableIds; // unset = available, set = borrowed (note that this is the opposite of the 3.x implementation) private final BitSet ids; - private AtomicInteger availableIds; + private final AtomicInteger availableIds; StreamIdGenerator(int maxAvailableIds) { this.maxAvailableIds = maxAvailableIds; From 387f75714da6e23f0f68cea2815a5e9088a3ae74 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Tue, 17 Aug 2021 11:55:59 +0200 Subject: [PATCH 192/395] Raise test timeouts in ShutdownIT --- .../java/com/datastax/oss/driver/core/session/ShutdownIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java index 9f84c9144de..0e5dd780cec 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java @@ -120,7 +120,7 @@ public void should_fail_requests_when_session_is_closed() throws Exception { } TimeUnit.MILLISECONDS.sleep(100); session.forceCloseAsync(); - assertThat(gotSessionClosedError.await(1, TimeUnit.SECONDS)) + assertThat(gotSessionClosedError.await(10, TimeUnit.SECONDS)) .as("Expected to get the 'Session is closed' error shortly after shutting down") .isTrue(); requestExecutor.shutdownNow(); From b0b640e4fe9b73df96407f501718be4dba7d441e Mon Sep 17 00:00:00 2001 From: Ankit Barsainya <71305148+AnkitBarsainyaPSL@users.noreply.github.com> Date: Wed, 18 Aug 2021 15:14:33 +0530 Subject: [PATCH 193/395] Update log message to inform about incorrect CL for read repair (#1571) --- .../oss/driver/api/core/servererrors/ReadTimeoutException.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java index cac44b4983d..21afa245e13 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.java @@ -45,7 +45,8 @@ public ReadTimeoutException( this( coordinator, String.format( - "Cassandra timeout during read query at consistency %s (%s)", + "Cassandra timeout during read query at consistency %s (%s). " + + "In case this was generated during read repair, the consistency level is not representative of the actual consistency.", consistencyLevel, formatDetails(received, blockFor, dataPresent)), consistencyLevel, received, From 6da12e31e60d132b1f50a3004d45397c4db912ae Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 19 Aug 2021 11:14:53 +0200 Subject: [PATCH 194/395] Raise verify timeout in ChannelPoolTestBase --- .../oss/driver/internal/core/pool/ChannelPoolResizeTest.java | 2 +- .../oss/driver/internal/core/pool/ChannelPoolTestBase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolResizeTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolResizeTest.java index da1c5e3d2a2..acd7be61d3e 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolResizeTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolResizeTest.java @@ -125,7 +125,7 @@ public void should_shrink_during_reconnection() throws Exception { factoryHelper.waitForCalls(node, 2); - // Pool should have shrinked back to 2. We keep the most recent channels so 1 and 2 get closed. + // Pool should have shrunk back to 2. We keep the most recent channels so 1 and 2 get closed. inOrder.verify(eventBus, VERIFY_TIMEOUT.times(2)).fire(ChannelEvent.channelOpened(node)); inOrder.verify(eventBus, VERIFY_TIMEOUT.times(2)).fire(ChannelEvent.channelClosed(node)); inOrder.verify(eventBus, VERIFY_TIMEOUT).fire(ChannelEvent.reconnectionStopped(node)); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolTestBase.java b/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolTestBase.java index cc18e7d2842..7e9b1aa5b5e 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolTestBase.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/pool/ChannelPoolTestBase.java @@ -50,7 +50,7 @@ abstract class ChannelPoolTestBase { /** How long we wait when verifying mocks for async invocations */ - protected static final VerificationWithTimeout VERIFY_TIMEOUT = timeout(500); + protected static final VerificationWithTimeout VERIFY_TIMEOUT = timeout(2000); @Mock protected InternalDriverContext context; @Mock private DriverConfig config; From 2a1e37a21cc6da8d9f78c2001a1c1c9edd9c79a7 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Thu, 19 Aug 2021 11:16:45 +0200 Subject: [PATCH 195/395] Raise sleep time in ShutdownIT --- .../java/com/datastax/oss/driver/core/session/ShutdownIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java index 0e5dd780cec..6a1bac5cc9b 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ShutdownIT.java @@ -118,7 +118,7 @@ public void should_fail_requests_when_session_is_closed() throws Exception { } }); } - TimeUnit.MILLISECONDS.sleep(100); + TimeUnit.MILLISECONDS.sleep(1000); session.forceCloseAsync(); assertThat(gotSessionClosedError.await(10, TimeUnit.SECONDS)) .as("Expected to get the 'Session is closed' error shortly after shutting down") From 0a7b1c86d077b74ceb203bd356b214727ab416e1 Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Tue, 24 Aug 2021 01:13:50 -0700 Subject: [PATCH 196/395] JAVA-2959: Don't throw NoNodeAvailableException when all connections busy (#1570) For cases in which there are no connections available to send requests to a Node in the query plan, collect the error rather than silently skipping over the node. The error will be thrown as part of an AllNodesFailedException if all nodes fail. This can happen when we've saturated the max in-flight requests across all nodes or when the request is directed to a particular node and it has no connections available (or all its connections are saturated). Note that in the latter case we used to throw a NoNodeAvailableException but we now throw AllNodesFailedException. --- changelog/README.md | 4 ++ .../ContinuousRequestHandlerBase.java | 11 ++-- .../core/graph/GraphRequestHandler.java | 3 + .../api/core/NodeUnavailableException.java | 60 +++++++++++++++++++ .../internal/core/cql/CqlPrepareHandler.java | 3 + .../internal/core/cql/CqlRequestHandler.java | 3 + ...ousCqlRequestHandlerNodeTargetingTest.java | 13 +++- .../core/cql/CqlPrepareHandlerTest.java | 36 +++++++++++ .../core/cql/CqlRequestHandlerTest.java | 42 +++++++++++++ upgrade_guide/README.md | 9 +++ 10 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/NodeUnavailableException.java diff --git a/changelog/README.md b/changelog/README.md index 48a16bc6f28..9b3c2f4a609 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,10 @@ +### 4.14.0 (in progress) + +- [improvement] JAVA-2959: Don't throw NoNodeAvailableException when all connections busy + ### 4.13.0 - [improvement] JAVA-2940: Add GraalVM native image build configurations diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java index f97bc684e37..91fc1ef2f3a 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java @@ -24,6 +24,7 @@ import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.ProtocolVersion; import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; @@ -348,6 +349,8 @@ private void sendRequest( channel = session.getChannel(node, logPrefix); if (channel != null) { break; + } else { + recordError(node, new NodeUnavailableException(node)); } } } @@ -455,6 +458,10 @@ CompletableFuture getPendingResult() { } } + private void recordError(@NonNull Node node, @NonNull Throwable error) { + errors.add(new AbstractMap.SimpleEntry<>(node, error)); + } + /** * Handles the interaction with a single node in the query plan. * @@ -1433,10 +1440,6 @@ private void reenableAutoReadIfNeeded() { // ERROR HANDLING - private void recordError(@NonNull Node node, @NonNull Throwable error) { - errors.add(new AbstractMap.SimpleEntry<>(node, error)); - } - private void trackNodeError(@NonNull Node node, @NonNull Throwable error) { if (nodeErrorReported.compareAndSet(false, true)) { long latencyNanos = System.nanoTime() - this.messageStartTimeNanos; diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java index ca84f1c634a..a710f447512 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java @@ -24,6 +24,7 @@ import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.DriverException; import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; @@ -253,6 +254,8 @@ private void sendRequest( channel = session.getChannel(node, logPrefix); if (channel != null) { break; + } else { + recordError(node, new NodeUnavailableException(node)); } } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/NodeUnavailableException.java b/core/src/main/java/com/datastax/oss/driver/api/core/NodeUnavailableException.java new file mode 100644 index 00000000000..69c3dca0691 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/NodeUnavailableException.java @@ -0,0 +1,60 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core; + +import com.datastax.oss.driver.api.core.metadata.Node; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Objects; + +/** + * Indicates that a {@link Node} was selected in a query plan, but it had no connection available. + * + *

    A common reason to encounter this error is when the configured number of connections per node + * and requests per connection is not high enough to absorb the overall request rate. This can be + * mitigated by tuning the following options: + * + *

      + *
    • {@code advanced.connection.pool.local.size}; + *
    • {@code advanced.connection.pool.remote.size}; + *
    • {@code advanced.connection.max-requests-per-connection}. + *
    + * + * See {@code reference.conf} for more details. + * + *

    Another possibility is when you are trying to direct a request {@linkplain + * com.datastax.oss.driver.api.core.cql.Statement#setNode(Node) to a particular node}, but that node + * has no connections available. + */ +public class NodeUnavailableException extends DriverException { + + private final Node node; + + public NodeUnavailableException(Node node) { + super("No connection was available to " + node, null, null, true); + this.node = Objects.requireNonNull(node); + } + + @NonNull + public Node getNode() { + return node; + } + + @Override + @NonNull + public DriverException copy() { + return new NodeUnavailableException(node); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java index d60a6c65260..68fa386b12b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java @@ -18,6 +18,7 @@ import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.ProtocolVersion; import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; @@ -188,6 +189,8 @@ private void sendRequest(PrepareRequest request, Node node, int retryCount) { channel = session.getChannel(node, logPrefix); if (channel != null) { break; + } else { + recordError(node, new NodeUnavailableException(node)); } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java index 743d11c9ad4..dba2dc38460 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.DriverException; import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; @@ -251,6 +252,8 @@ private void sendRequest( channel = session.getChannel(node, logPrefix); if (channel != null) { break; + } else { + recordError(node, new NodeUnavailableException(node)); } } } diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerNodeTargetingTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerNodeTargetingTest.java index 3d560d964b0..f245d8599ae 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerNodeTargetingTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousCqlRequestHandlerNodeTargetingTest.java @@ -25,13 +25,17 @@ import com.datastax.dse.driver.DseTestFixtures; import com.datastax.dse.driver.api.core.DseProtocolVersion; import com.datastax.dse.driver.api.core.cql.continuous.ContinuousAsyncResultSet; -import com.datastax.oss.driver.api.core.NoNodeAvailableException; +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.internal.core.cql.RequestHandlerTestHarness; import com.datastax.oss.driver.internal.core.metadata.LoadBalancingPolicyWrapper; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletionStage; import org.junit.Test; import org.mockito.InOrder; @@ -67,7 +71,12 @@ public void should_fail_if_targeted_node_not_available(DseProtocolVersion versio assertThatStage(resultSetFuture) .isFailed( error -> { - assertThat(error).isInstanceOf(NoNodeAvailableException.class); + assertThat(error).isInstanceOf(AllNodesFailedException.class); + Map> errors = + ((AllNodesFailedException) error).getAllErrors(); + assertThat(errors).hasSize(1); + List nodeErrors = errors.values().iterator().next(); + assertThat(nodeErrors).singleElement().isInstanceOf(NodeUnavailableException.class); invocations .verify(loadBalancingPolicy, never()) .newQueryPlan(any(Request.class), anyString(), any(Session.class)); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java index 0bafdb41305..f0bf319e581 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandlerTest.java @@ -25,6 +25,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.ColumnDefinitions; @@ -47,6 +49,7 @@ import com.datastax.oss.protocol.internal.response.result.RowsMetadata; import com.datastax.oss.protocol.internal.util.Bytes; import java.nio.ByteBuffer; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletionStage; import org.junit.Before; @@ -228,6 +231,39 @@ public void should_not_retry_initial_prepare_if_unrecoverable_error() { } } + @Test + public void should_fail_if_nodes_unavailable() { + RequestHandlerTestHarness.Builder harnessBuilder = RequestHandlerTestHarness.builder(); + try (RequestHandlerTestHarness harness = + harnessBuilder.withEmptyPool(node1).withEmptyPool(node2).build()) { + CompletionStage prepareFuture = + new CqlPrepareHandler(PREPARE_REQUEST, harness.getSession(), harness.getContext(), "test") + .handle(); + assertThatStage(prepareFuture) + .isFailed( + error -> { + assertThat(error).isInstanceOf(AllNodesFailedException.class); + Map> allErrors = + ((AllNodesFailedException) error).getAllErrors(); + assertThat(allErrors).hasSize(2); + assertThat(allErrors) + .hasEntrySatisfying( + node1, + nodeErrors -> + assertThat(nodeErrors) + .singleElement() + .isInstanceOf(NodeUnavailableException.class)); + assertThat(allErrors) + .hasEntrySatisfying( + node2, + nodeErrors -> + assertThat(nodeErrors) + .singleElement() + .isInstanceOf(NodeUnavailableException.class)); + }); + } + } + @Test public void should_fail_if_retry_policy_ignores_error() { RequestHandlerTestHarness.Builder harnessBuilder = diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java index 5f41fc42f62..42cd492aad9 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java @@ -21,9 +21,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.DriverTimeoutException; import com.datastax.oss.driver.api.core.NoNodeAvailableException; +import com.datastax.oss.driver.api.core.NodeUnavailableException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import com.datastax.oss.driver.api.core.cql.BoundStatement; @@ -32,6 +34,7 @@ import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.internal.core.session.RepreparePayload; import com.datastax.oss.driver.internal.core.util.concurrent.CapturingTimer.CapturedTimeout; import com.datastax.oss.protocol.internal.request.Prepare; @@ -43,6 +46,8 @@ import java.time.Duration; import java.util.Collections; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -105,6 +110,43 @@ public void should_fail_if_no_node_available() { } } + @Test + public void should_fail_if_nodes_unavailable() { + RequestHandlerTestHarness.Builder harnessBuilder = RequestHandlerTestHarness.builder(); + try (RequestHandlerTestHarness harness = + harnessBuilder.withEmptyPool(node1).withEmptyPool(node2).build()) { + CompletionStage resultSetFuture = + new CqlRequestHandler( + UNDEFINED_IDEMPOTENCE_STATEMENT, + harness.getSession(), + harness.getContext(), + "test") + .handle(); + assertThatStage(resultSetFuture) + .isFailed( + error -> { + assertThat(error).isInstanceOf(AllNodesFailedException.class); + Map> allErrors = + ((AllNodesFailedException) error).getAllErrors(); + assertThat(allErrors).hasSize(2); + assertThat(allErrors) + .hasEntrySatisfying( + node1, + nodeErrors -> + assertThat(nodeErrors) + .singleElement() + .isInstanceOf(NodeUnavailableException.class)); + assertThat(allErrors) + .hasEntrySatisfying( + node2, + nodeErrors -> + assertThat(nodeErrors) + .singleElement() + .isInstanceOf(NodeUnavailableException.class)); + }); + } + } + @Test public void should_time_out_if_first_node_takes_too_long_to_respond() throws Exception { RequestHandlerTestHarness.Builder harnessBuilder = RequestHandlerTestHarness.builder(); diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 0be2af16a1e..e48a75ceb4e 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,14 @@ ## Upgrade guide +### 4.14.0 + +#### AllNodesFailedException instead of NoNodeAvailableException in certain cases + +[JAVA-2959](https://datastax-oss.atlassian.net/browse/JAVA-2959) changed the behavior for when a +request cannot be executed because all nodes tried were busy. Previously you would get back a +`NoNodeAvailableException` but you will now get back an `AllNodesFailedException` where the +`getAllErrors` map contains a `NodeUnavailableException` for that node. + ### 4.13.0 #### Enhanced support for GraalVM native images From d954af9d59c6493c78cbbcdfbada89c1e341087a Mon Sep 17 00:00:00 2001 From: Jeff DiNoto Date: Wed, 5 Jan 2022 14:07:14 -0500 Subject: [PATCH 197/395] Fossa scanning workflow (4.x) (#1578) --- .github/workflows/dep-lic-scan.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/dep-lic-scan.yaml diff --git a/.github/workflows/dep-lic-scan.yaml b/.github/workflows/dep-lic-scan.yaml new file mode 100644 index 00000000000..afb197bf137 --- /dev/null +++ b/.github/workflows/dep-lic-scan.yaml @@ -0,0 +1,23 @@ +name: Dependency and License Scan +on: + push: + branches: + - '4.x' + - '3.x' + paths-ignore: + - 'manual/**' + - 'faq/**' + - 'upgrade_guide/**' + - 'changelog/**' +jobs: + scan-repo: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Install Fossa CLI + run: | + curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash -s -- -b . + - name: Scan for dependencies and licenses + run: | + FOSSA_API_KEY=${{ secrets.FOSSA_PUSH_ONLY_API_KEY }} ./fossa analyze From cbb8194c2101cac4521e52fb007af8bfc0601c39 Mon Sep 17 00:00:00 2001 From: Tore Trettenes Date: Fri, 7 Jan 2022 22:25:02 +0100 Subject: [PATCH 198/395] Switch Esri Geometry API to an optional dependency (#1575) Co-authored-by: Tore Trettenes --- core-shaded/pom.xml | 5 +++++ core/pom.xml | 1 + osgi-tests/pom.xml | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index b84dd855234..bf49e92d36d 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -88,6 +88,11 @@ org.hdrhistogram HdrHistogram + + com.esri.geometry + esri-geometry-api + true + org.apache.tinkerpop gremlin-core diff --git a/core/pom.xml b/core/pom.xml index 13dfaca11fa..dce03062123 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -90,6 +90,7 @@ com.esri.geometry esri-geometry-api + true org.apache.tinkerpop diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 7cf7adf20bc..281c9ff67b3 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -78,6 +78,10 @@ org.reactivestreams reactive-streams + + com.esri.geometry + esri-geometry-api + org.apache.tinkerpop gremlin-core From 415f789f4e1db7c003ee110153965fc91b70fdf5 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 25 Jan 2022 16:23:51 -0600 Subject: [PATCH 199/395] JAVA-2982: Follow-up to recent PR making ESRI an optional dependency (#1580) --- core-shaded/pom.xml | 42 ++++++------------------------- integration-tests/pom.xml | 5 ++++ manual/core/integration/README.md | 21 ++++++++++++++-- upgrade_guide/README.md | 20 +++++++++++++++ 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index bf49e92d36d..a88b6987392 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -146,9 +146,6 @@ --> com.datastax.oss:java-driver-core io.netty:* - com.esri.geometry:* - org.json:* - org.codehaus.jackson:* com.fasterxml.jackson.core:* @@ -161,18 +158,6 @@ io.netty com.datastax.oss.driver.shaded.netty - - com.esri - com.datastax.oss.driver.shaded.esri - - - org.json - com.datastax.oss.driver.shaded.json - - - org.codehaus.jackson - com.datastax.oss.driver.shaded.codehaus.jackson - com.fasterxml.jackson com.datastax.oss.driver.shaded.fasterxml.jackson @@ -194,24 +179,6 @@ META-INF/** - - com.esri.geometry:* - - META-INF/** - - - - org.json:* - - META-INF/** - - - - org.codehaus.jackson:* - - META-INF/** - - com.fasterxml.jackson.core:* @@ -311,6 +278,11 @@ jctools-core 2.1.2 + + com.esri.geometry + esri-geometry-api + 1.2.1 + @@ -340,7 +312,7 @@ !com.datastax.oss.driver.shaded.netty.*, !com.datastax.oss.driver.shaded.esri.*, !com.datastax.oss.driver.shaded.json.*, !com.datastax.oss.driver.shaded.codehaus.jackson.*, !com.datastax.oss.driver.shaded.fasterxml.jackson.*, + -->!com.datastax.oss.driver.shaded.netty.*, !com.datastax.oss.driver.shaded.fasterxml.jackson.*, - com.datastax.oss.driver.api.core.*, com.datastax.oss.driver.internal.core.*, com.datastax.dse.driver.api.core.*, com.datastax.dse.driver.internal.core.*, com.datastax.oss.driver.shaded.netty.*, com.datastax.oss.driver.shaded.esri.*, com.datastax.oss.driver.shaded.json.*, com.datastax.oss.driver.shaded.codehaus.jackson.*, com.datastax.oss.driver.shaded.fasterxml.jackson.*, + com.datastax.oss.driver.api.core.*, com.datastax.oss.driver.internal.core.*, com.datastax.dse.driver.api.core.*, com.datastax.dse.driver.internal.core.*, com.datastax.oss.driver.shaded.netty.*, com.datastax.oss.driver.shaded.fasterxml.jackson.*, true diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 20fd13ea85d..96e682bd087 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -211,6 +211,11 @@ blockhound-junit-platform test + + com.esri.geometry + esri-geometry-api + test + diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 23380063cdf..7202dac2d94 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -479,8 +479,9 @@ don't use any of the above features, you can safely exclude the dependency: Our [geospatial types](../dse/geotypes/) implementation is based on the [Esri Geometry API](https://github.com/Esri/geometry-api-java). -Esri is declared as a required dependency, but the driver can operate normally without it. If you -don't use geospatial types anywhere in your application, you can exclude the dependency: +For driver versions >= 4.4.0 and < 4.14.0 Esri is declared as a required dependency, +although the driver can operate normally without it. If you don't use geospatial types +anywhere in your application you can exclude the dependency: ```xml @@ -496,6 +497,22 @@ don't use geospatial types anywhere in your application, you can exclude the dep ``` +Starting with driver 4.14.0 Esri has been changed to an optional dependency. You no longer have to +explicitly exclude the dependency if it's not used, but if you do wish to make use of the Esri +library you must now explicitly specify it as a dependency : + +```xml + + com.esri.geometry + esri-geometry-api + ${esri.version} + +``` + +In the dependency specification above you should use any 1.2.x version of Esri (we recommend +1.2.1). These versions are older than the current 2.x versions of the library but they are +guaranteed to be fully compatible with DSE. + #### TinkerPop [Apache TinkerPop™](http://tinkerpop.apache.org/) is used in our [graph API](../dse/graph/), diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index e48a75ceb4e..297c4ca7fda 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -9,6 +9,26 @@ request cannot be executed because all nodes tried were busy. Previously you wou `NoNodeAvailableException` but you will now get back an `AllNodesFailedException` where the `getAllErrors` map contains a `NodeUnavailableException` for that node. +#### Esri Geometry dependency now optional + +Previous versions of the Java driver defined a mandatory dependency on the Esri geometry library. +This library offered support for primitive geometric types supported by DSE. As of driver 4.14.0 +this dependency is now optional. + +If you do not use DSE (or if you do but do not use the support for geometric types within DSE) you +should experience no disruption. If you are using geometric types with DSE you'll now need to +explicitly declare a dependency on the Esri library: + +```xml + + com.esri.geometry + esri-geometry-api + ${esri.version} + +``` + +See the [integration](../manual/core/integration/#esri) section in the manual for more details. + ### 4.13.0 #### Enhanced support for GraalVM native images From 85efee414916aea235ae8578fb3343d7733b747f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0tefan=20Miklo=C5=A1ovi=C4=8D?= Date: Fri, 11 Feb 2022 17:07:46 +0100 Subject: [PATCH 200/395] JAVA-2992 include options into DefaultTableMetadata equals and hash methods (#1588) --- .../internal/core/metadata/schema/DefaultTableMetadata.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/DefaultTableMetadata.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/DefaultTableMetadata.java index e877e322993..34cb8ac9966 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/DefaultTableMetadata.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/DefaultTableMetadata.java @@ -142,7 +142,8 @@ public boolean equals(Object other) { && Objects.equals(this.partitionKey, that.getPartitionKey()) && Objects.equals(this.clusteringColumns, that.getClusteringColumns()) && Objects.equals(this.columns, that.getColumns()) - && Objects.equals(this.indexes, that.getIndexes()); + && Objects.equals(this.indexes, that.getIndexes()) + && Objects.equals(this.options, that.getOptions()); } else { return false; } @@ -159,7 +160,8 @@ public int hashCode() { partitionKey, clusteringColumns, columns, - indexes); + indexes, + options); } @Override From 73f9141c44bb69f4c38f6a70649dbb3a4d6b2797 Mon Sep 17 00:00:00 2001 From: Schnikonos Date: Mon, 14 Feb 2022 07:01:40 +0100 Subject: [PATCH 201/395] JAVA-2987 BasicLoadBalancingPolicy remote compute nodes check all liveNodes (#1576) * BasicLoadBalancingPolicy remote compute nodes -> don't presume local dc nodes to be up and among the liveNodes that where found (can happen if the local dc wasn't up when the application started) * BasicLoadBalancingPolicy: follow suggestion from @absurdfarce for remote computeNodes to make the code cleaner and more efficient * BasicLoadBalancingPolicy: fix formatting --- .../BasicLoadBalancingPolicy.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java index 395412272ce..ba1c3e39f30 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java @@ -42,6 +42,7 @@ import com.datastax.oss.driver.internal.core.util.collection.LazyQueryPlan; import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; +import com.datastax.oss.driver.shaded.guava.common.base.Predicates; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; @@ -322,30 +323,19 @@ protected Queue maybeAddDcFailover(@Nullable Request request, @NonNull Que @Override protected Object[] computeNodes() { - Object[] dcs = liveNodes.dcs().toArray(); - if (dcs.length <= 1) { - return EMPTY_NODES; - } - Object[] remoteNodes = new Object[(dcs.length - 1) * maxNodesPerRemoteDc]; - int remoteNodesLength = 0; - for (Object dc : dcs) { - if (!dc.equals(localDc)) { - Object[] remoteNodesInDc = liveNodes.dc((String) dc).toArray(); - for (int i = 0; i < maxNodesPerRemoteDc && i < remoteNodesInDc.length; i++) { - remoteNodes[remoteNodesLength++] = remoteNodesInDc[i]; - } - } - } + Set dcs = liveNodes.dcs(); + Object[] remoteNodes = + dcs.stream() + .filter(Predicates.not(Predicates.equalTo(localDc))) + .flatMap(dc -> liveNodes.dc(dc).stream().limit(maxNodesPerRemoteDc)) + .toArray(); + + int remoteNodesLength = remoteNodes.length; if (remoteNodesLength == 0) { return EMPTY_NODES; } shuffleHead(remoteNodes, remoteNodesLength); - if (remoteNodes.length == remoteNodesLength) { - return remoteNodes; - } - Object[] trimmedRemoteNodes = new Object[remoteNodesLength]; - System.arraycopy(remoteNodes, 0, trimmedRemoteNodes, 0, remoteNodesLength); - return trimmedRemoteNodes; + return remoteNodes; } }; From 71e57575d2f569101d5fae6062e195165a1e65a6 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 14 Feb 2022 14:53:09 -0600 Subject: [PATCH 202/395] Minor optimization to previous commit --- .../internal/core/loadbalancing/BasicLoadBalancingPolicy.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java index ba1c3e39f30..9e8184879ea 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java @@ -323,9 +323,8 @@ protected Queue maybeAddDcFailover(@Nullable Request request, @NonNull Que @Override protected Object[] computeNodes() { - Set dcs = liveNodes.dcs(); Object[] remoteNodes = - dcs.stream() + liveNodes.dcs().stream() .filter(Predicates.not(Predicates.equalTo(localDc))) .flatMap(dc -> liveNodes.dc(dc).stream().limit(maxNodesPerRemoteDc)) .toArray(); From c1e3a634077999f42a8dd78ec63b952e70fb144b Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 16 Feb 2022 10:34:05 -0600 Subject: [PATCH 203/395] JAVA-2976: Protocol v5 error codes CAS_WRITE_UNKNOWN, CDC_WRITE_FAILURE not supported (4.x) (#1586) --- bom/pom.xml | 2 +- .../CASWriteUnknownException.java | 84 +++++++++++++++++++ .../CDCWriteFailureException.java | 58 +++++++++++++ .../driver/internal/core/cql/Conversions.java | 12 +++ .../internal/core/util/ProtocolUtils.java | 4 + 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CASWriteUnknownException.java create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CDCWriteFailureException.java diff --git a/bom/pom.xml b/bom/pom.xml index a228074bf7a..7eb3b983ec4 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -71,7 +71,7 @@ com.datastax.oss native-protocol - 1.5.0 + 1.5.1 com.datastax.oss diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CASWriteUnknownException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CASWriteUnknownException.java new file mode 100644 index 00000000000..856f8951e7e --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CASWriteUnknownException.java @@ -0,0 +1,84 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.servererrors; + +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.DriverException; +import com.datastax.oss.driver.api.core.cql.ExecutionInfo; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.session.Request; +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * The result of a CAS operation is in an unknown state. + * + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, + * CoordinatorException, int)} , which will decide if it is rethrown directly to the client or if + * the request should be retried. If all other tried nodes also fail, this exception will appear in + * the {@link AllNodesFailedException} thrown to the client. + */ +public class CASWriteUnknownException extends QueryConsistencyException { + + public CASWriteUnknownException( + @NonNull Node coordinator, + @NonNull ConsistencyLevel consistencyLevel, + int received, + int blockFor) { + this( + coordinator, + String.format( + "CAS operation result is unknown - proposal was not accepted by a quorum. (%d / %d)", + received, blockFor), + consistencyLevel, + received, + blockFor, + null, + false); + } + + private CASWriteUnknownException( + @NonNull Node coordinator, + @NonNull String message, + @NonNull ConsistencyLevel consistencyLevel, + int received, + int blockFor, + ExecutionInfo executionInfo, + boolean writableStackTrace) { + super( + coordinator, + message, + consistencyLevel, + received, + blockFor, + executionInfo, + writableStackTrace); + } + + @NonNull + @Override + public DriverException copy() { + return new CASWriteUnknownException( + getCoordinator(), + getMessage(), + getConsistencyLevel(), + getReceived(), + getBlockFor(), + getExecutionInfo(), + true); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CDCWriteFailureException.java b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CDCWriteFailureException.java new file mode 100644 index 00000000000..f6f6552e9b4 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/servererrors/CDCWriteFailureException.java @@ -0,0 +1,58 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.servererrors; + +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.DriverException; +import com.datastax.oss.driver.api.core.cql.ExecutionInfo; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.retry.RetryPolicy; +import com.datastax.oss.driver.api.core.session.Request; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +/** + * An attempt was made to write to a commitlog segment which doesn't support CDC mutations. + * + *

    This exception is processed by {@link RetryPolicy#onErrorResponseVerdict(Request, + * CoordinatorException, int)}, which will decide if it is rethrown directly to the client or if the + * request should be retried. If all other tried nodes also fail, this exception will appear in the + * {@link AllNodesFailedException} thrown to the client. + */ +public class CDCWriteFailureException extends QueryExecutionException { + + public CDCWriteFailureException(@NonNull Node coordinator) { + super(coordinator, "Commitlog does not support CDC mutations", null, false); + } + + public CDCWriteFailureException(@NonNull Node coordinator, @NonNull String message) { + super(coordinator, "Commitlog does not support CDC mutations", null, false); + } + + private CDCWriteFailureException( + @NonNull Node coordinator, + @NonNull String message, + @Nullable ExecutionInfo executionInfo, + boolean writableStackTrace) { + super(coordinator, message, executionInfo, writableStackTrace); + } + + @NonNull + @Override + public DriverException copy() { + return new CDCWriteFailureException(getCoordinator(), getMessage(), getExecutionInfo(), true); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java index 1031ca01bd2..6a01f364000 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java @@ -40,6 +40,8 @@ import com.datastax.oss.driver.api.core.retry.RetryPolicy; import com.datastax.oss.driver.api.core.servererrors.AlreadyExistsException; import com.datastax.oss.driver.api.core.servererrors.BootstrappingException; +import com.datastax.oss.driver.api.core.servererrors.CASWriteUnknownException; +import com.datastax.oss.driver.api.core.servererrors.CDCWriteFailureException; import com.datastax.oss.driver.api.core.servererrors.CoordinatorException; import com.datastax.oss.driver.api.core.servererrors.FunctionFailureException; import com.datastax.oss.driver.api.core.servererrors.InvalidConfigurationInQueryException; @@ -75,6 +77,7 @@ import com.datastax.oss.protocol.internal.response.Error; import com.datastax.oss.protocol.internal.response.Result; import com.datastax.oss.protocol.internal.response.error.AlreadyExists; +import com.datastax.oss.protocol.internal.response.error.CASWriteUnknown; import com.datastax.oss.protocol.internal.response.error.ReadFailure; import com.datastax.oss.protocol.internal.response.error.ReadTimeout; import com.datastax.oss.protocol.internal.response.error.Unavailable; @@ -505,6 +508,15 @@ public static CoordinatorException toThrowable( context.getWriteTypeRegistry().fromName(writeFailure.writeType), writeFailure.numFailures, writeFailure.reasonMap); + case ProtocolConstants.ErrorCode.CDC_WRITE_FAILURE: + return new CDCWriteFailureException(node, errorMessage.message); + case ProtocolConstants.ErrorCode.CAS_WRITE_UNKNOWN: + CASWriteUnknown casFailure = (CASWriteUnknown) errorMessage; + return new CASWriteUnknownException( + node, + context.getConsistencyLevelRegistry().codeToLevel(casFailure.consistencyLevel), + casFailure.received, + casFailure.blockFor); case ProtocolConstants.ErrorCode.SYNTAX_ERROR: return new SyntaxError(node, errorMessage.message); case ProtocolConstants.ErrorCode.UNAUTHORIZED: diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/ProtocolUtils.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/ProtocolUtils.java index 06b47479eee..386fd3be525 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/ProtocolUtils.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/ProtocolUtils.java @@ -95,6 +95,10 @@ public static String errorCodeString(int errorCode) { return "FUNCTION_FAILURE"; case ProtocolConstants.ErrorCode.WRITE_FAILURE: return "WRITE_FAILURE"; + case ProtocolConstants.ErrorCode.CDC_WRITE_FAILURE: + return "CDC_WRITE_FAILURE"; + case ProtocolConstants.ErrorCode.CAS_WRITE_UNKNOWN: + return "CAS_WRITE_UNKNOWN"; case ProtocolConstants.ErrorCode.SYNTAX_ERROR: return "SYNTAX_ERROR"; case ProtocolConstants.ErrorCode.UNAUTHORIZED: From 42cb6583f3b87b92ab07b02ba05c07c029d07994 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 16 Feb 2022 11:56:06 -0600 Subject: [PATCH 204/395] Changelog updates --- changelog/README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/changelog/README.md b/changelog/README.md index 9b3c2f4a609..fd6dccdb3a0 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,8 +2,12 @@ -### 4.14.0 (in progress) +### 4.14.0 +- [bug] JAVA-2976: Support missing protocol v5 error codes CAS_WRITE_UNKNOWN, CDC_WRITE_FAILURE +- [bug] JAVA-2987: BasicLoadBalancingPolicy remote computation assumes local DC is up and live +- [bug] JAVA-2992: Include options into DefaultTableMetadata equals and hash methods +- [improvement] JAVA-2982: Switch Esri geometry lib to an optional dependency - [improvement] JAVA-2959: Don't throw NoNodeAvailableException when all connections busy ### 4.13.0 @@ -597,6 +601,17 @@ changelog](https://docs.datastax.com/en/developer/java-driver-dse/latest/changel - [bug] JAVA-1499: Wait for load balancing policy at cluster initialization - [new feature] JAVA-1495: Add prepared statements +## 3.11.1 +- [bug] JAVA-2967: Support native transport peer information for DSE 6.8. +- [bug] JAVA-2976: Support missing protocol v5 error codes CAS_WRITE_UNKNOWN, CDC_WRITE_FAILURE. + +## 3.11.0 + +- [improvement] JAVA-2705: Remove protocol v5 beta status, add v6-beta. +- [bug] JAVA-2923: Detect and use Guava's new HostAndPort.getHost method. +- [bug] JAVA-2922: Switch to modern framing format inside a channel handler. +- [bug] JAVA-2924: Consider protocol version unsupported when server requires USE_BETA flag for it. + ### 3.10.2 - [bug] JAVA-2860: Avoid NPE if channel initialization crashes. From ce2cd11ab692375f5c28b2c6548c98c3339e336e Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 17 Feb 2022 10:35:03 -0600 Subject: [PATCH 205/395] Update manual for 4.14.0 release --- README.md | 4 +- manual/case_sensitivity/README.md | 10 +-- manual/core/README.md | 26 +++---- manual/core/address_resolution/README.md | 2 +- manual/core/async/README.md | 2 +- manual/core/authentication/README.md | 18 ++--- manual/core/bom/README.md | 6 +- manual/core/configuration/README.md | 20 ++--- manual/core/control_connection/README.md | 2 +- manual/core/custom_codecs/README.md | 74 +++++++++---------- manual/core/detachable_types/README.md | 14 ++-- manual/core/dse/geotypes/README.md | 6 +- manual/core/dse/graph/README.md | 4 +- manual/core/dse/graph/fluent/README.md | 4 +- .../core/dse/graph/fluent/explicit/README.md | 12 +-- manual/core/dse/graph/results/README.md | 6 +- manual/core/dse/graph/script/README.md | 6 +- manual/core/idempotence/README.md | 4 +- manual/core/integration/README.md | 7 +- manual/core/load_balancing/README.md | 12 +-- manual/core/metadata/README.md | 6 +- manual/core/metadata/node/README.md | 28 +++---- manual/core/metadata/schema/README.md | 20 ++--- manual/core/metadata/token/README.md | 4 +- manual/core/native_protocol/README.md | 6 +- manual/core/non_blocking/README.md | 44 +++++------ manual/core/paging/README.md | 12 +-- manual/core/performance/README.md | 10 +-- manual/core/pooling/README.md | 2 +- manual/core/query_timestamps/README.md | 4 +- manual/core/reactive/README.md | 24 +++--- manual/core/reconnection/README.md | 8 +- manual/core/request_tracker/README.md | 4 +- manual/core/retries/README.md | 36 ++++----- manual/core/speculative_execution/README.md | 2 +- manual/core/ssl/README.md | 6 +- manual/core/statements/README.md | 8 +- manual/core/statements/batch/README.md | 6 +- .../statements/per_query_keyspace/README.md | 2 +- manual/core/statements/prepared/README.md | 8 +- manual/core/statements/simple/README.md | 6 +- manual/core/temporal_types/README.md | 8 +- manual/core/throttling/README.md | 6 +- manual/core/tracing/README.md | 12 +-- manual/core/tuples/README.md | 4 +- manual/core/udts/README.md | 4 +- manual/developer/common/concurrency/README.md | 4 +- manual/mapper/config/kotlin/README.md | 2 +- manual/mapper/config/record/README.md | 2 +- manual/mapper/config/scala/README.md | 2 +- manual/mapper/daos/README.md | 8 +- manual/mapper/daos/custom_types/README.md | 10 +-- manual/mapper/daos/delete/README.md | 18 ++--- manual/mapper/daos/getentity/README.md | 18 ++--- manual/mapper/daos/increment/README.md | 12 +-- manual/mapper/daos/insert/README.md | 14 ++-- manual/mapper/daos/null_saving/README.md | 10 +-- manual/mapper/daos/query/README.md | 24 +++--- manual/mapper/daos/queryprovider/README.md | 16 ++-- manual/mapper/daos/select/README.md | 28 +++---- manual/mapper/daos/setentity/README.md | 10 +-- .../daos/statement_attributes/README.md | 2 +- manual/mapper/daos/update/README.md | 12 +-- manual/mapper/entities/README.md | 36 ++++----- manual/mapper/mapper/README.md | 10 +-- manual/osgi/README.md | 6 +- manual/query_builder/README.md | 10 +-- manual/query_builder/condition/README.md | 2 +- manual/query_builder/delete/README.md | 4 +- manual/query_builder/insert/README.md | 2 +- manual/query_builder/relation/README.md | 4 +- manual/query_builder/schema/README.md | 2 +- .../query_builder/schema/aggregate/README.md | 2 +- .../query_builder/schema/function/README.md | 2 +- manual/query_builder/schema/index/README.md | 2 +- .../query_builder/schema/keyspace/README.md | 2 +- .../schema/materialized_view/README.md | 4 +- manual/query_builder/schema/table/README.md | 6 +- manual/query_builder/schema/type/README.md | 2 +- manual/query_builder/select/README.md | 4 +- manual/query_builder/term/README.md | 4 +- manual/query_builder/truncate/README.md | 2 +- manual/query_builder/update/README.md | 4 +- 83 files changed, 411 insertions(+), 410 deletions(-) diff --git a/README.md b/README.md index b61f2464900..daffaff95c8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.13.0](https://github.com/datastax/java-driver/tree/4.13.0).* +[4.14.0](https://github.com/datastax/java-driver/tree/4.14.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol @@ -82,7 +82,7 @@ See the [upgrade guide](upgrade_guide/) for details. * [Changelog] * [FAQ] -[API docs]: https://docs.datastax.com/en/drivers/java/4.13 +[API docs]: https://docs.datastax.com/en/drivers/java/4.14 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [@dsJavaDriver]: https://twitter.com/dsJavaDriver diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index 947502cd5b0..865354f41df 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -106,11 +106,11 @@ For "consuming" methods, string overloads are also provided for convenience, for * in other cases, the string is always assumed to be in CQL form, and converted on the fly with `CqlIdentifier.fromCql`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html -[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html +[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html ### Good practices diff --git a/manual/core/README.md b/manual/core/README.md index f6418b2739f..8cc6b670b99 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -314,18 +314,18 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { } ``` -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html -[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html#builder-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/TupleValue.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html -[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- -[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html#builder-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/TupleValue.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html +[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- +[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index 11194b92e6b..fe8c967a62a 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -124,7 +124,7 @@ Cassandra node: domain name of the target instance. Then it performs a forward DNS lookup of the domain name; the EC2 DNS does the private/public switch automatically based on location). -[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html +[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html [cassandra.yaml]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html [rpc_address]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html?scroll=configCassandra_yaml__rpc_address diff --git a/manual/core/async/README.md b/manual/core/async/README.md index e2bac78d755..1daecfd61ee 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -207,4 +207,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 7843ae2d1f8..45742c3aac2 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -227,13 +227,13 @@ session.execute(statement); [SASL]: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer -[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/AuthProvider.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html -[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html -[ProgrammaticPlainTextAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.html -[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html -[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html -[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- -[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- -[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- +[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/auth/AuthProvider.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html +[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[ProgrammaticPlainTextAuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.html +[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html +[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html +[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- +[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- +[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- [reference.conf]: ../configuration/reference/ \ No newline at end of file diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index c31df62a3d6..f1741a43372 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.13.0 + 4.14.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.13.0 + 4.14.0 @@ -104,4 +104,4 @@ good idea to extract a property to keep it in sync with the BOM: ``` -[MCOMPILER-391]: https://issues.apache.org/jira/browse/MCOMPILER-391 \ No newline at end of file +[MCOMPILER-391]: https://issues.apache.org/jira/browse/MCOMPILER-391 diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index ef1c6e801b2..7dc9fd73afc 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -520,16 +520,16 @@ config.getDefaultProfile().getString(MyCustomOption.ADMIN_EMAIL); config.getDefaultProfile().getInt(MyCustomOption.AWESOMENESS_FACTOR); ``` -[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfig.html -[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html -[DriverOption]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverOption.html -[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html -[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- -[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- -[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- -[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- +[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfig.html +[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html +[DriverOption]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverOption.html +[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html +[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- +[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- +[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- +[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- [Typesafe Config]: https://github.com/typesafehub/config [config standard behavior]: https://github.com/typesafehub/config#standard-behavior diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index 3b33639059e..d8a9cddc718 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -23,4 +23,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index ca3c20d7538..92a0274577b 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -660,13 +660,13 @@ private static String formatRow(Row row) { } ``` -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html -[format()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- -[parse()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- -[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html -[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html +[format()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- +[parse()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- +[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html +[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- [Enums]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html [Enum.name()]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#name-- @@ -680,36 +680,36 @@ private static String formatRow(Row row) { [java.time.LocalDateTime]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html [java.time.ZoneId]: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html -[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html -[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY -[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY -[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY -[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY -[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY -[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY -[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY -[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY -[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC -[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- -[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM -[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC -[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC -[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC -[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED -[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- -[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- -[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- -[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- - -[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB -[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP +[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html +[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY +[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY +[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY +[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY +[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY +[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY +[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY +[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY +[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC +[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- +[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM +[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC +[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC +[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC +[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED +[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- +[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- +[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- +[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- + +[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB +[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index 4a0cc9044dc..a0f38d11f74 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -137,13 +137,13 @@ Even then, the defaults used by detached objects might be good enough for you: Otherwise, just make sure you reattach objects any time you deserialize them or create them from scratch. -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT -[DataType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/DataType.html -[Detachable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/detach/Detachable.html -[Session]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html -[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html -[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT +[DataType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/DataType.html +[Detachable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/detach/Detachable.html +[Session]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html +[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html +[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html [Java serialization]: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html [protocol specifications]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index 7116ff79886..79470ec946b 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -166,9 +166,9 @@ All geospatial types interoperate with three standard formats: [ESRI]: https://github.com/Esri/geometry-api-java -[LineString]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/data/geometry/LineString.html -[Point]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/data/geometry/Point.html -[Polygon]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/data/geometry/Polygon.html +[LineString]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/data/geometry/LineString.html +[Point]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/data/geometry/Point.html +[Polygon]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/data/geometry/Polygon.html [Well-known text]: https://en.wikipedia.org/wiki/Well-known_text [Well-known binary]: https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index 19d5312b6df..bc9669634ee 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -74,8 +74,8 @@ fluent API returns Apache TinkerPop™ types directly. [Apache TinkerPop™]: http://tinkerpop.apache.org/ -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html -[GraphSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/GraphSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html +[GraphSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/GraphSession.html [DSE developer guide]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphTOC.html [Gremlin]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dseGraphAbout.html#dseGraphAbout__what-is-cql diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index 443841b09ba..b7027490b33 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -109,8 +109,8 @@ All the DSE predicates are available on the driver side: .values("name"); ``` -[Search]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/predicates/Search.html -[Geo]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/predicates/Geo.html +[Search]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/predicates/Search.html +[Geo]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/predicates/Geo.html [Apache TinkerPop™]: http://tinkerpop.apache.org/ [TinkerPop DSL]: http://tinkerpop.apache.org/docs/current/reference/#dsl diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index 3157f46d01a..b7741a0de2b 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -105,9 +105,9 @@ added in a future version. See also the [parent page](../) for topics common to all fluent traversals. -[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html -[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html -[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- -[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- +[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html +[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html +[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- +[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index 6be3bed590b..fa98525c756 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -137,8 +137,8 @@ If a type doesn't have a corresponding `asXxx()` method, use the variant that ta UUID uuid = graphNode.as(UUID.class); ``` -[GraphNode]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/GraphNode.html -[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/GraphResultSet.html -[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html +[GraphNode]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/GraphNode.html +[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/GraphResultSet.html +[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html [DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index 58173506349..b191cc7db7c 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -101,6 +101,6 @@ Note however that some types of queries can only be performed through the script * configuration; * DSE graph schema queries. -[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html -[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html +[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index 0c24efda673..8eb9135488a 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -60,5 +60,5 @@ assert bs.isIdempotent(); The query builder tries to infer idempotence automatically; refer to [its manual](../../query_builder/idempotence/) for more details. -[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- -[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- +[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- +[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 7202dac2d94..75695763158 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -562,6 +562,7 @@ Here are the recommended TinkerPop versions for each driver version:

    Driver versionTinkerPop version
    4.13.03.4.10
    4.12.03.4.10
    4.11.03.4.10
    4.10.03.4.9
    + @@ -662,6 +663,6 @@ The remaining core driver dependencies are the only ones that are truly mandator [guava]: https://github.com/google/guava/issues/2721 [annotation processing]: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#sthref65 -[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- -[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[Uuids]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/uuid/Uuids.html +[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- +[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[Uuids]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/uuid/Uuids.html diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index 2997d427106..abc950fe378 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -426,12 +426,12 @@ Then it uses the "closest" distance for any given node. For example: * policy1 changes its suggestion to IGNORED. node1 is set to REMOTE; * policy1 changes its suggestion to REMOTE. node1 stays at REMOTE. -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html -[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html +[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html [BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java -[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- -[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- -[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- -[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html +[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- +[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- +[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index f160575729a..34358bfdf5e 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -56,6 +56,6 @@ new keyspace in the schema metadata before the token metadata was updated. Schema and node state events are debounced. This allows you to control how often the metadata gets refreshed. See the [Performance](../performance/#debouncing) page for more details. -[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- -[Metadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- +[Metadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html +[Node]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 4548f95aeee..1555c2ad1a5 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -129,17 +129,17 @@ beyond the scope of this document; if you're interested, study the `TopologyMoni the source code. -[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- -[Node]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html -[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- -[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- -[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- -[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- -[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- -[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- -[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- -[NodeState]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/NodeState.html -[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html -[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file +[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- +[Node]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html +[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- +[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- +[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- +[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- +[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- +[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- +[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- +[NodeState]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeState.html +[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html +[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html +[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index 52711d11bd1..c42e56e5735 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -321,16 +321,16 @@ unavailable for the excluded keyspaces. If you issue schema-altering requests from the driver (e.g. `session.execute("CREATE TABLE ..")`), take a look at the [Performance](../../performance/#schema-updates) page for a few tips. -[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html -[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html -[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- -[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- -[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- -[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html -[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html -[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html +[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html +[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html +[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- +[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- +[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- +[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html +[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html +[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html [JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 [java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index ea9f4a99832..475274fd4e4 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -169,5 +169,5 @@ on [schema metadata](../schema/). If schema metadata is disabled or filtered, to also be unavailable for the excluded keyspaces. -[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 08d551765dc..d64aaccda85 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -135,6 +135,6 @@ If you want to see the details of mixed cluster negotiation, enable `DEBUG` leve [protocol spec]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources [driver3]: https://docs.datastax.com/en/developer/java-driver/3.10/manual/native_protocol/ -[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- -[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- -[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- +[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- +[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- +[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 8876022f2f0..0960379936b 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -49,22 +49,22 @@ For example, calling any synchronous method declared in [`SyncCqlSession`], such will block until the result is available. These methods should never be used in non-blocking applications. -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` -[`execute`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all safe for use in non-blocking applications; the statement execution and asynchronous result delivery is guaranteed to never block. -[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html -[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the returned publisher will never block when subscribed to, until the final results are delivered to the subscriber. -[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- There is one exception though: continuous paging queries (a feature specific to DSE) have a special execution model which uses internal locks for coordination. Although such locks are only held for @@ -77,10 +77,10 @@ reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactiv though, continuous paging is extremely efficient and can safely be used in most non-blocking contexts, unless they require strict lock-freedom. -[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html -[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html -[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- -[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- #### Driver lock-free guarantees per session lifecycle phases @@ -110,8 +110,8 @@ Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` should be avoided in non-blocking applications. -[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- -[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- Once the session is initialized, however, the driver is guaranteed to be non-blocking during the session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. @@ -121,8 +121,8 @@ during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseab asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is shut down and lock-freedom enforcement is disabled. -[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html -[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- #### Driver lock-free guarantees for specific components @@ -131,7 +131,7 @@ Certain driver components are not implemented in lock-free algorithms. For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It should not be used if strict lock-freedom is enforced. -[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html The same is valid for both built-in [request throttlers]: @@ -143,7 +143,7 @@ use locks internally, and depending on how many requests are being executed in p contention on these locks can be high: in short, if your application enforces strict lock-freedom, then these components should not be used. -[request throttlers]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html +[request throttlers]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html Other components may be lock-free, *except* for their first invocation. This is the case of the following items: @@ -151,8 +151,8 @@ following items: * All built-in implementations of [`TimestampGenerator`], upon instantiation; * The utility method [`Uuids.timeBased()`]. -[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/time/TimestampGenerator.html -[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- Both components need to access native libraries when they get initialized and this may involve hitting the local filesystem, thus causing the initialization to become a blocking call. @@ -172,7 +172,7 @@ One component, the codec registry, can block when its [`register`] method is cal therefore advised that codecs should be registered during application startup exclusively. See the [custom codecs](../custom_codecs) section for more details about registering codecs. -[`register`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[`register`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- Finally, a few internal components also use locks, but only during session initialization; once the session is ready, they are either discarded, or don't use locks anymore for the rest of the @@ -213,7 +213,7 @@ lock-freedom enforcement tools could report calls to that method, but it was imp these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a non-blocking call and random UUIDs can now be safely generated in non-blocking applications. -[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- [JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 #### Driver lock-free guarantees when reloading the configuration @@ -228,8 +228,8 @@ detectors. If that is the case, it is advised to disable hot-reloading by settin `datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on [configuration](../configuration) for more information. -[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- #### Driver lock-free guarantees when connecting to DSE diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index 9f753a77181..d08d92e8f36 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -253,12 +253,12 @@ protocol page size and the logical page size to the same value. The [driver examples] include two complete web service implementations demonstrating forward-only and offset paging. -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- -[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- -[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/paging/OffsetPager.html -[PagingState]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/PagingState.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- +[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- +[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/paging/OffsetPager.html +[PagingState]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/PagingState.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index a26067dbed5..90b379c59d6 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -345,8 +345,8 @@ possible to reuse the same event loop group for I/O, admin tasks, and even your (the driver's internal code is fully asynchronous so it will never block any thread). The timer is the only one that will have to stay on a separate thread. -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html -[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- -[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html +[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index 84dee0ec80e..d0d2de7d128 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -170,5 +170,5 @@ you experience the issue, here's what to look out for: Try adding more connections per node. Thanks to the driver's hot-reload mechanism, you can do that at runtime and see the effects immediately. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html [CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index bde4b0722e9..bc01ce41d4d 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -187,9 +187,9 @@ Here is the order of precedence of all the methods described so far: 3. otherwise, if the timestamp generator assigned a timestamp, use it; 4. otherwise, let the server assign the timestamp. -[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/time/TimestampGenerator.html [gettimeofday]: http://man7.org/linux/man-pages/man2/settimeofday.2.html [JNR]: https://github.com/jnr/jnr-posix [Lightweight transactions]: https://docs.datastax.com/en/dse/6.0/cql/cql/cql_using/useInsertLWT.html -[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- +[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index bd32969f3c0..6073ac4bf98 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -367,18 +367,18 @@ Note that the driver already has a [built-in retry mechanism] that can transpare queries; the above example should be seen as a demonstration of application-level retries, when a more fine-grained control of what should be retried, and how, is required. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html -[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html -[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html -[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- -[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- -[wasApplied]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- -[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- -[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- -[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html +[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html +[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html +[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- +[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- +[wasApplied]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- +[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- +[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- +[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- [built-in retry mechanism]: ../retries/ [request throttling]: ../throttling/ diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index b5b6b3e10b4..c383b887fcc 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -84,7 +84,7 @@ Note that the session is not accessible until it is fully ready: the `CqlSession call — or the future returned by `buildAsync()` — will not complete until the connection was established. -[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/context/DriverContext.html -[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html +[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index af66851c748..4186139c0ba 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -123,5 +123,5 @@ all FROM users WHERE user_id=? [v0=42] com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined column name all ``` -[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/tracker/RequestTracker.html +[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index ec07dc2cea2..6e150eb77e4 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -231,21 +231,21 @@ configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html -[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/DriverTimeoutException.html -[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html -[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/HeartbeatException.html -[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html -[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html -[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html -[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html -[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html -[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/retry/RetryDecision.html -[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/retry/RetryPolicy.html -[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/retry/RetryVerdict.html -[ServerError]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/ServerError.html -[TruncateException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/TruncateException.html -[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html -[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html -[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html +[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/DriverTimeoutException.html +[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html +[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/HeartbeatException.html +[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html +[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html +[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html +[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html +[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html +[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/retry/RetryDecision.html +[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/retry/RetryPolicy.html +[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[ServerError]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ServerError.html +[TruncateException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/TruncateException.html +[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html +[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html +[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index fe044e93df7..cf6675e9dbf 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -250,4 +250,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index 91bf0fc1878..2e293d7e346 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -204,6 +204,6 @@ the box, but with a bit of custom development it is fairly easy to add. See [dsClientToNode]: https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html [pickle]: http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html [JSSE system properties]: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization -[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- -[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- -[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html +[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- +[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- +[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index 156933f6649..08646b77609 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -59,7 +59,7 @@ the [configuration](../configuration/). Namely, these are: idempotent flag, quer consistency levels and page size. We recommended the configuration approach whenever possible (you can create execution profiles to capture common combinations of those options). -[Statement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html -[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/StatementBuilder.html -[execute]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- -[executeAsync]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[Statement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html +[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/StatementBuilder.html +[execute]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[executeAsync]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index 917482cae3e..051a3a35df9 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -61,8 +61,8 @@ In addition, simple statements with named parameters are currently not supported due to a [protocol limitation][CASSANDRA-10246] that will be fixed in a future version). If you try to execute such a batch, an `IllegalArgumentException` is thrown. -[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BatchStatement.html -[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- -[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BatchStatement.html +[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- [batch_dse]: http://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/useBatch.html [CASSANDRA-10246]: https://issues.apache.org/jira/browse/CASSANDRA-10246 diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index 03c2584e2c9..4100e864660 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -124,6 +124,6 @@ SimpleStatement statement = At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we'll probably deprecate `setRoutingKeyspace()`. -[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index b795e5f138f..29ad525fc42 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -330,10 +330,10 @@ With Cassandra 4 and [native protocol](../../native_protocol/) v5, this issue is new version with the response; the driver updates its local cache transparently, and the client can observe the new columns in the result set. -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [CASSANDRA-10786]: https://issues.apache.org/jira/browse/CASSANDRA-10786 [CASSANDRA-10813]: https://issues.apache.org/jira/browse/CASSANDRA-10813 [guava eviction]: https://github.com/google/guava/wiki/CachesExplained#reference-based-eviction -[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- -[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- +[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- +[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index 3b87d7521f3..d4f62e0a207 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -182,6 +182,6 @@ session.execute( Or you could also use [prepared statements](../prepared/), which don't have this limitation since parameter types are known in advance. -[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SimpleStatement.html -[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- -[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- +[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SimpleStatement.html +[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- +[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index 5b35bfd1750..2bb0573ce90 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -146,7 +146,7 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]" ``` -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index ced51bca1a5..f1496cbf176 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -145,6 +145,6 @@ datastax-java-driver { If you enable `throttling.delay`, make sure to also check the associated extra options to correctly size the underlying histograms (`metrics.session.throttling.delay.*`). -[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/RequestThrottlingException.html -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/RequestThrottlingException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index f15dc0c69d9..858b089ffbe 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -113,9 +113,9 @@ for (TraceEvent event : trace.getEvents()) { If you call `getQueryTrace()` for a statement that didn't have tracing enabled, an exception is thrown. -[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html -[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/QueryTrace.html -[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- -[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- -[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- -[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html +[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/QueryTrace.html +[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- +[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- +[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- +[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index b6222f65439..e5bda3947a6 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -139,5 +139,5 @@ BoundStatement bs = [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html -[TupleType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/TupleType.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/TupleValue.html +[TupleType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/TupleType.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/TupleValue.html diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index 06c6006a903..99c34f234c4 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -135,5 +135,5 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index 981c1e7292b..36db9562032 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -101,8 +101,8 @@ public interface ExecutionInfo { When a public API method is blocking, this is generally clearly stated in its javadocs. -[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index a583718a16e..50809f8a7f2 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -106,4 +106,4 @@ before compilation: [build.gradle]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/build.gradle [UserDao.kt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/src/main/kotlin/com/datastax/examples/mapper/killrvideo/user/UserDao.kt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index 89363b45bf0..8d6f9621b47 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -27,7 +27,7 @@ You need to build with Java 14, and pass the `--enable-preview` flag to both the runtime JVM. See [pom.xml] in the example. -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html [DataStax-Examples/object-mapper-jvm/record]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/record [pom.xml]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/record/pom.xml diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index 6174c274fb7..e0d1970c209 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -54,4 +54,4 @@ mapper builder. [DataStax-Examples/object-mapper-jvm/scala]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/scala [build.sbt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/scala/build.sbt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index 6ee6dfc0aab..c55a10cc3ba 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -148,8 +148,8 @@ In this case, any annotations declared in `Dao1` would be chosen over `Dao2`. To control how the hierarchy is scanned, annotate interfaces with [@HierarchyScanStrategy]. -[@Dao]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html [Entity Inheritance]: ../entities/#inheritance diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index 179f61a0b22..ed5fd69a535 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -236,8 +236,8 @@ flag: With this configuration, if a DAO method declares a non built-in return type, it will be surfaced as a compiler error. -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/MapperContext.html -[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html -[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/MapperContext.html +[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html +[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index c067d049106..6d4ad9854cc 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -151,15 +151,15 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@Delete]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Delete.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@Delete]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Delete.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index 9995e073ef8..6c37bb1169b 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -130,15 +130,15 @@ If the return type doesn't match the parameter type (for example [PagingIterable [AsyncResultSet]), the mapper processor will issue a compile-time error. -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[GettableByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/GettableByName.html -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[GettableByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/GettableByName.html +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html [Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index 2445490b8a1..1c2c1f24d3c 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -75,12 +75,12 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[@Increment]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Increment.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Increment]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Increment.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/CqlName.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index 624cf20f311..2d4a08fb694 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -108,13 +108,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Insert]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Insert]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index e94fed266c1..aca631062db 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -93,10 +93,10 @@ public interface UserDao extends InventoryDao { } ``` -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[MapperException]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/MapperException.html -[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET -[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[MapperException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/MapperException.html +[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET +[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL [CASSANDRA-7304]: https://issues.apache.org/jira/browse/CASSANDRA-7304 diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index 1ccc0f8e7b7..d45063eb74c 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -113,18 +113,18 @@ Then: query succeeds or not depends on whether the session that the mapper was built with has a [default keyspace]. -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Query]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Query.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[Row]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/Row.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Query]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Query.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index acf9de0fea4..e4958928c59 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -137,11 +137,11 @@ Here is the full implementation: the desired [PagingIterable][PagingIterable]. -[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html -[providerClass]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- -[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- -[providerMethod]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/MapperContext.html -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/EntityHelper.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html +[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html +[providerClass]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- +[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- +[providerMethod]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/MapperContext.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/EntityHelper.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index f42b41e4632..857e176552d 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -160,20 +160,20 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html -[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- -[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- -[groupBy()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- -[limit()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- -[orderBy()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- -[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html +[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- +[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- +[groupBy()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- +[limit()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- +[orderBy()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- +[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index 0929daaf847..de6701ada50 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -112,8 +112,8 @@ BoundStatement bind(Product product, BoundStatement statement); If you use a void method with [BoundStatement], the mapper processor will issue a compile-time warning. -[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html -[SettableByName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/SettableByName.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/data/UdtValue.html +[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html +[SettableByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/SettableByName.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index 57d73956e64..141b619dd7f 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -60,4 +60,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 8920e8f75f7..610bc9fb4d7 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -143,13 +143,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Update]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Update.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Update]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Update.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html [Boolean]: https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Boolean.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/ResultSet.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index 2d584bed282..72edc82ea66 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -555,22 +555,22 @@ the same level. To control how the class hierarchy is scanned, annotate classes with [@HierarchyScanStrategy]. -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/CqlName.html -[@Dao]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@Entity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Entity.html -[NameConverter]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html -[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html -[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Computed]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Computed.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Select.html -[@Insert]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[@Update]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Update.html -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[@Query]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Query.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@Entity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Entity.html +[NameConverter]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html +[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html +[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Computed]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Computed.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html +[@Insert]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[@Update]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Update.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[@Query]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Query.html [aliases]: http://cassandra.apache.org/doc/latest/cql/dml.html?#aliases -[@Transient]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Transient.html -[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@Transient]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Transient.html +[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 3c723aacb73..0a81816f9a3 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -230,8 +230,8 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) You can also permanently disable validation of an individual entity by annotating it with `@SchemaHint(targetElement = NONE)`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html -[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html -[@Mapper]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/mapper/annotations/Mapper.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html +[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html +[@Mapper]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Mapper.html diff --git a/manual/osgi/README.md b/manual/osgi/README.md index d0ee00538ad..966d89c12a6 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -138,7 +138,7 @@ starting the driver: [driver configuration]: ../core/configuration [OSGi]:https://www.osgi.org [JNR]: https://github.com/jnr/jnr-posix -[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- [JAVA-1127]:https://datastax-oss.atlassian.net/browse/JAVA-1127 -[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- -[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- +[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- +[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index fe508fca68b..ab4369f2016 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -212,8 +212,8 @@ For a complete tour of the API, browse the child pages in this manual: * [Terms](term/) * [Idempotence](idempotence/) -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/CqlIdentifier.html -[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html -[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html +[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html +[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index 1517b5a106a..01897774c85 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -132,4 +132,4 @@ It is mutually exclusive with column conditions: if you previously specified col the statement, they will be ignored; conversely, adding a column condition cancels a previous IF EXISTS clause. -[Condition]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/condition/Condition.html +[Condition]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/condition/Condition.html diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index c39d97869cb..2aff86a6825 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -141,5 +141,5 @@ deleteFrom("user") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index 74f87c5b204..269afba7437 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -114,4 +114,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index 9f0193825d5..c4d4990affa 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -201,5 +201,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Relation]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/relation/Relation.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Relation]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/relation/Relation.html diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index ea012439f11..de6d4bacd6c 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -44,4 +44,4 @@ element type: * [function](function/) * [aggregate](aggregate/) -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index 99d7b893b22..fbdf36147e3 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -76,4 +76,4 @@ dropAggregate("average").ifExists(); // DROP AGGREGATE IF EXISTS average ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index 508ff737eac..c77f6431b73 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -92,4 +92,4 @@ dropFunction("log").ifExists(); // DROP FUNCTION IF EXISTS log ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index ecbd9c4559c..9c590c1e79e 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -99,4 +99,4 @@ dropIndex("my_idx").ifExists(); // DROP INDEX IF EXISTS my_idx ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index ccdbcea3d1f..a07af3479f4 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -83,6 +83,6 @@ dropKeyspace("cycling").ifExists(); // DROP KEYSPACE IF EXISTS cycling ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index 89c0a687801..55c9cc41c07 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -85,5 +85,5 @@ dropTable("cyclist_by_age").ifExists(); // DROP MATERIALIZED VIEW IF EXISTS cyclist_by_age ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index da5ea6ff015..e0ed365375b 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -107,6 +107,6 @@ dropTable("cyclist_name").ifExists(); // DROP TABLE IF EXISTS cyclist_name ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html -[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html +[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index 734bcf65d8e..c5302843f7d 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -88,4 +88,4 @@ dropTable("address").ifExists(); // DROP TYPE IF EXISTS address ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index 1ca33a1c2f5..42fd0410bcd 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -391,5 +391,5 @@ selectFrom("user").all().allowFiltering(); // SELECT * FROM user ALLOW FILTERING ``` -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index 28169a31d9f..7fb94e0f31f 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -105,5 +105,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index 3a6c7609b5d..d877433dd2e 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -17,4 +17,4 @@ Truncate truncate2 = truncate(CqlIdentifier.fromCql("mytable")); Note that, at this stage, the query is ready to build. After creating a TRUNCATE query it does not take any values. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index 0d6c8a40644..1161d093bc4 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -251,5 +251,5 @@ update("foo") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Assignment]: https://docs.datastax.com/en/drivers/java/4.13/com/datastax/oss/driver/api/querybuilder/update/Assignment.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Assignment]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/update/Assignment.html From 02def26cacb7657e9a32266d2a5a92e1d444cbb2 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Feb 2022 09:37:09 -0300 Subject: [PATCH 206/395] [maven-release-plugin] prepare release 4.14.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 7eb3b983ec4..f1d0a71ecf1 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-core-shaded - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-mapper-processor - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-mapper-runtime - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-query-builder - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-test-infra - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-metrics-micrometer - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss java-driver-metrics-microprofile - 4.13.1-SNAPSHOT + 4.14.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index a88b6987392..ad58d447bf2 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index dce03062123..2278a520c21 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 0da803804e4..0894e2b9601 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 130204c6918..5abc68f5b4c 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.13.1-SNAPSHOT + 4.14.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 96e682bd087..630f34d9926 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 84b0e39d825..0c4e9a713d0 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index bf9be82718c..1a53602bf44 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 82b113dd1a8..427b9ff0ba6 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index af31fdc5fc2..a7161cbb0ea 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 281c9ff67b3..4a0166a3bd6 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 9de5ceb0e30..c7d73108a70 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.14.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 069af2819e9..b9dd3675ddd 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 6578516f10e..03d506407a9 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.13.1-SNAPSHOT + 4.14.0 java-driver-test-infra bundle From 5f46d3ed022fbbec1980344ebe69f8d5d4e1c7f9 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Fri, 18 Feb 2022 09:37:16 -0300 Subject: [PATCH 207/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index f1d0a71ecf1..a3baefbdb71 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.14.0 + 4.14.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index ad58d447bf2..1b2eddc6a3b 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 2278a520c21..c191e688b51 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 0894e2b9601..63267f03d8a 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 5abc68f5b4c..ee9c3a8af63 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.14.0 + 4.14.1-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 630f34d9926..24d337c8aab 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 0c4e9a713d0..486358cd1c0 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 1a53602bf44..e7e3408f39f 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 427b9ff0ba6..03f4524837b 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index a7161cbb0ea..3df7a6f929b 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 4a0166a3bd6..2cf8856baee 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index c7d73108a70..7caa9668bc2 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.14.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index b9dd3675ddd..867f9249ce9 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 03d506407a9..bd510000d8d 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.0 + 4.14.1-SNAPSHOT java-driver-test-infra bundle From 55e6e40afcd7df2be931285b323379f9ea8c6c82 Mon Sep 17 00:00:00 2001 From: Om Sharma Date: Wed, 6 Apr 2022 20:58:47 +0100 Subject: [PATCH 208/395] JAVA-3003: CVE-2014-4043 Update com.github.jnr:jnr-posix to 3.1.15 to remove the vulnerability (#1589) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7caa9668bc2..5c3f1c60b3b 100644 --- a/pom.xml +++ b/pom.xml @@ -132,7 +132,7 @@ com.github.jnr jnr-posix - 3.1.5 + 3.1.15 io.dropwizard.metrics From 6304cb725a858e107ac826edfa6c8a6983504d78 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 15 Apr 2022 11:54:43 -0500 Subject: [PATCH 209/395] JAVA-2977: Upgrade Netty to 4.1.75 (4.x) (#1592) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5c3f1c60b3b..42abf4d5c53 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 1.4.1 2.1.12 4.1.18 - 4.1.60.Final + 4.1.75.Final 1.2.1 !com.google.protobuf.*, !com.jcraft.jzlib.*, !com.ning.compress.*, !lzma.sdk.*, !net.jpountz.xxhash.*, !org.bouncycastle.*, !org.conscrypt.*, !org.apache.commons.logging.*, !org.apache.log4j.*, !org.apache.logging.log4j.*, !org.eclipse.jetty.*, !org.jboss.marshalling.*, !sun.misc.*, !sun.security.*, !com.barchart.udt.*, !com.fasterxml.aalto.*, !com.sun.nio.sctp.*, !gnu.io.*, !org.xml.sax.*, !org.w3c.dom.*, * + -->!com.google.protobuf.*, !com.jcraft.jzlib.*, !com.ning.compress.*, !lzma.sdk.*, !net.jpountz.xxhash.*, !org.bouncycastle.*, !org.conscrypt.*, !org.apache.commons.logging.*, !org.apache.log4j.*, !org.apache.logging.log4j.*, !org.eclipse.jetty.*, !org.jboss.marshalling.*, !sun.misc.*, !sun.security.*, !com.barchart.udt.*, !com.fasterxml.aalto.*, !com.sun.nio.sctp.*, !gnu.io.*, !org.xml.sax.*, !org.w3c.dom.*, !com.aayushatharva.brotli4j.*, !com.github.luben.zstd.*, * - 3.4.10 + 3.5.3 1.7.26 1.0.3 20210307 - 2.12.2 - 2.12.2 + 2.13.2 + 2.13.2.2 1.9.12 1.1.7.3 @@ -81,7 +81,7 @@ 4.0.3 2.0.0-M19 2.22.2 - 21.0.0.2 + 22.0.0.2 false ${skipTests} From 5d038049cbbf989ff28c73f4e193199e46650d51 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 27 Apr 2022 14:48:31 -0500 Subject: [PATCH 211/395] Update version in docs to 4.14.1 --- README.md | 2 +- changelog/README.md | 6 ++++++ manual/core/bom/README.md | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index daffaff95c8..dbfcf5c308e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.14.0](https://github.com/datastax/java-driver/tree/4.14.0).* +[4.14.1](https://github.com/datastax/java-driver/tree/4.14.1).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol diff --git a/changelog/README.md b/changelog/README.md index fd6dccdb3a0..eb17219a060 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,12 @@ +### 4.14.1 + +- [improvement] JAVA-3013: Upgrade dependencies to address CVEs and other security issues, 4.14.1 edition +- [improvement] JAVA-3003: Update jnr-posix to address CVE-2014-4043 +- [improvement] JAVA-2977: Update Netty to resolve higher-priority CVEs + ### 4.14.0 - [bug] JAVA-2976: Support missing protocol v5 error codes CAS_WRITE_UNKNOWN, CDC_WRITE_FAILURE diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index f1741a43372..df16bda4492 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.14.0 + 4.14.1 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.14.0 + 4.14.1 From 33154cfb33d041dc7c6a4cd70bfeb0692ac07145 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 27 Apr 2022 15:02:21 -0500 Subject: [PATCH 212/395] [maven-release-plugin] prepare release 4.14.1 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index a3baefbdb71..fb0aa7c1ace 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-core-shaded - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-mapper-processor - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-mapper-runtime - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-query-builder - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-test-infra - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-metrics-micrometer - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss java-driver-metrics-microprofile - 4.14.1-SNAPSHOT + 4.14.1 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 0ff78b2d319..7fb092040cb 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index c191e688b51..26bcf0673c0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 63267f03d8a..475b8a6926e 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index ee9c3a8af63..b9e22507d2d 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.14.1-SNAPSHOT + 4.14.1 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 24d337c8aab..29b5945f60a 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 486358cd1c0..9d78d920de6 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index e7e3408f39f..a2efa79426f 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 03f4524837b..2683fea3a48 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 3df7a6f929b..e934c102593 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 2cf8856baee..484ab5b0883 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 34ecf8dba71..6137eb7d5d5 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.14.1 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 867f9249ce9..8d6890db008 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index bd510000d8d..b2ddad07bd6 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1-SNAPSHOT + 4.14.1 java-driver-test-infra bundle From 82d61d8ed68271023b822afb00134b48b1624456 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 27 Apr 2022 15:02:25 -0500 Subject: [PATCH 213/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index fb0aa7c1ace..01fada01ad6 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.14.1 + 4.14.2-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 7fb092040cb..000e39af026 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 26bcf0673c0..4bdc5f1234c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 475b8a6926e..d65c82bca5d 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index b9e22507d2d..1089928dfc7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.14.1 + 4.14.2-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 29b5945f60a..9392ae28c66 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 9d78d920de6..3c2c7052247 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index a2efa79426f..062b3381687 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 2683fea3a48..62fcd1a477a 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index e934c102593..fc562771206 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 484ab5b0883..1720a69000d 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 6137eb7d5d5..8120beed458 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.14.1 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 8d6890db008..043b72cee93 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index b2ddad07bd6..0b8354c1bd3 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.1 + 4.14.2-SNAPSHOT java-driver-test-infra bundle From b1cf8a898b57d38cce2c6317a9c45af9cda698e8 Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Tue, 24 May 2022 09:00:05 -0700 Subject: [PATCH 214/395] Update dangling Cluster references in reference.conf to Session (#1596) --- core/src/main/resources/reference.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 44e454fe42d..d3c3c4f737f 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1041,7 +1041,7 @@ datastax-java-driver { # an incompatible node joins the cluster later, connection will fail and the driver will force # it down (i.e. never try to connect to it again). # - # You can check the actual version at runtime with Cluster.getContext().getProtocolVersion(). + # You can check the actual version at runtime with Session.getContext().getProtocolVersion(). # # Required: no # Modifiable at runtime: no @@ -1925,7 +1925,7 @@ datastax-java-driver { max-events = 20 } - # Options relating to schema metadata (Cluster.getMetadata.getKeyspaces). + # Options relating to schema metadata (Session.getMetadata.getKeyspaces). # This metadata is exposed by the driver for informational purposes, and is also necessary for # token-aware routing. schema { @@ -1934,7 +1934,7 @@ datastax-java-driver { # # Required: yes # Modifiable at runtime: yes, the new value will be used for refreshes issued after the - # change. It can also be overridden programmatically via Cluster.setSchemaMetadataEnabled. + # change. It can also be overridden programmatically via Session.setSchemaMetadataEnabled. # Overridable in a profile: no enabled = true @@ -2013,7 +2013,7 @@ datastax-java-driver { } } - # Whether token metadata (Cluster.getMetadata.getTokenMap) is enabled. + # Whether token metadata (Session.getMetadata.getTokenMap) is enabled. # This metadata is exposed by the driver for informational purposes, and is also necessary for # token-aware routing. # If this is false, it will remain empty, or to the last known value. Note that its computation From decabed60caf61412499ef320982b7b74ff45a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0tefan=20Miklo=C5=A1ovi=C4=8D?= Date: Thu, 26 May 2022 17:46:48 +0200 Subject: [PATCH 215/395] JAVA-2995: CodecNotFoundException doesn't extend DriverException (#1598) Co-authored-by: Alexandre Dutra --- core/revapi.json | 7 ++++ .../type/codec/CodecNotFoundException.java | 11 ++++- upgrade_guide/README.md | 40 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/core/revapi.json b/core/revapi.json index fe066e27b55..af719e9987e 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -6817,6 +6817,13 @@ "new": "method void com.fasterxml.jackson.databind.type.TypeBase::serialize(com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) throws java.io.IOException", "exception": "com.fasterxml.jackson.core.JsonProcessingException", "justification": "Upgrade deps around JAVA-2977 to address outstanding CVEs" + }, + { + "code": "java.class.nonFinalClassInheritsFromNewClass", + "old": "class com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException", + "new": "class com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException", + "superClass": "com.datastax.oss.driver.api.core.DriverException", + "justification": "Make CodecNotFoundException to extend DriverException as all other driver exceptions do" } ] } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/CodecNotFoundException.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/CodecNotFoundException.java index 4d46f253915..9396c2547d9 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/CodecNotFoundException.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/CodecNotFoundException.java @@ -15,6 +15,7 @@ */ package com.datastax.oss.driver.api.core.type.codec; +import com.datastax.oss.driver.api.core.DriverException; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; import com.datastax.oss.driver.api.core.type.reflect.GenericType; @@ -22,7 +23,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; /** Thrown when a suitable {@link TypeCodec} cannot be found by the {@link CodecRegistry}. */ -public class CodecNotFoundException extends RuntimeException { +public class CodecNotFoundException extends DriverException { private final DataType cqlType; @@ -48,7 +49,7 @@ public CodecNotFoundException( private CodecNotFoundException( String msg, Throwable cause, DataType cqlType, GenericType javaType) { - super(msg, cause); + super(msg, null, cause, true); this.cqlType = cqlType; this.javaType = javaType; } @@ -62,4 +63,10 @@ public DataType getCqlType() { public GenericType getJavaType() { return javaType; } + + @NonNull + @Override + public DriverException copy() { + return new CodecNotFoundException(getMessage(), getCause(), getCqlType(), getJavaType()); + } } diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 297c4ca7fda..68d03fbfd6e 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,45 @@ ## Upgrade guide +### 4.15.0 + +#### CodecNotFoundException now extends DriverException + +Before [JAVA-2995](https://datastax-oss.atlassian.net/browse/JAVA-2959), `CodecNotFoundException` +was extending `RuntimeException`. This is a discrepancy as all other exceptions extend +`DriverException`, which in turn extends `RuntimeException`. + +This was causing integrators to do workarounds in order to react on all exceptions correctly. + +The change introduced by JAVA-2995 shouldn't be a problem for most users. But if your code was using +a logic such as below, it won't compile anymore: + +```java +try { + doSomethingWithDriver(); +} catch(DriverException e) { +} catch(CodecNotFoundException e) { +} +``` + +You need to either reverse the catch order and catch `CodecNotFoundException` first: + +```java +try { + doSomethingWithDriver(); +} catch(CodecNotFoundException e) { +} catch(DriverException e) { +} +``` + +Or catch only `DriverException`: + +```java +try { + doSomethingWithDriver(); +} catch(DriverException e) { +} +``` + ### 4.14.0 #### AllNodesFailedException instead of NoNodeAvailableException in certain cases From 8511588f6efcf5b7d57e3a5876152ce7623b0499 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 26 May 2022 10:52:28 -0500 Subject: [PATCH 216/395] Minor fix to upgrade guide after last commit --- upgrade_guide/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 68d03fbfd6e..125c04db034 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -4,7 +4,7 @@ #### CodecNotFoundException now extends DriverException -Before [JAVA-2995](https://datastax-oss.atlassian.net/browse/JAVA-2959), `CodecNotFoundException` +Before [JAVA-2995](https://datastax-oss.atlassian.net/browse/JAVA-2995), `CodecNotFoundException` was extending `RuntimeException`. This is a discrepancy as all other exceptions extend `DriverException`, which in turn extends `RuntimeException`. From a76d38e4ec86c18850381ed4c01afd21e3bd1e6e Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 21 Jun 2022 17:04:39 -0500 Subject: [PATCH 217/395] JAVA-3023: Upgrade Netty to 4.1.77 (4.x) (#1600) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8120beed458..87e983b088d 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 1.4.1 2.1.12 4.1.18 - 4.1.75.Final + 4.1.77.Final 1.2.1 +### 4.14.2 (in progress) + +- [bug] JAVA-3002 JAVA-3005: Refresh entire node list when a new node is added + ### 4.14.1 - [improvement] JAVA-3013: Upgrade dependencies to address CVEs and other security issues, 4.14.1 edition diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java index 1412168d4f8..298b6b89d94 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManager.java @@ -185,10 +185,10 @@ private void onDebouncedTopologyEvent(TopologyEvent event) { } } else { LOG.debug( - "[{}] Received UP event for unknown node {}, adding it", + "[{}] Received UP event for unknown node {}, refreshing node list", logPrefix, event.broadcastRpcAddress); - metadataManager.addNode(event.broadcastRpcAddress); + metadataManager.refreshNodes(); } break; case SUGGEST_DOWN: diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManagerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManagerTest.java index d1b2f47d8dc..2680fa36893 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManagerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/NodeStateManagerTest.java @@ -147,7 +147,7 @@ public void should_apply_up_event_if_node_is_unknown_or_down() { } @Test - public void should_add_node_if_up_event_and_not_in_metadata() { + public void should_refresh_node_list_if_up_event_and_not_in_metadata() { // Given new NodeStateManager(context); @@ -157,7 +157,7 @@ public void should_add_node_if_up_event_and_not_in_metadata() { // Then verify(eventBus, never()).fire(any(NodeStateEvent.class)); - verify(metadataManager).addNode(NEW_ADDRESS); + verify(metadataManager).refreshNodes(); } @Test From fb24e9767f5c6301574ed7265f30c098f40eed9a Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 13 Jul 2022 14:24:52 -0500 Subject: [PATCH 219/395] JAVA-3021: Update docs to replace withPrimaryKey with withPartitionKey (#1599) --- manual/query_builder/schema/table/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index e0ed365375b..a3000ee70db 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -31,12 +31,12 @@ CreateTable create = createTable("cycling", "cyclist_name").withPartitionKey("id A table with only one column is not so typical however. At this point you may provide partition, clustering, regular and static columns using any of the following API methods: -* `withPrimaryKey(name, dataType)` +* `withPartitionKey(name, dataType)` * `withClusteringColumn(name, dataType)` * `withColumn(name, dataType)` * `withStaticColumn(name, dataType)` -Primary key precedence is driven by the order of `withPrimaryKey` and `withClusteringKey` +Primary key precedence is driven by the order of `withPartitionKey` and `withClusteringKey` invocations, for example: From df74d101f7fa1afd9b7ff31e73d81c3e6e226e47 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 13 Jul 2022 12:37:58 -0500 Subject: [PATCH 220/395] Some minor changelog updates --- changelog/README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog/README.md b/changelog/README.md index 9c18d471ca9..e102cd00767 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,15 +2,19 @@ -### 4.14.2 (in progress) +### 4.15.0 (in progress) -- [bug] JAVA-3002 JAVA-3005: Refresh entire node list when a new node is added +- [bug] JAVA-3021: Update table SchemaBuilder page to replace withPrimaryKey with withPartitionKey +- [bug] JAVA-3005: Node list refresh behavior in 4.x is different from 3.x +- [bug] JAVA-3002: spring-boot app keeps connecting to IP of replaced node +- [improvement] JAVA-3023 Upgrade Netty to 4.1.77 +- [improvement] JAVA-2995: CodecNotFoundException doesn't extend DriverException ### 4.14.1 - [improvement] JAVA-3013: Upgrade dependencies to address CVEs and other security issues, 4.14.1 edition -- [improvement] JAVA-3003: Update jnr-posix to address CVE-2014-4043 - [improvement] JAVA-2977: Update Netty to resolve higher-priority CVEs +- [improvement] JAVA-3003: Update jnr-posix to address CVE-2014-4043 ### 4.14.0 From 43a6ac5b6f0552c40bbeafb1a810108b63432044 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 13 Jul 2022 12:43:37 -0500 Subject: [PATCH 221/395] Upgrade version to 4.15.0-SNAPSHOT --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 2 +- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 01fada01ad6..73a9cebdf7e 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 000e39af026..742dc8e2d67 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 4bdc5f1234c..a53d476df0f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index d65c82bca5d..d5f8ad1f64b 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 1089928dfc7..35ff3b29856 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 9392ae28c66..f857df7c3d2 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 3c2c7052247..6d5b31a7a00 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 062b3381687..385e0050153 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 62fcd1a477a..9e08a931cfc 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index fc562771206..7569c81ef81 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 1720a69000d..2c6b90094ae 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 87e983b088d..3f9cb1227a8 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 043b72cee93..f958bf9f092 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 0b8354c1bd3..035436526a6 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.14.2-SNAPSHOT + 4.15.0-SNAPSHOT java-driver-test-infra bundle From 65d2c19c401175dcc6c370560dd5f783d05b05b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0tefan=20Miklo=C5=A1ovi=C4=8D?= Date: Thu, 14 Jul 2022 23:06:02 +0200 Subject: [PATCH 222/395] JAVA-3022: Implementation of address translator for fixed hostname (#1597) --- .../FixedHostNameAddressTranslator.java | 72 +++++++++++++++++++ core/src/main/resources/reference.conf | 3 + .../FixedHostNameAddressTranslatorTest.java | 46 ++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java new file mode 100644 index 00000000000..80009de8c3c --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java @@ -0,0 +1,72 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import com.datastax.oss.driver.api.core.addresstranslation.AddressTranslator; +import com.datastax.oss.driver.api.core.config.DriverOption; +import com.datastax.oss.driver.api.core.context.DriverContext; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.net.InetSocketAddress; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This translator always returns same hostname, no matter what IP address a node has but still + * using its native transport port. + * + *

    The translator can be used for scenarios when all nodes are behind some kind of proxy, and it + * is not tailored for one concrete use case. One can use this, for example, for AWS PrivateLink as + * all nodes would be exposed to consumer - behind one hostname pointing to AWS Endpoint. + */ +public class FixedHostNameAddressTranslator implements AddressTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(FixedHostNameAddressTranslator.class); + + public static final String ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME = + "advanced.address-translator.advertised-hostname"; + + public static DriverOption ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME_OPTION = + new DriverOption() { + @NonNull + @Override + public String getPath() { + return ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME; + } + }; + + private final String advertisedHostname; + private final String logPrefix; + + public FixedHostNameAddressTranslator(@NonNull DriverContext context) { + logPrefix = context.getSessionName(); + advertisedHostname = + context + .getConfig() + .getDefaultProfile() + .getString(ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME_OPTION); + } + + @NonNull + @Override + public InetSocketAddress translate(@NonNull InetSocketAddress address) { + final int port = address.getPort(); + LOG.debug("[{}] Resolved {}:{} to {}:{}", logPrefix, address, port, advertisedHostname, port); + return new InetSocketAddress(advertisedHostname, port); + } + + @Override + public void close() {} +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index d3c3c4f737f..f7e2cd76ad1 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -990,6 +990,7 @@ datastax-java-driver { # # The driver provides the following implementations out of the box: # - PassThroughAddressTranslator: returns all addresses unchanged + # - FixedHostNameAddressTranslator: translates all addresses to a specific hostname. # - Ec2MultiRegionAddressTranslator: suitable for an Amazon multi-region EC2 deployment where # clients are also deployed in EC2. It optimizes network costs by favoring private IPs over # public ones whenever possible. @@ -997,6 +998,8 @@ datastax-java-driver { # You can also specify a custom class that implements AddressTranslator and has a public # constructor with a DriverContext argument. class = PassThroughAddressTranslator + # This property has to be set only in case you use FixedHostNameAddressTranslator. + # advertised-hostname = mycustomhostname } # Whether to resolve the addresses passed to `basic.contact-points`. diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java new file mode 100644 index 00000000000..d7ee0e2d880 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java @@ -0,0 +1,46 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.context.MockedDriverContextFactory; +import java.net.InetSocketAddress; +import java.util.Optional; +import org.junit.Test; + +public class FixedHostNameAddressTranslatorTest { + + @Test + public void should_translate_address() { + DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class); + when(defaultProfile.getString( + FixedHostNameAddressTranslator.ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME_OPTION)) + .thenReturn("myaddress"); + DefaultDriverContext defaultDriverContext = + MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile)); + + FixedHostNameAddressTranslator translator = + new FixedHostNameAddressTranslator(defaultDriverContext); + InetSocketAddress address = new InetSocketAddress("192.0.2.5", 6061); + + assertThat(translator.translate(address)).isEqualTo(new InetSocketAddress("myaddress", 6061)); + } +} From 03961c9510ff9a111e07b57c4950a8e8966dfff4 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko <79898499+smatvienko-tb@users.noreply.github.com> Date: Wed, 7 Sep 2022 19:21:37 +0300 Subject: [PATCH 223/395] JAVA-3041: Update Guava session sample code to use ProgrammaticArguments (#1606) Enabling support for Astra in the Guava ListenableFuture examples requires use of the new ProgrammaticArguments constructor/method --- .../guava/api/GuavaSessionBuilder.java | 28 ++----------------- .../guava/internal/GuavaDriverContext.java | 28 ++----------------- 2 files changed, 6 insertions(+), 50 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/api/GuavaSessionBuilder.java b/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/api/GuavaSessionBuilder.java index 1fe041fcfe7..6356b632f3e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/api/GuavaSessionBuilder.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/api/GuavaSessionBuilder.java @@ -18,40 +18,18 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.metadata.NodeStateListener; -import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; +import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; import com.datastax.oss.driver.api.core.session.SessionBuilder; -import com.datastax.oss.driver.api.core.tracker.RequestTracker; -import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.example.guava.internal.DefaultGuavaSession; import com.datastax.oss.driver.example.guava.internal.GuavaDriverContext; import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; public class GuavaSessionBuilder extends SessionBuilder { @Override protected DriverContext buildContext( - DriverConfigLoader configLoader, - List> typeCodecs, - NodeStateListener nodeStateListener, - SchemaChangeListener schemaChangeListener, - RequestTracker requestTracker, - Map localDatacenters, - Map> nodeFilters, - ClassLoader classLoader) { - return new GuavaDriverContext( - configLoader, - typeCodecs, - nodeStateListener, - schemaChangeListener, - requestTracker, - localDatacenters, - nodeFilters, - classLoader); + DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { + return new GuavaDriverContext(configLoader, programmaticArguments); } @Override diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java b/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java index 3ecf6a1b128..5a8b44be739 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java @@ -18,11 +18,7 @@ import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.cql.PrepareRequest; import com.datastax.oss.driver.api.core.cql.Statement; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.metadata.NodeStateListener; -import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; -import com.datastax.oss.driver.api.core.tracker.RequestTracker; -import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; import com.datastax.oss.driver.example.guava.api.GuavaSession; import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; @@ -30,9 +26,6 @@ import com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor; import com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor; import com.datastax.oss.driver.internal.core.session.RequestProcessorRegistry; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; /** * A Custom {@link DefaultDriverContext} that overrides {@link #getRequestProcessorRegistry()} to @@ -41,23 +34,8 @@ public class GuavaDriverContext extends DefaultDriverContext { public GuavaDriverContext( - DriverConfigLoader configLoader, - List> typeCodecs, - NodeStateListener nodeStateListener, - SchemaChangeListener schemaChangeListener, - RequestTracker requestTracker, - Map localDatacenters, - Map> nodeFilters, - ClassLoader classLoader) { - super( - configLoader, - typeCodecs, - nodeStateListener, - schemaChangeListener, - requestTracker, - localDatacenters, - nodeFilters, - classLoader); + DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { + super(configLoader, programmaticArguments); } @Override From 8439108eb0dc54787819a2c5b81eccedce607fe1 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 14 Sep 2022 22:03:01 +0000 Subject: [PATCH 224/395] Docs + changelog updates --- README.md | 2 +- changelog/README.md | 4 +++- manual/core/bom/README.md | 4 ++-- manual/core/integration/README.md | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dbfcf5c308e..d2930ba6e66 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.14.1](https://github.com/datastax/java-driver/tree/4.14.1).* +[4.15.0](https://github.com/datastax/java-driver/tree/4.15.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol diff --git a/changelog/README.md b/changelog/README.md index e102cd00767..a0ec32f7a8b 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,8 +2,10 @@ -### 4.15.0 (in progress) +### 4.15.0 +- [improvement] JAVA-3041: Update Guava session sample code to use ProgrammaticArguments +- [improvement] JAVA-3022: Implement AddressTranslator for AWS PrivateLink - [bug] JAVA-3021: Update table SchemaBuilder page to replace withPrimaryKey with withPartitionKey - [bug] JAVA-3005: Node list refresh behavior in 4.x is different from 3.x - [bug] JAVA-3002: spring-boot app keeps connecting to IP of replaced node diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index df16bda4492..dc8f12eb599 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.14.1 + 4.15.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.14.1 + 4.15.0 diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 2935e84a485..9900d3b3f90 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -562,6 +562,7 @@ Here are the recommended TinkerPop versions for each driver version:

    Driver versionTinkerPop version
    4.14.03.4.10
    4.13.03.4.10
    4.12.03.4.10
    4.11.03.4.10
    + From f5b4c2586961884d2c0ddaf6189ad4d5836bf293 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 19 Sep 2022 18:51:06 +0000 Subject: [PATCH 225/395] [maven-release-plugin] prepare release 4.15.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 73a9cebdf7e..0893a09571d 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-core-shaded - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-mapper-processor - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-mapper-runtime - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-query-builder - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-test-infra - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-metrics-micrometer - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss java-driver-metrics-microprofile - 4.15.0-SNAPSHOT + 4.15.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 742dc8e2d67..03a5f245e70 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index a53d476df0f..b65c9786b2d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index d5f8ad1f64b..e4f9d490a73 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 35ff3b29856..5ebef2b974e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.15.0-SNAPSHOT + 4.15.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index f857df7c3d2..2d8c04f5150 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 6d5b31a7a00..b2e375723c5 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 385e0050153..39f4b187289 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 9e08a931cfc..9407e7d34d5 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 7569c81ef81..b49a633a699 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 2c6b90094ae..9727ac3e93a 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 3f9cb1227a8..46d3d197362 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.15.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index f958bf9f092..58f21ea1c9b 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 035436526a6..db568c12334 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0-SNAPSHOT + 4.15.0 java-driver-test-infra bundle From f6cc4d787b1118e4240d584241a97bbbea1c6607 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 19 Sep 2022 18:51:11 +0000 Subject: [PATCH 226/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 0893a09571d..837fcde0f89 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.15.0 + 4.15.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 03a5f245e70..0cf5700b493 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index b65c9786b2d..288b0df925a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index e4f9d490a73..7a077be1553 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 5ebef2b974e..21417669a5f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.15.0 + 4.15.1-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 2d8c04f5150..17e4ff393ef 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index b2e375723c5..81c1a78c95a 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 39f4b187289..70121a8b9ad 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 9407e7d34d5..f1536f493d1 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index b49a633a699..b16f8b17c41 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 9727ac3e93a..1e78ce04975 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 46d3d197362..2ac1715fee9 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.15.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 58f21ea1c9b..96559c8588e 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index db568c12334..873de05d8c4 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.0 + 4.15.1-SNAPSHOT java-driver-test-infra bundle From 0a61884b7fcb62a839d15af94686eb1d9d4b440e Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Fri, 7 Oct 2022 12:43:48 -0700 Subject: [PATCH 227/395] Standardize on DataStax vs Datastax since that appears to be more common (#1608) Updates to documentation only --- README.md | 2 +- .../driver/api/core/cql/continuous/ContinuousSession.java | 8 ++++---- .../continuous/reactive/ContinuousReactiveSession.java | 4 ++-- .../datastax/dse/driver/api/core/graph/GraphSession.java | 4 ++-- .../java/com/datastax/oss/driver/api/core/CqlSession.java | 2 +- .../driver/api/core/auth/PlainTextAuthProviderBase.java | 2 +- .../api/core/auth/ProgrammaticPlainTextAuthProvider.java | 4 ++-- .../oss/driver/api/core/config/DefaultDriverOption.java | 2 +- .../oss/driver/api/core/config/TypedDriverOption.java | 2 +- .../oss/driver/api/core/session/SessionBuilder.java | 2 +- .../driver/internal/core/auth/PlainTextAuthProvider.java | 2 +- core/src/main/resources/reference.conf | 4 ++-- manual/core/dse/README.md | 4 ++-- manual/core/integration/README.md | 2 +- manual/core/metadata/node/README.md | 4 ++-- manual/query_builder/README.md | 4 ++-- upgrade_guide/README.md | 6 +++--- 17 files changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index d2930ba6e66..0b5a61520f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Datastax Java Driver for Apache Cassandra® +# DataStax Java Driver for Apache Cassandra® [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core) diff --git a/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.java b/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.java index f98b0a5d1fa..bf05fce92b1 100644 --- a/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.java +++ b/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.java @@ -30,8 +30,8 @@ /** * A session that has the ability to execute continuous paging queries. * - *

    Continuous paging is a new method of streaming bulk amounts of records from Datastax - * Enterprise (DSE) to the Datastax Java Driver, available since DSE 5.1. It is mainly intended to + *

    Continuous paging is a new method of streaming bulk amounts of records from DataStax + * Enterprise (DSE) to the DataStax Java Driver, available since DSE 5.1. It is mainly intended to * be leveraged by DSE * Analytics and Apache Spark™, or by any similar analytics tool that needs to read large @@ -76,7 +76,7 @@ public interface ContinuousSession extends Session { * *

    See {@link ContinuousSession} for more explanations about continuous paging. * - *

    This feature is only available with Datastax Enterprise. Executing continuous queries + *

    This feature is only available with DataStax Enterprise. Executing continuous queries * against an Apache Cassandra© cluster will result in a runtime error. * * @param statement the query to execute. @@ -99,7 +99,7 @@ default ContinuousResultSet executeContinuously(@NonNull Statement statement) * *

    See {@link ContinuousSession} for more explanations about continuous paging. * - *

    This feature is only available with Datastax Enterprise. Executing continuous queries + *

    This feature is only available with DataStax Enterprise. Executing continuous queries * against an Apache Cassandra© cluster will result in a runtime error. * * @param statement the query to execute. diff --git a/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.java b/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.java index 9661f9bf5a1..20392fb81ec 100644 --- a/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.java +++ b/core/src/main/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.java @@ -51,7 +51,7 @@ public interface ContinuousReactiveSession extends Session { * *

    See {@link ContinuousSession} for more explanations about continuous paging. * - *

    This feature is only available with Datastax Enterprise. Executing continuous queries + *

    This feature is only available with DataStax Enterprise. Executing continuous queries * against an Apache Cassandra® cluster will result in a runtime error. * * @param query the query to execute. @@ -68,7 +68,7 @@ default ContinuousReactiveResultSet executeContinuouslyReactive(@NonNull String * *

    See {@link ContinuousSession} for more explanations about continuous paging. * - *

    This feature is only available with Datastax Enterprise. Executing continuous queries + *

    This feature is only available with DataStax Enterprise. Executing continuous queries * against an Apache Cassandra® cluster will result in a runtime error. * * @param statement the statement to execute. diff --git a/core/src/main/java/com/datastax/dse/driver/api/core/graph/GraphSession.java b/core/src/main/java/com/datastax/dse/driver/api/core/graph/GraphSession.java index 2c022ff4d49..6cd447e9c2e 100644 --- a/core/src/main/java/com/datastax/dse/driver/api/core/graph/GraphSession.java +++ b/core/src/main/java/com/datastax/dse/driver/api/core/graph/GraphSession.java @@ -49,7 +49,7 @@ public interface GraphSession extends Session { * configuration and schema. * * - *

    This feature is only available with Datastax Enterprise. Executing graph queries against an + *

    This feature is only available with DataStax Enterprise. Executing graph queries against an * Apache Cassandra® cluster will result in a runtime error. * * @see GraphResultSet @@ -67,7 +67,7 @@ default GraphResultSet execute(@NonNull GraphStatement graphStatement) { * Executes a graph statement asynchronously (the call returns as soon as the statement was sent, * generally before the result is available). * - *

    This feature is only available with Datastax Enterprise. Executing graph queries against an + *

    This feature is only available with DataStax Enterprise. Executing graph queries against an * Apache Cassandra® cluster will result in a runtime error. * * @see #execute(GraphStatement) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/CqlSession.java b/core/src/main/java/com/datastax/oss/driver/api/core/CqlSession.java index 2392182bf67..86eb88e2f0b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/CqlSession.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/CqlSession.java @@ -32,7 +32,7 @@ * *

      *
    • CQL requests: synchronous, asynchronous or reactive mode; - *
    • requests specific to Datastax Enterprise: graph and continuous paging. + *
    • requests specific to DataStax Enterprise: graph and continuous paging. *
    * * Client applications can use this interface even if they don't need all the features. In diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java b/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java index c9241577d6b..9624724b226 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.java @@ -100,7 +100,7 @@ public static class Credentials { * Builds an instance for username/password authentication, and proxy authentication with the * given authorizationId. * - *

    This feature is only available with Datastax Enterprise. If the target server is Apache + *

    This feature is only available with DataStax Enterprise. If the target server is Apache * Cassandra, the authorizationId will be ignored. */ public Credentials( diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java b/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java index 7166e72b1f5..50de327884d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.java @@ -67,7 +67,7 @@ public ProgrammaticPlainTextAuthProvider(@NonNull String username, @NonNull Stri * Builds an instance for username/password authentication, and proxy authentication with the * given authorizationId. * - *

    This feature is only available with Datastax Enterprise. If the target server is Apache + *

    This feature is only available with DataStax Enterprise. If the target server is Apache * Cassandra, use {@link #ProgrammaticPlainTextAuthProvider(String, String)} instead, or set the * authorizationId to an empty string. */ @@ -109,7 +109,7 @@ public void setPassword(@NonNull String password) { * *

    The new credentials will be used for all connections initiated after this method was called. * - *

    This feature is only available with Datastax Enterprise. If the target server is Apache + *

    This feature is only available with DataStax Enterprise. If the target server is Apache * Cassandra, this method should not be used. * * @param authorizationId the new authorization id. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index b2fba21d6a3..e7e75d952fa 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -793,7 +793,7 @@ public enum DefaultDriverOption implements DriverOption { NETTY_DAEMON("advanced.netty.daemon"), /** - * The location of the cloud secure bundle used to connect to Datastax Apache Cassandra as a + * The location of the cloud secure bundle used to connect to DataStax Apache Cassandra as a * service. * *

    Value-type: {@link String} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index bce8f923c77..2428be064ce 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -617,7 +617,7 @@ public String toString() { public static final TypedDriverOption NETTY_DAEMON = new TypedDriverOption<>(DefaultDriverOption.NETTY_DAEMON, GenericType.BOOLEAN); /** - * The location of the cloud secure bundle used to connect to Datastax Apache Cassandra as a + * The location of the cloud secure bundle used to connect to DataStax Apache Cassandra as a * service. */ public static final TypedDriverOption CLOUD_SECURE_CONNECT_BUNDLE = diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index 966372fa20d..2cfd7bf55a0 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -351,7 +351,7 @@ public SelfT withAuthCredentials(@NonNull String username, @NonNull String passw * Configures the session to use DSE plaintext authentication with the given username and * password, and perform proxy authentication with the given authorization id. * - *

    This feature is only available in Datastax Enterprise. If connecting to Apache Cassandra, + *

    This feature is only available in DataStax Enterprise. If connecting to Apache Cassandra, * the authorization id will be ignored; it is recommended to use {@link * #withAuthCredentials(String, String)} instead. * diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java b/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java index 73f320bbcdf..857ef456136 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/auth/PlainTextAuthProvider.java @@ -39,7 +39,7 @@ * username = cassandra * password = cassandra * - * // If connecting to Datastax Enterprise, this additional option allows proxy authentication + * // If connecting to DataStax Enterprise, this additional option allows proxy authentication * // (login as another user or role) * authorization-id = userOrRole * } diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index f7e2cd76ad1..ee83280032e 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -241,7 +241,7 @@ datastax-java-driver { slow-replica-avoidance = true } basic.cloud { - # The location of the cloud secure bundle used to connect to Datastax Apache Cassandra as a + # The location of the cloud secure bundle used to connect to DataStax Apache Cassandra as a # service. # This setting must be a valid URL. # If the protocol is not specified, it is implicitly assumed to be the `file://` protocol, @@ -683,7 +683,7 @@ datastax-java-driver { # # The driver provides two implementations: # - PlainTextAuthProvider: uses plain-text credentials. It requires the `username` and - # `password` options below. When connecting to Datastax Enterprise, an optional + # `password` options below. When connecting to DataStax Enterprise, an optional # `authorization-id` can also be specified. # For backward compatibility with previous driver versions, you can also use the class name # "DsePlainTextAuthProvider" for this provider. diff --git a/manual/core/dse/README.md b/manual/core/dse/README.md index e0d41ef38c7..8df3568e1ff 100644 --- a/manual/core/dse/README.md +++ b/manual/core/dse/README.md @@ -1,6 +1,6 @@ ## DSE-specific features -Some driver features only work with Datastax Enterprise: +Some driver features only work with DataStax Enterprise: * [Graph](graph/); * [Geospatial types](geotypes/); @@ -8,4 +8,4 @@ Some driver features only work with Datastax Enterprise: Note that, if you don't use these features, you might be able to exclude certain dependencies in order to limit the number of JARs in your classpath. See the -[Integration](../integration/#driver-dependencies) page. \ No newline at end of file +[Integration](../integration/#driver-dependencies) page. diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 9900d3b3f90..3f42b1dabfe 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -453,7 +453,7 @@ dependency: [Jackson](https://github.com/FasterXML/jackson) is used: -* when connecting to [Datastax Astra](../../cloud/); +* when connecting to [DataStax Astra](../../cloud/); * when Insights monitoring is enabled; * when [Json codecs](../custom_codecs) are being used. diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 1555c2ad1a5..ae66a468fd3 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -51,7 +51,7 @@ but in general it represents the proximity to the client, and `LOCAL` nodes will coordinators. They also influence pooling options. [Node#getExtras()] contains additional free-form properties. This is intended for future evolution -or custom driver extensions. In particular, if the driver is connected to Datastax Enterprise, the +or custom driver extensions. In particular, if the driver is connected to DataStax Enterprise, the map will contain additional information under the keys defined in [DseNodeProperties]: ```java @@ -142,4 +142,4 @@ the source code. [NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html [NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html [SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html \ No newline at end of file +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index ab4369f2016..4677fb84145 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -70,13 +70,13 @@ SimpleStatement statement = select.build(); SimpleStatementBuilder builder = select.builder(); ``` -#### Datastax Enterprise +#### DataStax Enterprise The driver provides two additional entry points for DSE-specific queries: [DseQueryBuilder] and [DseSchemaBuilder]. They extend their respective non-DSE counterparts, so anything that is available on the default query builder can also be done with the DSE query builder. -We recommend that you use those classes if you are targeting Datastax Enterprise; they will be +We recommend that you use those classes if you are targeting DataStax Enterprise; they will be enriched in the future if DSE adds custom CQL syntax. Currently, the only difference is the support for the `DETERMINISTIC` and `MONOTONIC` keywords when diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 125c04db034..785f51290da 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -372,7 +372,7 @@ least 4.6.1. ### 4.4.0 -Datastax Enterprise support is now available directly in the main driver. There is no longer a +DataStax Enterprise support is now available directly in the main driver. There is no longer a separate DSE driver. #### For Apache Cassandra® users @@ -388,7 +388,7 @@ Apart from that, the only visible change is that DSE-specific features are now e lean, you can exclude some dependencies when you don't use the corresponding DSE features; see the [Integration>Driver dependencies](../manual/core/integration/#driver-dependencies) section. -#### For Datastax Enterprise users +#### For DataStax Enterprise users Adjust your Maven coordinates to use the unified artifact: @@ -514,7 +514,7 @@ We have dropped support for legacy protocol versions v1 and v2. As a result, the compatible with: * **Apache Cassandra®: 2.1 and above**; -* **Datastax Enterprise: 4.7 and above**. +* **DataStax Enterprise: 4.7 and above**. #### Packages From 0351c4fa0297332054114dc730c7ab460650fa55 Mon Sep 17 00:00:00 2001 From: Benoit TELLIER Date: Wed, 16 Nov 2022 02:54:54 +0700 Subject: [PATCH 228/395] Improve IdentifierIndex firstIndexOf performance (#1615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve IdentifierIndex firstIndexOf performance Avoids doing two hasmap lookups and instead does a single one, thus improving performances (CPU) of rougthly 33%. In applications reading lots of rows and not managing manually indexes (which is tricky, boiler plate and error prone), IdentifierIndex::firstIndexOf is typically a CPU hotspots. In reactive applications it might even run on the driver event loop. As such, performances gains here are welcome. ## Before ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexGetFirst avgt 5 0.046 ± 0.005 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.046 ± 0.002 us/op ``` ## After ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexGetFirst avgt 5 0.028 ± 0.002 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.030 ± 0.002 us/op ``` * Use ImmutableListMultimap within IdentifierIndex This unlocks massive performance gains upon reads, for a minor slow down at instanciation time, which won't be felt by applications relying on prepared statements. ## Before ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexAllIndices avgt 5 0.007 ± 0.001 us/op IdentifierIndexBench.complexGetFirst avgt 5 0.026 ± 0.002 us/op IdentifierIndexBench.createComplex avgt 5 0.759 ± 0.059 us/op IdentifierIndexBench.createSimple avgt 5 0.427 ± 0.048 us/op IdentifierIndexBench.simpleAllIndices avgt 5 0.007 ± 0.001 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.027 ± 0.002 us/op ``` ## After ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexAllIndices avgt 5 0.004 ± 0.001 us/op IdentifierIndexBench.complexGetFirst avgt 5 0.005 ± 0.001 us/op IdentifierIndexBench.createComplex avgt 5 0.680 ± 0.020 us/op IdentifierIndexBench.createSimple avgt 5 0.538 ± 0.096 us/op IdentifierIndexBench.simpleAllIndices avgt 5 0.004 ± 0.001 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.005 ± 0.001 us/op ``` --- .../internal/core/data/IdentifierIndex.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java index 29396f08440..74c98ed7f4e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java @@ -20,8 +20,11 @@ import com.datastax.oss.driver.api.core.data.GettableById; import com.datastax.oss.driver.api.core.data.GettableByName; import com.datastax.oss.driver.internal.core.util.Strings; +import com.datastax.oss.driver.shaded.guava.common.collect.ArrayListMultimap; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableListMultimap; import com.datastax.oss.driver.shaded.guava.common.collect.LinkedListMultimap; import com.datastax.oss.driver.shaded.guava.common.collect.ListMultimap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import net.jcip.annotations.Immutable; @@ -40,9 +43,9 @@ public class IdentifierIndex { private final ListMultimap byCaseInsensitiveName; public IdentifierIndex(List ids) { - this.byId = LinkedListMultimap.create(ids.size()); - this.byCaseSensitiveName = LinkedListMultimap.create(ids.size()); - this.byCaseInsensitiveName = LinkedListMultimap.create(ids.size()); + ImmutableListMultimap.Builder byId = ImmutableListMultimap.builder(); + ImmutableListMultimap.Builder byCaseSensitiveName = ImmutableListMultimap.builder(); + ImmutableListMultimap.Builder byCaseInsensitiveName = ImmutableListMultimap.builder(); int i = 0; for (CqlIdentifier id : ids) { @@ -51,6 +54,10 @@ public IdentifierIndex(List ids) { byCaseInsensitiveName.put(id.asInternal().toLowerCase(Locale.ROOT), i); i += 1; } + + this.byId = byId.build(); + this.byCaseSensitiveName = byCaseSensitiveName.build(); + this.byCaseInsensitiveName = byCaseInsensitiveName.build(); } /** @@ -68,8 +75,8 @@ public List allIndicesOf(String name) { * AccessibleByName}, or -1 if it's not in the list. */ public int firstIndexOf(String name) { - List indices = allIndicesOf(name); - return indices.isEmpty() ? -1 : indices.get(0); + Iterator indices = allIndicesOf(name).iterator(); + return indices.hasNext() ? -1 : indices.next(); } /** Returns all occurrences of a given identifier. */ @@ -79,7 +86,7 @@ public List allIndicesOf(CqlIdentifier id) { /** Returns the first occurrence of a given identifier, or -1 if it's not in the list. */ public int firstIndexOf(CqlIdentifier id) { - List indices = allIndicesOf(id); - return indices.isEmpty() ? -1 : indices.get(0); + Iterator indices = allIndicesOf(id).iterator(); + return indices.hasNext() ? -1 : indices.next(); } } From f9ced726c20dcedd11401e2e01f9f01321857329 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 15 Nov 2022 14:04:15 -0600 Subject: [PATCH 229/395] Maven formatting fixes after last commit --- .../oss/driver/internal/core/data/IdentifierIndex.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java index 74c98ed7f4e..6b1d8fbb3a6 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java @@ -20,9 +20,7 @@ import com.datastax.oss.driver.api.core.data.GettableById; import com.datastax.oss.driver.api.core.data.GettableByName; import com.datastax.oss.driver.internal.core.util.Strings; -import com.datastax.oss.driver.shaded.guava.common.collect.ArrayListMultimap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableListMultimap; -import com.datastax.oss.driver.shaded.guava.common.collect.LinkedListMultimap; import com.datastax.oss.driver.shaded.guava.common.collect.ListMultimap; import java.util.Iterator; import java.util.List; @@ -44,8 +42,10 @@ public class IdentifierIndex { public IdentifierIndex(List ids) { ImmutableListMultimap.Builder byId = ImmutableListMultimap.builder(); - ImmutableListMultimap.Builder byCaseSensitiveName = ImmutableListMultimap.builder(); - ImmutableListMultimap.Builder byCaseInsensitiveName = ImmutableListMultimap.builder(); + ImmutableListMultimap.Builder byCaseSensitiveName = + ImmutableListMultimap.builder(); + ImmutableListMultimap.Builder byCaseInsensitiveName = + ImmutableListMultimap.builder(); int i = 0; for (CqlIdentifier id : ids) { From a40bbc2e451f03c6328ccfcbe0ac6560fd0492cf Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 15 Nov 2022 14:11:34 -0600 Subject: [PATCH 230/395] JAVA-3045: Fix GraalVM native image support for GraalVM 22.2 (#1612) --- .../internal/core/protocol/CompressorSubstitutions.java | 9 --------- .../oss/driver/internal/core/util/Dependency.java | 8 +++++--- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java index 889e4e1c137..f4578720f23 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/CompressorSubstitutions.java @@ -21,7 +21,6 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.internal.core.util.GraalDependencyChecker; import com.datastax.oss.protocol.internal.Compressor; -import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import io.netty.buffer.ByteBuf; @@ -82,14 +81,6 @@ public static Compressor newInstance(String name, DriverContext context } } - @TargetClass(value = Lz4Compressor.class, onlyWith = Lz4Missing.class) - @Delete - public static final class DeleteLz4Compressor {} - - @TargetClass(value = SnappyCompressor.class) - @Delete - public static final class DeleteSnappyCompressor {} - public static class Lz4Present implements BooleanSupplier { @Override public boolean getAsBoolean() { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java index bbefe698d55..72db22e5c5b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/Dependency.java @@ -15,7 +15,9 @@ */ package com.datastax.oss.driver.internal.core.util; -import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * A set of driver optional dependencies and a common mechanism to test the presence of such @@ -48,10 +50,10 @@ public enum Dependency { ; @SuppressWarnings("ImmutableEnumChecker") - private final ImmutableList clzs; + private final List clzs; Dependency(String... classNames) { - clzs = ImmutableList.copyOf(classNames); + clzs = Collections.unmodifiableList(Arrays.asList(classNames)); } public Iterable classes() { From 97d9c4c7083a12d177be91ffc81b690e33483292 Mon Sep 17 00:00:00 2001 From: Benoit TELLIER Date: Sat, 19 Nov 2022 05:39:48 +0700 Subject: [PATCH 231/395] Optimizations for TypeSafeDriverConfig (#1616) * TypesafeDriverConfig: getProfile can avoid calling containsKey On a typical applicative workload, 0.53% of CPU is spend resolving configuration profiles. By getting the profile first and failing if it is null we can easily cut that in half. * TypesafeDriverConfig: optimize getDefaultProfile We could easily get a dedicated field for the default profile thus avoiding recurring maps lookups. * fixup! TypesafeDriverConfig: optimize getDefaultProfile --- .../config/typesafe/TypesafeDriverConfig.java | 19 ++++++++++++++----- .../typesafe/TypesafeDriverConfigTest.java | 8 ++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java index cc3f841436b..ca5d919c604 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java @@ -32,6 +32,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import java.net.URL; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; @@ -50,6 +51,8 @@ public class TypesafeDriverConfig implements DriverConfig { private final Map defaultOverrides = new ConcurrentHashMap<>(); + private final TypesafeDriverExecutionProfile.Base defaultProfile; + public TypesafeDriverConfig(Config config) { this.lastLoadedConfig = config; Map profileConfigs = extractProfiles(config); @@ -62,6 +65,7 @@ public TypesafeDriverConfig(Config config) { new TypesafeDriverExecutionProfile.Base(entry.getKey(), entry.getValue())); } this.profiles = builder.build(); + this.defaultProfile = profiles.get(DriverExecutionProfile.DEFAULT_NAME); } /** @return whether the configuration changed */ @@ -136,14 +140,19 @@ private Map extractProfiles(Config sourceConfig) { return result.build(); } + @Override + public DriverExecutionProfile getDefaultProfile() { + return defaultProfile; + } + @NonNull @Override public DriverExecutionProfile getProfile(@NonNull String profileName) { - Preconditions.checkArgument( - profiles.containsKey(profileName), - "Unknown profile '%s'. Check your configuration.", - profileName); - return profiles.get(profileName); + if (profileName.equals(DriverExecutionProfile.DEFAULT_NAME)) { + return defaultProfile; + } + return Optional.ofNullable(profiles.get(profileName)) + .orElseThrow(() -> new IllegalArgumentException(String.format("Unknown profile '%s'. Check your configuration.", profileName))); } @NonNull diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java index 019d50ab2a0..b39479647e9 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java @@ -171,6 +171,14 @@ public void should_enumerate_options() { entry("int1", 45)); } + @Test + public void should_update_default_profile_on_reload() { + TypesafeDriverConfig config = parse("int1 = 42\n profiles { profile1 { int1 = 43 } }"); + assertThat(config.getDefaultProfile().getInt(MockOptions.INT1)).isEqualTo(42); + config.reload(ConfigFactory.parseString("int1 = 44\n profiles { profile1 { int1 = 45 } }")); + assertThat(config.getDefaultProfile().getInt(MockOptions.INT1)).isEqualTo(44); + } + private TypesafeDriverConfig parse(String configString) { Config config = ConfigFactory.parseString(configString); return new TypesafeDriverConfig(config); From a650ee43712cc0448ce6d263db30f15eb2f55c2c Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 17 Nov 2022 22:12:00 -0600 Subject: [PATCH 232/395] Formatting fix after recent TypeSafe config changes. Also fixed a logic bug in previous commit re: IdentifierIndex --- .../internal/core/config/typesafe/TypesafeDriverConfig.java | 6 ++++-- .../oss/driver/internal/core/data/IdentifierIndex.java | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java index ca5d919c604..c65e9035e0a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfig.java @@ -21,7 +21,6 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.config.DriverOption; import com.datastax.oss.driver.internal.core.util.Loggers; -import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.typesafe.config.Config; import com.typesafe.config.ConfigObject; @@ -152,7 +151,10 @@ public DriverExecutionProfile getProfile(@NonNull String profileName) { return defaultProfile; } return Optional.ofNullable(profiles.get(profileName)) - .orElseThrow(() -> new IllegalArgumentException(String.format("Unknown profile '%s'. Check your configuration.", profileName))); + .orElseThrow( + () -> + new IllegalArgumentException( + String.format("Unknown profile '%s'. Check your configuration.", profileName))); } @NonNull diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java index 6b1d8fbb3a6..868617e0c1e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java @@ -76,7 +76,7 @@ public List allIndicesOf(String name) { */ public int firstIndexOf(String name) { Iterator indices = allIndicesOf(name).iterator(); - return indices.hasNext() ? -1 : indices.next(); + return indices.hasNext() ? indices.next() : -1; } /** Returns all occurrences of a given identifier. */ @@ -87,6 +87,6 @@ public List allIndicesOf(CqlIdentifier id) { /** Returns the first occurrence of a given identifier, or -1 if it's not in the list. */ public int firstIndexOf(CqlIdentifier id) { Iterator indices = allIndicesOf(id).iterator(); - return indices.hasNext() ? -1 : indices.next(); + return indices.hasNext() ? indices.next() : -1; } } From f92384469f7d9be863dd88d34a8f7896497c72e0 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 12 Dec 2022 12:38:04 -0600 Subject: [PATCH 233/395] Trying to work around JENKINS-37984 --- Jenkinsfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0f9a28265d3..51e2400982f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -175,7 +175,9 @@ def describeAdhocAndScheduledTestingStage() { // branch pattern for cron // should match 3.x, 4.x, 4.5.x, etc -def branchPatternCron = ~"((\\d+(\\.[\\dx]+)+))" +def branchPatternCron() = { + ~"((\\d+(\\.[\\dx]+)+))" +} pipeline { agent none @@ -354,7 +356,7 @@ pipeline { triggers { // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) - parameterizedCron(branchPatternCron.matcher(env.BRANCH_NAME).matches() ? """ + parameterizedCron(branchPatternCron().matcher(env.BRANCH_NAME).matches() ? """ # Every weeknight (Monday - Friday) around 2:00 AM ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0 and DSE 6.7 H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7;CI_SCHEDULE_JABBA_VERSION=1.8 From d4a52aa2c91e2abd99ca5583b09ea6c01f4db5e6 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 12 Dec 2022 12:40:41 -0600 Subject: [PATCH 234/395] Hey, let's try not to mangle the Groovy --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 51e2400982f..c5e8ac69b7f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -175,7 +175,7 @@ def describeAdhocAndScheduledTestingStage() { // branch pattern for cron // should match 3.x, 4.x, 4.5.x, etc -def branchPatternCron() = { +def branchPatternCron() { ~"((\\d+(\\.[\\dx]+)+))" } From 8ce9497bdef9c5a6ff7e24187e042dfbff9844c2 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 15 Dec 2022 17:12:46 -0600 Subject: [PATCH 235/395] Removing submission of CI metrics temporarily after AWS conversion --- Jenkinsfile | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c5e8ac69b7f..bf90ebbacda 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -133,25 +133,6 @@ ${status} after ${currentBuild.durationString - ' and counting'}""" } } -def submitCIMetrics(buildType) { - long durationMs = currentBuild.duration - long durationSec = durationMs / 1000 - long nowSec = (currentBuild.startTimeInMillis + durationMs) / 1000 - def branchNameNoPeriods = env.BRANCH_NAME.replaceAll('\\.', '_') - def durationMetric = "okr.ci.java.${env.DRIVER_METRIC_TYPE}.${buildType}.${branchNameNoPeriods} ${durationSec} ${nowSec}" - - timeout(time: 1, unit: 'MINUTES') { - withCredentials([string(credentialsId: 'lab-grafana-address', variable: 'LAB_GRAFANA_ADDRESS'), - string(credentialsId: 'lab-grafana-port', variable: 'LAB_GRAFANA_PORT')]) { - withEnv(["DURATION_METRIC=${durationMetric}"]) { - sh label: 'Send runtime metrics to labgrafana', script: '''#!/bin/bash -le - echo "${DURATION_METRIC}" | nc -q 5 ${LAB_GRAFANA_ADDRESS} ${LAB_GRAFANA_PORT} - ''' - } - } - } -} - def describePerCommitStage() { script { currentBuild.displayName = "Per-Commit build" @@ -462,11 +443,6 @@ pipeline { } } post { - always { - node('master') { - submitCIMetrics('commit') - } - } aborted { notifySlack('aborted') } From 1b455ff5fc204edaff8897d2f1ea73b7e6e88574 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 5 Jan 2023 01:24:14 -0600 Subject: [PATCH 236/395] Forgot to copy over a few 3.x releases into the changelog in this branch --- changelog/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index a0ec32f7a8b..17025eb417b 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -617,7 +617,17 @@ changelog](https://docs.datastax.com/en/developer/java-driver-dse/latest/changel - [bug] JAVA-1499: Wait for load balancing policy at cluster initialization - [new feature] JAVA-1495: Add prepared statements +## 3.11.3 + +- [improvement] JAVA-3023: Upgrade Netty to 4.1.77, 3.x edition + +## 3.11.2 + +- [improvement] JAVA-3008: Upgrade Netty to 4.1.75, 3.x edition +- [improvement] JAVA-2984: Upgrade Jackson to resolve high-priority CVEs + ## 3.11.1 + - [bug] JAVA-2967: Support native transport peer information for DSE 6.8. - [bug] JAVA-2976: Support missing protocol v5 error codes CAS_WRITE_UNKNOWN, CDC_WRITE_FAILURE. From 355844408325df5045fc5b10d99737f24003042d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Fri, 24 Feb 2023 17:15:24 +0000 Subject: [PATCH 237/395] fix dse builds on 4.x (#1625) --- Jenkinsfile | 61 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index bf90ebbacda..67ed4fcd769 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -31,6 +31,21 @@ def initializeEnvironment() { . ${CCM_ENVIRONMENT_SHELL} ${SERVER_VERSION} ''' + if (env.SERVER_VERSION.split('-')[0] == 'dse') { + env.DSE_FIXED_VERSION = env.SERVER_VERSION.split('-')[1] + sh label: 'Update environment for DataStax Enterprise', script: '''#!/bin/bash -le + cat >> ${HOME}/environment.txt << ENVIRONMENT_EOF +CCM_CASSANDRA_VERSION=${DSE_FIXED_VERSION} # maintain for backwards compatibility +CCM_VERSION=${DSE_FIXED_VERSION} +CCM_SERVER_TYPE=dse +DSE_VERSION=${DSE_FIXED_VERSION} +CCM_IS_DSE=true +CCM_BRANCH=${DSE_FIXED_VERSION} +DSE_BRANCH=${DSE_FIXED_VERSION} +ENVIRONMENT_EOF + ''' + } + sh label: 'Display Java and environment information',script: '''#!/bin/bash -le # Load CCM environment variables set -o allexport @@ -198,12 +213,12 @@ pipeline { '3.0', // Previous Apache CassandraⓇ '3.11', // Current Apache CassandraⓇ '4.0', // Development Apache CassandraⓇ - 'dse-4.8', // Previous EOSL DataStax Enterprise - 'dse-5.0', // Long Term Support DataStax Enterprise - 'dse-5.1', // Legacy DataStax Enterprise - 'dse-6.0', // Previous DataStax Enterprise - 'dse-6.7', // Previous DataStax Enterprise - 'dse-6.8', // Current DataStax Enterprise + 'dse-4.8.16', // Previous EOSL DataStax Enterprise + 'dse-5.0.15', // Long Term Support DataStax Enterprise + 'dse-5.1.35', // Legacy DataStax Enterprise + 'dse-6.0.18', // Previous DataStax Enterprise + 'dse-6.7.17', // Previous DataStax Enterprise + 'dse-6.8.30', // Current DataStax Enterprise 'ALL'], description: '''Apache Cassandra® and DataStax Enterprise server version to use for adhoc BUILD-AND-EXECUTE-TESTS builds

    Driver versionTinkerPop version
    4.15.03.5.3
    4.14.13.5.3
    4.14.03.4.10
    4.13.03.4.10
    @@ -234,27 +249,27 @@ pipeline { - + - + - + - + - + - +
    Apache Cassandra® v4.x (CURRENTLY UNDER DEVELOPMENT)
    dse-4.8dse-4.8.16 DataStax Enterprise v4.8.x (END OF SERVICE LIFE)
    dse-5.0dse-5.0.15 DataStax Enterprise v5.0.x (Long Term Support)
    dse-5.1dse-5.1.35 DataStax Enterprise v5.1.x
    dse-6.0dse-6.0.18 DataStax Enterprise v6.0.x
    dse-6.7dse-6.7.17 DataStax Enterprise v6.7.x
    dse-6.8dse-6.8.30 DataStax Enterprise v6.8.x
    ''') @@ -339,13 +354,13 @@ pipeline { // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) parameterizedCron(branchPatternCron().matcher(env.BRANCH_NAME).matches() ? """ # Every weeknight (Monday - Friday) around 2:00 AM - ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, DSE-6.0 and DSE 6.7 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8 dse-5.0 dse-5.1 dse-6.0 dse-6.7;CI_SCHEDULE_JABBA_VERSION=1.8 + ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, dse-6.0.18 and DSE 6.7 + H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 ### JDK11 tests against 3.11, 4.0 and DSE 6.8 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 + H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 # Every weekend (Sunday) around 12:00 PM noon ### JDK14 tests against 3.11, 4.0 and DSE 6.8 - H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 + H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 """ : "") } @@ -381,7 +396,7 @@ pipeline { name 'SERVER_VERSION' values '3.11', // Latest stable Apache CassandraⓇ '4.0', // Development Apache CassandraⓇ - 'dse-6.8' // Current DataStax Enterprise + 'dse-6.8.30' // Current DataStax Enterprise } } @@ -489,12 +504,12 @@ pipeline { '3.0', // Previous Apache CassandraⓇ '3.11', // Current Apache CassandraⓇ '4.0', // Development Apache CassandraⓇ - 'dse-4.8', // Previous EOSL DataStax Enterprise - 'dse-5.0', // Last EOSL DataStax Enterprise - 'dse-5.1', // Legacy DataStax Enterprise - 'dse-6.0', // Previous DataStax Enterprise - 'dse-6.7', // Previous DataStax Enterprise - 'dse-6.8' // Current DataStax Enterprise + 'dse-4.8.16', // Previous EOSL DataStax Enterprise + 'dse-5.0.15', // Last EOSL DataStax Enterprise + 'dse-5.1.35', // Legacy DataStax Enterprise + 'dse-6.0.18', // Previous DataStax Enterprise + 'dse-6.7.17', // Previous DataStax Enterprise + 'dse-6.8.30' // Current DataStax Enterprise } } when { From 741df6f98a1aad172d7dce2a760fac6c280a208c Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 4 Apr 2023 13:48:27 -0500 Subject: [PATCH 238/395] JAVA-3042: Add support for ad-hoc Java 17 builds (#1629) --- Jenkinsfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 67ed4fcd769..1859ceb7689 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -281,7 +281,8 @@ pipeline { 'openjdk@1.11', // OpenJDK version 11 'openjdk@1.12', // OpenJDK version 12 'openjdk@1.13', // OpenJDK version 13 - 'openjdk@1.14'], // OpenJDK version 14 + 'openjdk@1.14', // OpenJDK version 14 + 'openjdk@1.17'], // OpenJDK version 17 description: '''JDK version to use for TESTING when running adhoc BUILD-AND-EXECUTE-TESTS builds. All builds will use JDK8 for building the driver @@ -318,6 +319,10 @@ pipeline { + + + +
    openjdk@1.14 OpenJDK version 14
    openjdk@1.17OpenJDK version 17
    ''') booleanParam( name: 'SKIP_SERIAL_ITS', From f91979f99dd7271c036a3dae8d35b71e59fe396d Mon Sep 17 00:00:00 2001 From: Emelia <105240296+emeliawilkinson24@users.noreply.github.com> Date: Tue, 9 May 2023 10:39:22 -0400 Subject: [PATCH 239/395] DOC-2813 (#1632) Added error handling guidance linking to a helpful blog post plus Jamie's addition. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0b5a61520f5..c9003f606f1 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ remain unchanged, and the new API will look very familiar to 2.x and 3.x users. See the [upgrade guide](upgrade_guide/) for details. +## Error Handling + +See the [Cassandra error handling done right blog](https://www.datastax.com/blog/cassandra-error-handling-done-right) for error handling with the DataStax Java Driver for Apache Cassandra™. + ## Useful links * [Manual](manual/) From cfeb55f8ba9c35bd3b19c9442b429a564b565440 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 5 Jun 2023 11:42:14 -0500 Subject: [PATCH 240/395] JAVA-3060: Add vector type, codec + support for parsing CQL type (#1639) --- .../oss/driver/api/core/data/CqlVector.java | 91 ++++++++++++ .../driver/api/core/data/GettableById.java | 18 +++ .../driver/api/core/data/GettableByIndex.java | 12 ++ .../driver/api/core/data/GettableByName.java | 18 +++ .../driver/api/core/data/SettableById.java | 21 +++ .../driver/api/core/data/SettableByIndex.java | 13 ++ .../driver/api/core/data/SettableByName.java | 21 +++ .../driver/api/core/type/CqlVectorType.java | 86 +++++++++++ .../oss/driver/api/core/type/DataTypes.java | 28 +++- .../api/core/type/codec/TypeCodecs.java | 9 ++ .../api/core/type/reflect/GenericType.java | 8 ++ .../schema/parsing/DataTypeCqlNameParser.java | 11 ++ .../core/type/codec/CqlVectorCodec.java | 135 ++++++++++++++++++ .../time/PersistentZonedTimestampCodec.java | 2 +- .../codec/registry/CachingCodecRegistry.java | 7 + .../core/type/codec/CqlVectorCodecTest.java | 115 +++++++++++++++ .../examples/datatypes/TuplesMapped.java | 4 +- 17 files changed, 593 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java new file mode 100644 index 00000000000..c34cc38a10a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java @@ -0,0 +1,91 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.data; + +import com.datastax.oss.driver.shaded.guava.common.base.Joiner; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import java.util.Arrays; + +/** An n-dimensional vector defined in CQL */ +public class CqlVector { + + private final ImmutableList values; + + private CqlVector(ImmutableList values) { + this.values = values; + } + + public static Builder builder() { + return new Builder(); + } + + public Iterable getValues() { + return values; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof CqlVector) { + CqlVector that = (CqlVector) o; + return this.values.equals(that.values); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Arrays.hashCode(values.toArray()); + } + + @Override + public String toString() { + + String contents = Joiner.on(", ").join(this.values); + return "CqlVector{" + contents + '}'; + } + + public static class Builder { + + private ImmutableList.Builder listBuilder; + + private Builder() { + listBuilder = new ImmutableList.Builder(); + } + + public Builder add(T element) { + listBuilder.add(element); + return this; + } + + public Builder add(T... elements) { + listBuilder.addAll(Iterators.forArray(elements)); + return this; + } + + public Builder addAll(Iterable iter) { + listBuilder.addAll(iter); + return this; + } + + public CqlVector build() { + return new CqlVector(listBuilder.build()); + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java index a6c46e4abe8..7d2ea3a7f8b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java @@ -515,6 +515,24 @@ default CqlDuration getCqlDuration(@NonNull CqlIdentifier id) { return getCqlDuration(firstIndexOf(id)); } + /** + * Returns the value for the first occurrence of {@code id} as a vector. + * + *

    By default, this works with CQL type {@code vector}. + * + *

    If an identifier appears multiple times, this can only be used to access the first value. + * For the other ones, use positional getters. + * + *

    If you want to avoid the overhead of building a {@code CqlIdentifier}, use the variant of + * this method that takes a string argument. + * + * @throws IllegalArgumentException if the id is invalid. + */ + @Nullable + default CqlVector getCqlVector(@NonNull CqlIdentifier id) { + return getCqlVector(firstIndexOf(id)); + } + /** * Returns the value for the first occurrence of {@code id} as a token. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java index 9e3502732c9..0da60bef285 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java @@ -436,6 +436,18 @@ default CqlDuration getCqlDuration(int i) { return get(i, CqlDuration.class); } + /** + * Returns the {@code i}th value as a vector. + * + *

    By default, this works with CQL type {@code vector}. + * + * @throws IndexOutOfBoundsException if the index is invalid. + */ + @Nullable + default CqlVector getCqlVector(int i) { + return get(i, CqlVector.class); + } + /** * Returns the {@code i}th value as a token. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java index abbb16aeb75..40e5532f85a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java @@ -511,6 +511,24 @@ default CqlDuration getCqlDuration(@NonNull String name) { return getCqlDuration(firstIndexOf(name)); } + /** + * Returns the value for the first occurrence of {@code name} as a vector. + * + *

    By default, this works with CQL type {@code vector}. + * + *

    If an identifier appears multiple times, this can only be used to access the first value. + * For the other ones, use positional getters. + * + *

    This method deals with case sensitivity in the way explained in the documentation of {@link + * AccessibleByName}. + * + * @throws IllegalArgumentException if the name is invalid. + */ + @Nullable + default CqlVector getCqlVector(@NonNull String name) { + return getCqlVector(firstIndexOf(name)); + } + /** * Returns the value for the first occurrence of {@code name} as a token. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java index 0d3cba5601d..58eb7098028 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java @@ -559,6 +559,27 @@ default SelfT setCqlDuration(@NonNull CqlIdentifier id, @Nullable CqlDuration v) return result; } + /** + * Sets the value for all occurrences of {@code id} to the provided duration. + * + *

    By default, this works with CQL type {@code vector}. + * + *

    If you want to avoid the overhead of building a {@code CqlIdentifier}, use the variant of + * this method that takes a string argument. + * + * @throws IllegalArgumentException if the id is invalid. + */ + @NonNull + @CheckReturnValue + default SelfT setCqlVector(@NonNull CqlIdentifier id, @Nullable CqlVector v) { + SelfT result = null; + for (Integer i : allIndicesOf(id)) { + result = (result == null ? this : result).setCqlVector(i, v); + } + assert result != null; // allIndices throws if there are no results + return result; + } + /** * Sets the value for all occurrences of {@code id} to the provided token. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java index 7cd0b5671ff..bdee1de7b6f 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java @@ -414,6 +414,19 @@ default SelfT setCqlDuration(int i, @Nullable CqlDuration v) { return set(i, v, CqlDuration.class); } + /** + * Sets the {@code i}th value to the provided duration. + * + *

    By default, this works with CQL type {@code vector}. + * + * @throws IndexOutOfBoundsException if the index is invalid. + */ + @NonNull + @CheckReturnValue + default SelfT setCqlVector(int i, @Nullable CqlVector v) { + return set(i, v, CqlVector.class); + } + /** * Sets the {@code i}th value to the provided token. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java index d93f4ebf5b2..26e5340bdce 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java @@ -558,6 +558,27 @@ default SelfT setCqlDuration(@NonNull String name, @Nullable CqlDuration v) { return result; } + /** + * Sets the value for all occurrences of {@code name} to the provided duration. + * + *

    By default, this works with CQL type {@code vector}. + * + *

    This method deals with case sensitivity in the way explained in the documentation of {@link + * AccessibleByName}. + * + * @throws IllegalArgumentException if the name is invalid. + */ + @NonNull + @CheckReturnValue + default SelfT setCqlVector(@NonNull String name, @Nullable CqlVector v) { + SelfT result = null; + for (Integer i : allIndicesOf(name)) { + result = (result == null ? this : result).setCqlVector(i, v); + } + assert result != null; // allIndices throws if there are no results + return result; + } + /** * Sets the value for all occurrences of {@code name} to the provided token. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java new file mode 100644 index 00000000000..528a688451a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java @@ -0,0 +1,86 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.type; + +import com.datastax.oss.driver.api.core.detach.AttachmentPoint; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Objects; + +public class CqlVectorType implements CustomType { + + public static final String CQLVECTOR_CLASS_NAME = "org.apache.cassandra.db.marshal.VectorType"; + + private final DataType subtype; + private final int dimensions; + + public CqlVectorType(DataType subtype, int dimensions) { + + this.dimensions = dimensions; + this.subtype = subtype; + } + + public int getDimensions() { + return this.dimensions; + } + + public DataType getSubtype() { + return this.subtype; + } + + @NonNull + @Override + public String getClassName() { + return CQLVECTOR_CLASS_NAME; + } + + @NonNull + @Override + public String asCql(boolean includeFrozen, boolean pretty) { + return String.format("'%s(%d)'", getClassName(), getDimensions()); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof CqlVectorType) { + CqlVectorType that = (CqlVectorType) o; + return that.subtype.equals(this.subtype) && that.dimensions == this.dimensions; + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), subtype, dimensions); + } + + @Override + public String toString() { + return String.format("CqlVector(%s, %d)", getSubtype(), getDimensions()); + } + + @Override + public boolean isDetached() { + return false; + } + + @Override + public void attach(@NonNull AttachmentPoint attachmentPoint) { + // nothing to do + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java index 0a61314ca71..f8cc7042516 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java @@ -15,17 +15,21 @@ */ package com.datastax.oss.driver.api.core.type; +import com.datastax.oss.driver.api.core.detach.AttachmentPoint; import com.datastax.oss.driver.api.core.detach.Detachable; +import com.datastax.oss.driver.internal.core.metadata.schema.parsing.DataTypeClassNameParser; import com.datastax.oss.driver.internal.core.type.DefaultCustomType; import com.datastax.oss.driver.internal.core.type.DefaultListType; import com.datastax.oss.driver.internal.core.type.DefaultMapType; import com.datastax.oss.driver.internal.core.type.DefaultSetType; import com.datastax.oss.driver.internal.core.type.DefaultTupleType; import com.datastax.oss.driver.internal.core.type.PrimitiveType; +import com.datastax.oss.driver.shaded.guava.common.base.Splitter; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.protocol.internal.ProtocolConstants; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; +import java.util.List; /** Constants and factory methods to obtain data type instances. */ public class DataTypes { @@ -51,14 +55,26 @@ public class DataTypes { public static final DataType TINYINT = new PrimitiveType(ProtocolConstants.DataType.TINYINT); public static final DataType DURATION = new PrimitiveType(ProtocolConstants.DataType.DURATION); + private static final DataTypeClassNameParser classNameParser = new DataTypeClassNameParser(); + private static final Splitter paramSplitter = Splitter.on(',').trimResults(); + @NonNull public static DataType custom(@NonNull String className) { + // In protocol v4, duration is implemented as a custom type - if ("org.apache.cassandra.db.marshal.DurationType".equals(className)) { - return DURATION; - } else { - return new DefaultCustomType(className); + if (className.equals("org.apache.cassandra.db.marshal.DurationType")) return DURATION; + + /* Vector support is currently implemented as a custom type but is also parameterized */ + if (className.startsWith(CqlVectorType.CQLVECTOR_CLASS_NAME)) { + List params = + paramSplitter.splitToList( + className.substring( + CqlVectorType.CQLVECTOR_CLASS_NAME.length() + 1, className.length() - 1)); + DataType subType = classNameParser.parse(params.get(0), AttachmentPoint.NONE); + int dimensions = Integer.parseInt(params.get(1)); + return new CqlVectorType(subType, dimensions); } + return new DefaultCustomType(className); } @NonNull @@ -118,4 +134,8 @@ public static MapType frozenMapOf(@NonNull DataType keyType, @NonNull DataType v public static TupleType tupleOf(@NonNull DataType... componentTypes) { return new DefaultTupleType(ImmutableList.copyOf(Arrays.asList(componentTypes))); } + + public static CqlVectorType vectorOf(DataType subtype, int dimensions) { + return new CqlVectorType(subtype, dimensions); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java index 6cd4b68a042..07fbf309988 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java @@ -16,8 +16,10 @@ package com.datastax.oss.driver.api.core.type.codec; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; +import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.CustomType; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; @@ -28,6 +30,7 @@ import com.datastax.oss.driver.internal.core.type.codec.BooleanCodec; import com.datastax.oss.driver.internal.core.type.codec.CounterCodec; import com.datastax.oss.driver.internal.core.type.codec.CqlDurationCodec; +import com.datastax.oss.driver.internal.core.type.codec.CqlVectorCodec; import com.datastax.oss.driver.internal.core.type.codec.CustomCodec; import com.datastax.oss.driver.internal.core.type.codec.DateCodec; import com.datastax.oss.driver.internal.core.type.codec.DecimalCodec; @@ -205,6 +208,12 @@ public static TypeCodec tupleOf(@NonNull TupleType cqlType) { return new TupleCodec(cqlType); } + public static TypeCodec> vectorOf( + @NonNull CqlVectorType type, @NonNull TypeCodec subtypeCodec) { + return new CqlVectorCodec( + DataTypes.vectorOf(subtypeCodec.getCqlType(), type.getDimensions()), subtypeCodec); + } + /** * Builds a new codec that maps a CQL user defined type to the driver's {@link UdtValue}, for the * given type definition. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java index a1977e39f23..db573b3451b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.api.core.type.reflect; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.GettableByIndex; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; @@ -165,6 +166,13 @@ public static GenericType> mapOf( return new GenericType<>(token); } + @NonNull + public static GenericType> vectorOf(@NonNull GenericType elementType) { + TypeToken> token = + new TypeToken>() {}.where(new TypeParameter() {}, elementType.token); + return new GenericType<>(token); + } + @NonNull public static GenericType arrayOf(@NonNull Class componentType) { TypeToken token = diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java index 3523aa5c459..76a2301522d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.metadata.schema.parsing; import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.UserDefinedType; @@ -137,6 +138,16 @@ private DataType parse( return new DefaultTupleType(componentTypesBuilder.build(), context); } + if (type.equalsIgnoreCase("vector")) { + if (parameters.size() != 2) { + throw new IllegalArgumentException( + String.format("Expecting two parameters for vector custom type, got %s", parameters)); + } + DataType subType = parse(parameters.get(0), keyspaceId, false, userTypes, context); + int dimensions = Integer.parseInt(parameters.get(1)); + return new CqlVectorType(subType, dimensions); + } + throw new IllegalArgumentException("Could not parse type name " + toParse); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java new file mode 100644 index 00000000000..4b739862d33 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java @@ -0,0 +1,135 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type.codec; + +import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.data.CqlVector; +import com.datastax.oss.driver.api.core.type.CqlVectorType; +import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.shaded.guava.common.base.Splitter; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; +import com.datastax.oss.driver.shaded.guava.common.collect.Streams; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.nio.ByteBuffer; +import java.util.Iterator; + +public class CqlVectorCodec implements TypeCodec> { + + private final CqlVectorType cqlType; + private final GenericType> javaType; + private final TypeCodec subtypeCodec; + + public CqlVectorCodec(CqlVectorType cqlType, TypeCodec subtypeCodec) { + this.cqlType = cqlType; + this.subtypeCodec = subtypeCodec; + this.javaType = GenericType.vectorOf(subtypeCodec.getJavaType()); + } + + @NonNull + @Override + public GenericType> getJavaType() { + return this.javaType; + } + + @NonNull + @Override + public DataType getCqlType() { + return this.cqlType; + } + + @Nullable + @Override + public ByteBuffer encode( + @Nullable CqlVector value, @NonNull ProtocolVersion protocolVersion) { + if (value == null || cqlType.getDimensions() <= 0) { + return null; + } + ByteBuffer[] valueBuffs = new ByteBuffer[cqlType.getDimensions()]; + Iterator values = value.getValues().iterator(); + int allValueBuffsSize = 0; + for (int i = 0; i < cqlType.getDimensions(); ++i) { + ByteBuffer valueBuff = this.subtypeCodec.encode(values.next(), protocolVersion); + allValueBuffsSize += valueBuff.limit(); + valueBuff.rewind(); + valueBuffs[i] = valueBuff; + } + /* Since we already did an early return for <= 0 dimensions above */ + assert valueBuffs.length > 0; + ByteBuffer rv = ByteBuffer.allocate(allValueBuffsSize); + for (int i = 0; i < cqlType.getDimensions(); ++i) { + rv.put(valueBuffs[i]); + } + rv.flip(); + return rv; + } + + @Nullable + @Override + public CqlVector decode( + @Nullable ByteBuffer bytes, @NonNull ProtocolVersion protocolVersion) { + if (bytes == null || bytes.remaining() == 0) { + return null; + } + + /* Determine element size by dividing count of remaining bytes by number of elements. This should have a remainder + of zero if we assume all elements are of uniform size (which is really a terrible assumption). + + TODO: We should probably tweak serialization format for vectors if we're going to allow them for arbitrary subtypes. + Elements should at least precede themselves with their size (along the lines of what lists do). */ + int elementSize = Math.floorDiv(bytes.remaining(), cqlType.getDimensions()); + if (!(bytes.remaining() % cqlType.getDimensions() == 0)) { + throw new IllegalArgumentException( + String.format( + "Expected elements of uniform size, observed %d elements with total bytes %d", + cqlType.getDimensions(), bytes.remaining())); + } + + ImmutableList.Builder builder = ImmutableList.builder(); + for (int i = 0; i < cqlType.getDimensions(); ++i) { + ByteBuffer slice = bytes.slice(); + slice.limit(elementSize); + builder.add(this.subtypeCodec.decode(slice, protocolVersion)); + bytes.position(bytes.position() + elementSize); + } + + /* Restore the input ByteBuffer to its original state */ + bytes.rewind(); + + return CqlVector.builder().addAll(builder.build()).build(); + } + + @NonNull + @Override + public String format(@Nullable CqlVector value) { + return value == null ? "NULL" : Iterables.toString(value.getValues()); + } + + @Nullable + @Override + public CqlVector parse(@Nullable String value) { + if (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL")) return null; + + ImmutableList values = + Streams.stream(Splitter.on(", ").split(value.substring(1, value.length() - 1))) + .map(subtypeCodec::parse) + .collect(ImmutableList.toImmutableList()); + return CqlVector.builder().addAll(values).build(); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/PersistentZonedTimestampCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/PersistentZonedTimestampCodec.java index 0cb1681d344..ac819d0044e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/PersistentZonedTimestampCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/PersistentZonedTimestampCodec.java @@ -98,7 +98,7 @@ protected TupleValue outerToInner(@Nullable ZonedDateTime value) { } else { Instant instant = value.toInstant(); String zoneId = value.getZone().toString(); - return getCqlType().newValue(instant, zoneId); + return this.getCqlType().newValue(instant, zoneId); } } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java index 35ea21f38c7..18b1f55e106 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java @@ -16,8 +16,10 @@ package com.datastax.oss.driver.internal.core.type.codec.registry; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; +import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.CustomType; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; @@ -602,6 +604,11 @@ protected TypeCodec createCodec( } else if (cqlType instanceof UserDefinedType && UdtValue.class.isAssignableFrom(token.getRawType())) { return TypeCodecs.udtOf((UserDefinedType) cqlType); + } else if (cqlType instanceof CqlVectorType + && CqlVector.class.isAssignableFrom(token.getRawType())) { + CqlVectorType vectorType = (CqlVectorType) cqlType; + TypeCodec subtypeCodec = codecFor(vectorType.getSubtype()); + return TypeCodecs.vectorOf((CqlVectorType) cqlType, subtypeCodec); } else if (cqlType instanceof CustomType && ByteBuffer.class.isAssignableFrom(token.getRawType())) { return TypeCodecs.custom(cqlType); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java new file mode 100644 index 00000000000..eac142f6ebe --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java @@ -0,0 +1,115 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type.codec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.datastax.oss.driver.api.core.data.CqlVector; +import com.datastax.oss.driver.api.core.type.CqlVectorType; +import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; +import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import org.junit.Test; + +public class CqlVectorCodecTest extends CodecTestBase> { + + private static final CqlVector VECTOR = CqlVector.builder().add(1.0f, 2.5f).build(); + + private static final String VECTOR_HEX_STRING = "0x" + "3f800000" + "40200000"; + + private static final String FORMATTED_VECTOR = "[1.0, 2.5]"; + + public CqlVectorCodecTest() { + CqlVectorType vectorType = DataTypes.vectorOf(DataTypes.FLOAT, 2); + this.codec = TypeCodecs.vectorOf(vectorType, TypeCodecs.FLOAT); + } + + @Test + public void should_encode() { + assertThat(encode(VECTOR)).isEqualTo(VECTOR_HEX_STRING); + assertThat(encode(null)).isNull(); + } + + @Test + public void should_decode() { + assertThat(decode(VECTOR_HEX_STRING)).isEqualTo(VECTOR); + assertThat(decode("0x")).isNull(); + assertThat(decode(null)).isNull(); + } + + @Test + public void decode_throws_if_too_few_bytes() { + // Dropping 4 bytes would knock off exactly 1 float, anything less than that would be something + // we couldn't parse a float out of + for (int i = 1; i <= 3; ++i) { + // 2 chars of hex encoded string = 1 byte + int lastIndex = VECTOR_HEX_STRING.length() - (2 * i); + assertThatThrownBy(() -> decode(VECTOR_HEX_STRING.substring(0, lastIndex))) + .isInstanceOf(IllegalArgumentException.class); + } + } + + @Test + public void should_format() { + assertThat(format(VECTOR)).isEqualTo(FORMATTED_VECTOR); + assertThat(format(null)).isEqualTo("NULL"); + } + + @Test + public void should_parse() { + assertThat(parse(FORMATTED_VECTOR)).isEqualTo(VECTOR); + assertThat(parse("NULL")).isNull(); + assertThat(parse("null")).isNull(); + assertThat(parse("")).isNull(); + assertThat(parse(null)).isNull(); + } + + @Test + public void should_accept_data_type() { + assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 2))).isTrue(); + assertThat(codec.accepts(DataTypes.INT)).isFalse(); + } + + @Test + public void should_accept_vector_type_correct_dimension_only() { + assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 0))).isFalse(); + assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 1))).isFalse(); + assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 2))).isTrue(); + for (int i = 3; i < 1000; ++i) { + assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, i))).isFalse(); + } + } + + @Test + public void should_accept_generic_type() { + assertThat(codec.accepts(GenericType.vectorOf(GenericType.FLOAT))).isTrue(); + assertThat(codec.accepts(GenericType.vectorOf(GenericType.INTEGER))).isFalse(); + assertThat(codec.accepts(GenericType.of(Integer.class))).isFalse(); + } + + @Test + public void should_accept_raw_type() { + assertThat(codec.accepts(CqlVector.class)).isTrue(); + assertThat(codec.accepts(Integer.class)).isFalse(); + } + + @Test + public void should_accept_object() { + assertThat(codec.accepts(VECTOR)).isTrue(); + assertThat(codec.accepts(Integer.MIN_VALUE)).isFalse(); + } +} diff --git a/examples/src/main/java/com/datastax/oss/driver/examples/datatypes/TuplesMapped.java b/examples/src/main/java/com/datastax/oss/driver/examples/datatypes/TuplesMapped.java index 817736df1cd..14afaaaee27 100644 --- a/examples/src/main/java/com/datastax/oss/driver/examples/datatypes/TuplesMapped.java +++ b/examples/src/main/java/com/datastax/oss/driver/examples/datatypes/TuplesMapped.java @@ -119,7 +119,9 @@ protected Coordinates innerToOuter(@Nullable TupleValue value) { @Nullable @Override protected TupleValue outerToInner(@Nullable Coordinates value) { - return value == null ? null : getCqlType().newValue().setInt(0, value.x).setInt(1, value.y); + return value == null + ? null + : this.getCqlType().newValue().setInt(0, value.x).setInt(1, value.y); } } From 52a919b85a40093aba7b13963fac8fa39407f7d4 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 5 Jun 2023 15:42:14 -0500 Subject: [PATCH 241/395] JAVA-3058: Clear prepared statement cache on UDT type change event (#1638) --- .../core/cql/CqlPrepareAsyncProcessor.java | 85 ++++++++++- .../session/BuiltInRequestProcessors.java | 9 +- ...BuiltInRequestProcessorsSubstitutions.java | 6 +- .../driver/core/cql/PreparedStatementIT.java | 142 ++++++++++++++++++ .../guava/internal/GuavaDriverContext.java | 4 +- 5 files changed, 237 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java index 4e0b51fe482..ff935aefb0a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java @@ -18,31 +18,112 @@ import com.datastax.oss.driver.api.core.cql.PrepareRequest; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.ListType; +import com.datastax.oss.driver.api.core.type.MapType; +import com.datastax.oss.driver.api.core.type.SetType; +import com.datastax.oss.driver.api.core.type.TupleType; +import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import com.datastax.oss.driver.internal.core.metadata.schema.events.TypeChangeEvent; import com.datastax.oss.driver.internal.core.session.DefaultSession; import com.datastax.oss.driver.internal.core.session.RequestProcessor; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; +import com.datastax.oss.driver.internal.core.util.concurrent.RunOrSchedule; import com.datastax.oss.driver.shaded.guava.common.cache.Cache; import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; +import com.datastax.oss.protocol.internal.ProtocolConstants; +import edu.umd.cs.findbugs.annotations.NonNull; +import io.netty.util.concurrent.EventExecutor; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutionException; import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @ThreadSafe public class CqlPrepareAsyncProcessor implements RequestProcessor> { + private static final Logger LOG = LoggerFactory.getLogger(CqlPrepareAsyncProcessor.class); + protected final Cache> cache; public CqlPrepareAsyncProcessor() { - this(CacheBuilder.newBuilder().weakValues().build()); + this(Optional.empty()); + } + + public CqlPrepareAsyncProcessor(@NonNull Optional context) { + this(CacheBuilder.newBuilder().weakValues().build(), context); } protected CqlPrepareAsyncProcessor( - Cache> cache) { + Cache> cache, + Optional context) { + this.cache = cache; + context.ifPresent( + (ctx) -> { + LOG.info("Adding handler to invalidate cached prepared statements on type changes"); + EventExecutor adminExecutor = ctx.getNettyOptions().adminEventExecutorGroup().next(); + ctx.getEventBus() + .register( + TypeChangeEvent.class, RunOrSchedule.on(adminExecutor, this::onTypeChanged)); + }); + } + + private static boolean typeMatches(UserDefinedType oldType, DataType typeToCheck) { + + switch (typeToCheck.getProtocolCode()) { + case ProtocolConstants.DataType.UDT: + UserDefinedType udtType = (UserDefinedType) typeToCheck; + return udtType.equals(oldType) + ? true + : Iterables.any(udtType.getFieldTypes(), (testType) -> typeMatches(oldType, testType)); + case ProtocolConstants.DataType.LIST: + ListType listType = (ListType) typeToCheck; + return typeMatches(oldType, listType.getElementType()); + case ProtocolConstants.DataType.SET: + SetType setType = (SetType) typeToCheck; + return typeMatches(oldType, setType.getElementType()); + case ProtocolConstants.DataType.MAP: + MapType mapType = (MapType) typeToCheck; + return typeMatches(oldType, mapType.getKeyType()) + || typeMatches(oldType, mapType.getValueType()); + case ProtocolConstants.DataType.TUPLE: + TupleType tupleType = (TupleType) typeToCheck; + return Iterables.any( + tupleType.getComponentTypes(), (testType) -> typeMatches(oldType, testType)); + default: + return false; + } + } + + private void onTypeChanged(TypeChangeEvent event) { + for (Map.Entry> entry : + this.cache.asMap().entrySet()) { + + try { + PreparedStatement stmt = entry.getValue().get(); + if (Iterables.any( + stmt.getResultSetDefinitions(), (def) -> typeMatches(event.oldType, def.getType())) + || Iterables.any( + stmt.getVariableDefinitions(), + (def) -> typeMatches(event.oldType, def.getType()))) { + + this.cache.invalidate(entry.getKey()); + this.cache.cleanUp(); + } + } catch (Exception e) { + LOG.info("Exception while invalidating prepared statement cache due to UDT change", e); + } + } } @Override diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java index e502714f1b2..c2f24d56e6d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessors.java @@ -34,6 +34,7 @@ import com.datastax.oss.driver.internal.core.util.DefaultDependencyChecker; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +44,7 @@ public class BuiltInRequestProcessors { public static List> createDefaultProcessors(DefaultDriverContext context) { List> processors = new ArrayList<>(); - addBasicProcessors(processors); + addBasicProcessors(processors, context); if (DefaultDependencyChecker.isPresent(TINKERPOP)) { addGraphProcessors(context, processors); } else { @@ -62,7 +63,8 @@ public class BuiltInRequestProcessors { return processors; } - public static void addBasicProcessors(List> processors) { + public static void addBasicProcessors( + List> processors, DefaultDriverContext context) { // regular requests (sync and async) CqlRequestAsyncProcessor cqlRequestAsyncProcessor = new CqlRequestAsyncProcessor(); CqlRequestSyncProcessor cqlRequestSyncProcessor = @@ -71,7 +73,8 @@ public static void addBasicProcessors(List> processors) { processors.add(cqlRequestSyncProcessor); // prepare requests (sync and async) - CqlPrepareAsyncProcessor cqlPrepareAsyncProcessor = new CqlPrepareAsyncProcessor(); + CqlPrepareAsyncProcessor cqlPrepareAsyncProcessor = + new CqlPrepareAsyncProcessor(Optional.of(context)); CqlPrepareSyncProcessor cqlPrepareSyncProcessor = new CqlPrepareSyncProcessor(cqlPrepareAsyncProcessor); processors.add(cqlPrepareAsyncProcessor); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java index 4485caed33d..868ab35b177 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/BuiltInRequestProcessorsSubstitutions.java @@ -36,7 +36,7 @@ public static final class BuiltInRequestProcessorsGraphMissingReactiveMissing { public static List> createDefaultProcessors( DefaultDriverContext context) { List> processors = new ArrayList<>(); - BuiltInRequestProcessors.addBasicProcessors(processors); + BuiltInRequestProcessors.addBasicProcessors(processors, context); return processors; } } @@ -48,7 +48,7 @@ public static final class BuiltInRequestProcessorsGraphMissingReactivePresent { public static List> createDefaultProcessors( DefaultDriverContext context) { List> processors = new ArrayList<>(); - BuiltInRequestProcessors.addBasicProcessors(processors); + BuiltInRequestProcessors.addBasicProcessors(processors, context); BuiltInRequestProcessors.addReactiveProcessors(processors); return processors; } @@ -61,7 +61,7 @@ public static final class BuiltInRequestProcessorsGraphPresentReactiveMissing { public static List> createDefaultProcessors( DefaultDriverContext context) { List> processors = new ArrayList<>(); - BuiltInRequestProcessors.addBasicProcessors(processors); + BuiltInRequestProcessors.addBasicProcessors(processors, context); BuiltInRequestProcessors.addGraphProcessors(context, processors); return processors; } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index 1b07edb53af..fe2df250a79 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -39,14 +39,20 @@ import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.metadata.schema.events.TypeChangeEvent; import com.datastax.oss.driver.internal.core.metadata.token.DefaultTokenMap; import com.datastax.oss.driver.internal.core.metadata.token.TokenFactory; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import com.datastax.oss.protocol.internal.util.Bytes; import com.google.common.collect.ImmutableList; import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.CompletionStage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import junit.framework.TestCase; import org.junit.Before; import org.junit.Rule; @@ -444,6 +450,142 @@ public void should_fail_fast_if_id_changes_on_reprepare() { } } + private void invalidationResultSetTest(Consumer createFn) { + + try (CqlSession session = sessionWithCacheSizeMetric()) { + + assertThat(getPreparedCacheSize(session)).isEqualTo(0); + createFn.accept(session); + + session.prepare("select f from test_table_1 where e = ?"); + session.prepare("select h from test_table_2 where g = ?"); + assertThat(getPreparedCacheSize(session)).isEqualTo(2); + + CountDownLatch latch = new CountDownLatch(1); + DefaultDriverContext ctx = (DefaultDriverContext) session.getContext(); + ctx.getEventBus() + .register( + TypeChangeEvent.class, + (e) -> { + assertThat(e.oldType.getName().toString()).isEqualTo("test_type_2"); + latch.countDown(); + }); + + session.execute("ALTER TYPE test_type_2 add i blob"); + Uninterruptibles.awaitUninterruptibly(latch, 2, TimeUnit.SECONDS); + + assertThat(getPreparedCacheSize(session)).isEqualTo(1); + } + } + + private void invalidationVariableDefsTest(Consumer createFn, boolean isCollection) { + + try (CqlSession session = sessionWithCacheSizeMetric()) { + + assertThat(getPreparedCacheSize(session)).isEqualTo(0); + createFn.accept(session); + + String fStr = isCollection ? "f contains ?" : "f = ?"; + session.prepare(String.format("select e from test_table_1 where %s allow filtering", fStr)); + String hStr = isCollection ? "h contains ?" : "h = ?"; + session.prepare(String.format("select g from test_table_2 where %s allow filtering", hStr)); + assertThat(getPreparedCacheSize(session)).isEqualTo(2); + + CountDownLatch latch = new CountDownLatch(1); + DefaultDriverContext ctx = (DefaultDriverContext) session.getContext(); + ctx.getEventBus() + .register( + TypeChangeEvent.class, + (e) -> { + assertThat(e.oldType.getName().toString()).isEqualTo("test_type_2"); + latch.countDown(); + }); + + session.execute("ALTER TYPE test_type_2 add i blob"); + Uninterruptibles.awaitUninterruptibly(latch, 2, TimeUnit.SECONDS); + + assertThat(getPreparedCacheSize(session)).isEqualTo(1); + } + } + + Consumer setupCacheEntryTestBasic = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); + session.execute("CREATE TABLE test_table_2 (g int primary key, h frozen)"); + }; + + @Test + public void should_invalidate_cache_entry_on_basic_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestBasic); + } + + @Test + public void should_invalidate_cache_entry_on_basic_udt_change_variable_defs() { + invalidationVariableDefsTest(setupCacheEntryTestBasic, false); + } + + Consumer setupCacheEntryTestCollection = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute( + "CREATE TABLE test_table_1 (e int primary key, f list>)"); + session.execute( + "CREATE TABLE test_table_2 (g int primary key, h list>)"); + }; + + @Test + public void should_invalidate_cache_entry_on_collection_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestCollection); + } + + @Test + public void should_invalidate_cache_entry_on_collection_udt_change_variable_defs() { + invalidationVariableDefsTest(setupCacheEntryTestCollection, true); + } + + Consumer setupCacheEntryTestTuple = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute( + "CREATE TABLE test_table_1 (e int primary key, f tuple)"); + session.execute( + "CREATE TABLE test_table_2 (g int primary key, h tuple)"); + }; + + @Test + public void should_invalidate_cache_entry_on_tuple_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestTuple); + } + + @Test + public void should_invalidate_cache_entry_on_tuple_udt_change_variable_defs() { + invalidationVariableDefsTest(setupCacheEntryTestTuple, false); + } + + Consumer setupCacheEntryTestNested = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute("CREATE TYPE test_type_3 (e frozen, f int)"); + session.execute("CREATE TYPE test_type_4 (g int, h frozen)"); + session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); + session.execute("CREATE TABLE test_table_2 (g int primary key, h frozen)"); + }; + + @Test + public void should_invalidate_cache_entry_on_nested_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestNested); + } + + @Test + public void should_invalidate_cache_entry_on_nested_udt_change_variable_defs() { + invalidationVariableDefsTest(setupCacheEntryTestNested, false); + } + @Test public void should_infer_routing_information_when_partition_key_is_bound() { should_infer_routing_information_when_partition_key_is_bound( diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java b/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java index 5a8b44be739..7eaa90eefed 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/example/guava/internal/GuavaDriverContext.java @@ -26,6 +26,7 @@ import com.datastax.oss.driver.internal.core.cql.CqlRequestAsyncProcessor; import com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor; import com.datastax.oss.driver.internal.core.session.RequestProcessorRegistry; +import java.util.Optional; /** * A Custom {@link DefaultDriverContext} that overrides {@link #getRequestProcessorRegistry()} to @@ -44,7 +45,8 @@ public RequestProcessorRegistry buildRequestProcessorRegistry() { // use GuavaRequestAsyncProcessor to return ListenableFutures in async methods. CqlRequestAsyncProcessor cqlRequestAsyncProcessor = new CqlRequestAsyncProcessor(); - CqlPrepareAsyncProcessor cqlPrepareAsyncProcessor = new CqlPrepareAsyncProcessor(); + CqlPrepareAsyncProcessor cqlPrepareAsyncProcessor = + new CqlPrepareAsyncProcessor(Optional.of(this)); CqlRequestSyncProcessor cqlRequestSyncProcessor = new CqlRequestSyncProcessor(cqlRequestAsyncProcessor); From 985d498d51d10adcb741cb692a156a0e6457bb54 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 5 Jun 2023 16:00:15 -0500 Subject: [PATCH 242/395] Docs + changelog updates, 4.16.0 version --- README.md | 2 +- changelog/README.md | 7 +++++++ manual/core/bom/README.md | 4 ++-- manual/core/integration/README.md | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c9003f606f1..739baedced3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.15.0](https://github.com/datastax/java-driver/tree/4.15.0).* +[4.16.0](https://github.com/datastax/java-driver/tree/4.16.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol diff --git a/changelog/README.md b/changelog/README.md index 17025eb417b..30bb1194674 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,13 @@ +### 4.16.0 + +- [improvement] JAVA-3058: Clear prepared statement cache on UDT type change event +- [improvement] JAVA-3060: Add vector type, codec + support for parsing CQL type +- [improvement] DOC-2813: Add error handling guidance linking to a helpful blog post +- [improvement] JAVA-3045: Fix GraalVM native image support for GraalVM 22.2 + ### 4.15.0 - [improvement] JAVA-3041: Update Guava session sample code to use ProgrammaticArguments diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index dc8f12eb599..935489beb7e 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.15.0 + 4.16.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.15.0 + 4.16.0 diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 3f42b1dabfe..02d0d97027b 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -562,6 +562,7 @@ Here are the recommended TinkerPop versions for each driver version: + From 1d87ffe4abde2b3e87f7a92ad4a5b06f226af1cc Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 5 Jun 2023 16:08:54 -0500 Subject: [PATCH 243/395] [maven-release-plugin] prepare release 4.16.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 837fcde0f89..c4362554165 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-core-shaded - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-mapper-processor - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-mapper-runtime - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-query-builder - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-test-infra - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-metrics-micrometer - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss java-driver-metrics-microprofile - 4.15.1-SNAPSHOT + 4.16.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 0cf5700b493..ebe689d0781 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 288b0df925a..7f0fc893a53 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 7a077be1553..389301e9f28 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 21417669a5f..6e70b274528 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.15.1-SNAPSHOT + 4.16.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 17e4ff393ef..a62d52cbd78 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 81c1a78c95a..7c838bf0c06 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 70121a8b9ad..42b64edbd63 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index f1536f493d1..2b6b4eab14c 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index b16f8b17c41..5bab7401cc3 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 1e78ce04975..3e9e9134d35 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 2ac1715fee9..b8c7e75369c 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.16.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 96559c8588e..d7967d3dbac 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 873de05d8c4..5a0113cd9af 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.15.1-SNAPSHOT + 4.16.0 java-driver-test-infra bundle From 5d3968b40cea5874fff500849c44b018f36e23d6 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 5 Jun 2023 16:08:57 -0500 Subject: [PATCH 244/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index c4362554165..79ea3485cda 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.16.0 + 4.16.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index ebe689d0781..fc89c2e7338 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 7f0fc893a53..d78ff6a3f02 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 389301e9f28..bd7d0c811ef 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 6e70b274528..85db139e7f4 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.16.0 + 4.16.1-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index a62d52cbd78..112ac7e73bc 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 7c838bf0c06..60d66d06584 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 42b64edbd63..2e5f74f83b7 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 2b6b4eab14c..ef4662d38ca 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 5bab7401cc3..c038a1567c5 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 3e9e9134d35..c1aebc6718b 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index b8c7e75369c..dbfc01b886e 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -955,7 +955,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.16.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index d7967d3dbac..41395bda871 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 5a0113cd9af..4c67bc35a1b 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.0 + 4.16.1-SNAPSHOT java-driver-test-infra bundle From a3a8a4fbefc842f785bfc2942e54229ac942f834 Mon Sep 17 00:00:00 2001 From: Chris Lin <99268912+chrislin22@users.noreply.github.com> Date: Thu, 22 Jun 2023 03:46:51 -0400 Subject: [PATCH 245/395] added Snyk monitor and snyk clean up after PR closed/merged (#1646) * added snyk monitor and clean up * used jdk 11 and add options * Update snyk-cli-scan.yml added explicit mvn package prepare for snyk * Update snyk-cli-scan.yml * use jdk 8 * added .snyk.ignore.example and .snyk * triggered by branch 4.x * address a few high CVEs identified by snyk scan * ignore graal-sdk CVE for now until we can move off java8 * clean up snyk yaml files * JAVA-3050: Upgrade Netty 4.1.94 to address recent CVEs osgi-tests/BundleOptions.java - since netty-4.1.78, netty-handler additionally depends on netty-transport-native-unix-common so we need to pull that in when configuring pax exam --------- Co-authored-by: weideng1 Co-authored-by: Henry Hughes --- .github/workflows/snyk-cli-scan.yml | 47 +++++++++++++++++++ .github/workflows/snyk-pr-cleanup.yml | 16 +++++++ .snyk | 19 ++++++++ .snyk.ignore.example | 9 ++++ .../internal/osgi/support/BundleOptions.java | 1 + pom.xml | 10 ++-- 6 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/snyk-cli-scan.yml create mode 100644 .github/workflows/snyk-pr-cleanup.yml create mode 100644 .snyk create mode 100644 .snyk.ignore.example diff --git a/.github/workflows/snyk-cli-scan.yml b/.github/workflows/snyk-cli-scan.yml new file mode 100644 index 00000000000..50d303a128b --- /dev/null +++ b/.github/workflows/snyk-cli-scan.yml @@ -0,0 +1,47 @@ +name: 🔬 Snyk cli SCA + +on: + push: + branches: [ 4.x ] + pull_request: + branches: [ 4.x ] + workflow_dispatch: + +env: + SNYK_SEVERITY_THRESHOLD_LEVEL: high + +jobs: + snyk-cli-scan: + runs-on: ubuntu-latest + steps: + - name: Git checkout + uses: actions/checkout@v3 + + - name: prepare for snyk scan + uses: datastax/shared-github-actions/actions/snyk-prepare@main + + - name: Set up JDK 8 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '8' + cache: maven + + - name: run maven install prepare for snyk + run: | + mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true + + - name: snyk scan java + uses: datastax/shared-github-actions/actions/snyk-scan-java@main + with: + directories: . + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + SNYK_ORG_ID: ${{ secrets.SNYK_ORG_ID }} + extra-snyk-options: "-DskipTests -Dmaven.javadoc.skip=true" + + - name: Snyk scan result + uses: datastax/shared-github-actions/actions/snyk-process-scan-results@main + with: + gh_repo_token: ${{ secrets.GITHUB_TOKEN }} + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + SNYK_ORG_ID: ${{ secrets.SNYK_ORG_ID }} diff --git a/.github/workflows/snyk-pr-cleanup.yml b/.github/workflows/snyk-pr-cleanup.yml new file mode 100644 index 00000000000..7cf018a59fc --- /dev/null +++ b/.github/workflows/snyk-pr-cleanup.yml @@ -0,0 +1,16 @@ +name: 🗑️ Snyk PR cleanup - merged/closed + +on: + pull_request: + types: + - closed + branches: + - snyk-monitor + workflow_dispatch: + +jobs: + snyk_project_cleanup_when_pr_closed: + uses: datastax/shared-github-actions/.github/workflows/snyk-pr-cleanup.yml@main + secrets: + snyk_token: ${{ secrets.SNYK_TOKEN }} + snyk_org_id: ${{ secrets.SNYK_ORG_ID }} diff --git a/.snyk b/.snyk new file mode 100644 index 00000000000..3c6284addca --- /dev/null +++ b/.snyk @@ -0,0 +1,19 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.22.2 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-JAVA-ORGGRAALVMSDK-2767964: + - '*': + reason: cannot upgrade to graal-sdk 22.1.0+ until we move off Java8, which is slated for later this year + expires: 2024-01-10T00:00:00.000Z + created: 2023-06-21T00:00:00.000Z + SNYK-JAVA-ORGGRAALVMSDK-2769618: + - '*': + reason: cannot upgrade to graal-sdk 22.1.0+ until we move off Java8, which is slated for later this year + expires: 2024-01-10T00:00:00.000Z + created: 2023-06-21T00:00:00.000Z + SNYK-JAVA-ORGGRAALVMSDK-5457933: + - '*': + reason: cannot upgrade to graal-sdk 22.1.0+ until we move off Java8, which is slated for later this year + expires: 2024-01-10T00:00:00.000Z + created: 2023-06-21T00:00:00.000Z diff --git a/.snyk.ignore.example b/.snyk.ignore.example new file mode 100644 index 00000000000..a4690b27223 --- /dev/null +++ b/.snyk.ignore.example @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.22.2 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-PYTHON-URLLIB3-1533435: + - '*': + reason: state your ignore reason here + expires: 2030-01-01T00:00:00.000Z + created: 2022-03-21T00:00:00.000Z \ No newline at end of file diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java index c4416768b4a..b7dac833f3d 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java @@ -91,6 +91,7 @@ public static CompositeOption nettyBundles() { mavenBundle("io.netty", "netty-codec").versionAsInProject(), mavenBundle("io.netty", "netty-common").versionAsInProject(), mavenBundle("io.netty", "netty-transport").versionAsInProject(), + mavenBundle("io.netty", "netty-transport-native-unix-common").versionAsInProject(), mavenBundle("io.netty", "netty-resolver").versionAsInProject()); } diff --git a/pom.xml b/pom.xml index dbfc01b886e..b56f22d6454 100644 --- a/pom.xml +++ b/pom.xml @@ -47,21 +47,21 @@ 1.4.1 2.1.12 4.1.18 - 4.1.77.Final + 4.1.94.Final 1.2.1 - 3.5.3 + 3.5.6 1.7.26 1.0.3 - 20210307 + 20230227 2.13.2 2.13.2.2 1.9.12 - 1.1.7.3 + 1.1.10.1 1.7.1 3.19.0 @@ -73,7 +73,7 @@ 4.13.4 0.11.0 1.1.4 - 2.28 + 2.31 2.5.0 2.1.1 1.1.4 From fba2cf6e91c7c7a666c217df070493b83d201990 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Thu, 22 Jun 2023 11:43:16 -0700 Subject: [PATCH 246/395] JAVA-3071: OsgiGraphIT.test_graph fails with dse-6.8.30 Test fails because tinkerpop classes cannot be loaded which gates enabling GraphRequest* processors Add missing dependencies required by TinkerIoRegistryV3d0 to the osgi testing bundle - com.sun.mail:mailapi:1.6.4 - org.apache.commons:commons-text:1.8 - org.apache.commons:commons-configuration2:2.7 --- .../oss/driver/internal/osgi/support/BundleOptions.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java index b7dac833f3d..6e7d82787f4 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java @@ -152,7 +152,9 @@ public static CompositeOption tinkerpopBundles() { .overwriteManifest(WrappedUrlProvisionOption.OverwriteMode.FULL), // Note: the versions below are hard-coded because they shouldn't change very often, // but if the tests fail because of them, we should consider parameterizing them - mavenBundle("commons-configuration", "commons-configuration", "1.10"), + mavenBundle("com.sun.mail", "mailapi", "1.6.4"), + mavenBundle("org.apache.commons", "commons-text", "1.8"), + mavenBundle("org.apache.commons", "commons-configuration2", "2.7"), CoreOptions.wrappedBundle(mavenBundle("commons-logging", "commons-logging", "1.1.1")) .exports("org.apache.commons.logging.*") .bundleVersion("1.1.1") From 9c44c72450b6d62a8363426c7a13d61b83746a0d Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Thu, 15 Jun 2023 19:01:44 -0700 Subject: [PATCH 247/395] JAVA-3065: PreparedStatementIT#should_fail_fast_if_id_changes_on_reprepare fails with recent C*/DSE versions PreparedStatementIT.java - add multiple backend requirements to should_fail_fast_if_id_changes_on_reprepare covering versions impacted by CASSANDRA-15252 - add handle_id_changes_on_reprepare to test CASSANDRA-15252 for versions which include the fix BackendRequirement.java - new repeatable annotation for specifying multiple ranges of backend requirements for tests VersionRequirementTest.java - tests for multiple ranges of backend requirements refactor BaseCcmRule.java annotation logic and move to VersionRequirements.java remove duplicated annotation code from CcmPaxExam.java and EmbeddedAdsRule --- .../driver/api/core/auth/EmbeddedAdsRule.java | 59 ++---- .../driver/core/cql/PreparedStatementIT.java | 47 ++++- .../internal/osgi/support/CcmPaxExam.java | 84 ++------ .../driver/api/testinfra/ccm/BaseCcmRule.java | 87 ++------- .../requirement/BackendRequirement.java | 36 ++++ .../requirement/BackendRequirements.java | 25 +++ .../testinfra/requirement/BackendType.java | 32 +++ .../requirement/VersionRequirement.java | 166 ++++++++++++++++ .../requirement/VersionRequirementTest.java | 184 ++++++++++++++++++ 9 files changed, 534 insertions(+), 186 deletions(-) create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirement.java create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirements.java create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java create mode 100644 test-infra/src/test/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirementTest.java diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java index cbec842a2cf..0903eb9b298 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java @@ -20,12 +20,14 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; +import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.io.File; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.junit.AssumptionViolatedException; @@ -151,50 +153,25 @@ protected void before() { } } - private Statement buildErrorStatement( - Version requirement, Version actual, String description, boolean lessThan) { - return new Statement() { - - @Override - public void evaluate() { - throw new AssumptionViolatedException( - String.format( - "Test requires %s %s %s but %s is configured. Description: %s", - lessThan ? "less than" : "at least", "DSE", requirement, actual, description)); - } - }; - } - @Override public Statement apply(Statement base, Description description) { - DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class); - if (dseRequirement != null) { - if (!CcmBridge.DSE_ENABLEMENT) { - return new Statement() { - @Override - public void evaluate() { - throw new AssumptionViolatedException("Test Requires DSE but C* is configured."); - } - }; - } else { - Version dseVersion = CcmBridge.VERSION; - if (!dseRequirement.min().isEmpty()) { - Version minVersion = Version.parse(dseRequirement.min()); - if (minVersion.compareTo(dseVersion) > 0) { - return buildErrorStatement(dseVersion, dseVersion, dseRequirement.description(), false); - } + BackendType backend = CcmBridge.DSE_ENABLEMENT ? BackendType.DSE : BackendType.CASSANDRA; + Version version = CcmBridge.VERSION; + + Collection requirements = VersionRequirement.fromAnnotations(description); + + if (VersionRequirement.meetsAny(requirements, backend, version)) { + return super.apply(base, description); + } else { + // requirements not met, throw reasoning assumption to skip test + return new Statement() { + @Override + public void evaluate() { + throw new AssumptionViolatedException( + VersionRequirement.buildReasonString(requirements, backend, version)); } - - if (!dseRequirement.max().isEmpty()) { - Version maxVersion = Version.parse(dseRequirement.max()); - - if (maxVersion.compareTo(dseVersion) <= 0) { - return buildErrorStatement(dseVersion, dseVersion, dseRequirement.description(), true); - } - } - } + }; } - return super.apply(base, description); } @Override diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index fe2df250a79..c3494a6ee96 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -16,7 +16,7 @@ package com.datastax.oss.driver.core.cql; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.catchThrowable; import com.codahale.metrics.Gauge; @@ -36,6 +36,8 @@ import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -54,6 +56,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import junit.framework.TestCase; +import org.assertj.core.api.AbstractThrowableAssert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -425,13 +428,11 @@ public void should_create_separate_instances_for_different_statement_parameters( } /** - * This test relies on CASSANDRA-15252 to reproduce the error condition. If the bug gets fixed in - * Cassandra, we'll need to add a version restriction. + * This method reproduces CASSANDRA-15252 which is fixed in 3.0.26/3.11.12/4.0.2. * * @see CASSANDRA-15252 */ - @Test - public void should_fail_fast_if_id_changes_on_reprepare() { + private AbstractThrowableAssert assertableReprepareAfterIdChange() { try (CqlSession session = SessionUtils.newSession(ccmRule)) { PreparedStatement preparedStatement = session.prepare( @@ -444,12 +445,42 @@ public void should_fail_fast_if_id_changes_on_reprepare() { executeDdl("DROP TABLE prepared_statement_test"); executeDdl("CREATE TABLE prepared_statement_test (a int PRIMARY KEY, b int, c int)"); - assertThatThrownBy(() -> session.execute(preparedStatement.bind(1))) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("ID mismatch while trying to reprepare"); + return assertThatCode(() -> session.execute(preparedStatement.bind(1))); } } + // Add version bounds to the DSE requirement if there is a version containing fix for + // CASSANDRA-15252 + @BackendRequirement( + type = BackendType.DSE, + description = "No DSE version contains fix for CASSANDRA-15252") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "3.0.0", maxExclusive = "3.0.26") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.11.0", + maxExclusive = "3.11.12") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0.0", maxExclusive = "4.0.2") + @Test + public void should_fail_fast_if_id_changes_on_reprepare() { + assertableReprepareAfterIdChange() + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("ID mismatch while trying to reprepare"); + } + + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.0.26", + maxExclusive = "3.11.0") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.11.12", + maxExclusive = "4.0.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0.2") + @Test + public void handle_id_changes_on_reprepare() { + assertableReprepareAfterIdChange().doesNotThrowAnyException(); + } + private void invalidationResultSetTest(Consumer createFn) { try (CqlSession session = sessionWithCacheSizeMetric()) { diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java index 8697a0d790d..4a1700639b4 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java @@ -18,10 +18,9 @@ import static com.datastax.oss.driver.internal.osgi.support.CcmStagedReactor.CCM_BRIDGE; import com.datastax.oss.driver.api.core.Version; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; -import com.datastax.oss.driver.api.testinfra.DseRequirement; -import java.util.Objects; -import java.util.Optional; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; +import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement; +import java.util.Collection; import org.junit.AssumptionViolatedException; import org.junit.runner.Description; import org.junit.runner.notification.Failure; @@ -38,69 +37,20 @@ public CcmPaxExam(Class klass) throws InitializationError { @Override public void run(RunNotifier notifier) { Description description = getDescription(); - CassandraRequirement cassandraRequirement = - description.getAnnotation(CassandraRequirement.class); - if (cassandraRequirement != null) { - if (!cassandraRequirement.min().isEmpty()) { - Version minVersion = Objects.requireNonNull(Version.parse(cassandraRequirement.min())); - if (minVersion.compareTo(CCM_BRIDGE.getCassandraVersion()) > 0) { - fireRequirementsNotMet(notifier, description, cassandraRequirement.min(), false, false); - return; - } - } - if (!cassandraRequirement.max().isEmpty()) { - Version maxVersion = Objects.requireNonNull(Version.parse(cassandraRequirement.max())); - if (maxVersion.compareTo(CCM_BRIDGE.getCassandraVersion()) <= 0) { - fireRequirementsNotMet(notifier, description, cassandraRequirement.max(), true, false); - return; - } - } - } - DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class); - if (dseRequirement != null) { - Optional dseVersionOption = CCM_BRIDGE.getDseVersion(); - if (!dseVersionOption.isPresent()) { - notifier.fireTestAssumptionFailed( - new Failure( - description, - new AssumptionViolatedException("Test Requires DSE but C* is configured."))); - return; - } else { - Version dseVersion = dseVersionOption.get(); - if (!dseRequirement.min().isEmpty()) { - Version minVersion = Objects.requireNonNull(Version.parse(dseRequirement.min())); - if (minVersion.compareTo(dseVersion) > 0) { - fireRequirementsNotMet(notifier, description, dseRequirement.min(), false, true); - return; - } - } - if (!dseRequirement.max().isEmpty()) { - Version maxVersion = Objects.requireNonNull(Version.parse(dseRequirement.max())); - if (maxVersion.compareTo(dseVersion) <= 0) { - fireRequirementsNotMet(notifier, description, dseRequirement.min(), true, true); - return; - } - } - } - } - super.run(notifier); - } + BackendType backend = + CCM_BRIDGE.getDseVersion().isPresent() ? BackendType.DSE : BackendType.CASSANDRA; + Version version = CCM_BRIDGE.getDseVersion().orElseGet(CCM_BRIDGE::getCassandraVersion); - private void fireRequirementsNotMet( - RunNotifier notifier, - Description description, - String requirement, - boolean lessThan, - boolean dse) { - AssumptionViolatedException e = - new AssumptionViolatedException( - String.format( - "Test requires %s %s %s but %s is configured. Description: %s", - lessThan ? "less than" : "at least", - dse ? "DSE" : "C*", - requirement, - dse ? CCM_BRIDGE.getDseVersion().orElse(null) : CCM_BRIDGE.getCassandraVersion(), - description)); - notifier.fireTestAssumptionFailed(new Failure(description, e)); + Collection requirements = + VersionRequirement.fromAnnotations(getDescription()); + if (VersionRequirement.meetsAny(requirements, backend, version)) { + super.run(notifier); + } else { + // requirements not met, throw reasoning assumption to skip test + AssumptionViolatedException e = + new AssumptionViolatedException( + VersionRequirement.buildReasonString(requirements, backend, version)); + notifier.fireTestAssumptionFailed(new Failure(description, e)); + } } } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java index c902434aac2..d4830dd249e 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java @@ -18,9 +18,10 @@ import com.datastax.oss.driver.api.core.DefaultProtocolVersion; import com.datastax.oss.driver.api.core.ProtocolVersion; import com.datastax.oss.driver.api.core.Version; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; +import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement; +import java.util.Collection; import java.util.Optional; import org.junit.AssumptionViolatedException; import org.junit.runner.Description; @@ -55,80 +56,26 @@ protected void after() { ccmBridge.remove(); } - private Statement buildErrorStatement( - Version requirement, String description, boolean lessThan, boolean dse) { - return new Statement() { - - @Override - public void evaluate() { - throw new AssumptionViolatedException( - String.format( - "Test requires %s %s %s but %s is configured. Description: %s", - lessThan ? "less than" : "at least", - dse ? "DSE" : "C*", - requirement, - dse ? ccmBridge.getDseVersion().orElse(null) : ccmBridge.getCassandraVersion(), - description)); - } - }; - } - @Override public Statement apply(Statement base, Description description) { - // If test is annotated with CassandraRequirement or DseRequirement, ensure configured CCM - // cluster meets those requirements. - CassandraRequirement cassandraRequirement = - description.getAnnotation(CassandraRequirement.class); + BackendType backend = + ccmBridge.getDseVersion().isPresent() ? BackendType.DSE : BackendType.CASSANDRA; + Version version = ccmBridge.getDseVersion().orElseGet(ccmBridge::getCassandraVersion); - if (cassandraRequirement != null) { - // if the configured cassandra cassandraRequirement exceeds the one being used skip this test. - if (!cassandraRequirement.min().isEmpty()) { - Version minVersion = Version.parse(cassandraRequirement.min()); - if (minVersion.compareTo(ccmBridge.getCassandraVersion()) > 0) { - return buildErrorStatement(minVersion, cassandraRequirement.description(), false, false); - } - } + Collection requirements = VersionRequirement.fromAnnotations(description); - if (!cassandraRequirement.max().isEmpty()) { - // if the test version exceeds the maximum configured one, fail out. - Version maxVersion = Version.parse(cassandraRequirement.max()); - - if (maxVersion.compareTo(ccmBridge.getCassandraVersion()) <= 0) { - return buildErrorStatement(maxVersion, cassandraRequirement.description(), true, false); - } - } - } - - DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class); - if (dseRequirement != null) { - Optional dseVersionOption = ccmBridge.getDseVersion(); - if (!dseVersionOption.isPresent()) { - return new Statement() { - - @Override - public void evaluate() { - throw new AssumptionViolatedException("Test Requires DSE but C* is configured."); - } - }; - } else { - Version dseVersion = dseVersionOption.get(); - if (!dseRequirement.min().isEmpty()) { - Version minVersion = Version.parse(dseRequirement.min()); - if (minVersion.compareTo(dseVersion) > 0) { - return buildErrorStatement(minVersion, dseRequirement.description(), false, true); - } - } - - if (!dseRequirement.max().isEmpty()) { - Version maxVersion = Version.parse(dseRequirement.max()); - - if (maxVersion.compareTo(dseVersion) <= 0) { - return buildErrorStatement(maxVersion, dseRequirement.description(), true, true); - } + if (VersionRequirement.meetsAny(requirements, backend, version)) { + return super.apply(base, description); + } else { + // requirements not met, throw reasoning assumption to skip test + return new Statement() { + @Override + public void evaluate() { + throw new AssumptionViolatedException( + VersionRequirement.buildReasonString(requirements, backend, version)); } - } + }; } - return super.apply(base, description); } public Version getCassandraVersion() { diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirement.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirement.java new file mode 100644 index 00000000000..ec034dbbac2 --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirement.java @@ -0,0 +1,36 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.requirement; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation for a Class or Method that defines a database backend Version requirement. If the + * type/version in use does not meet the requirement, the test is skipped. + */ +@Repeatable(BackendRequirements.class) +@Retention(RetentionPolicy.RUNTIME) +public @interface BackendRequirement { + BackendType type(); + + String minInclusive() default ""; + + String maxExclusive() default ""; + + String description() default ""; +} diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirements.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirements.java new file mode 100644 index 00000000000..09786c1215b --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirements.java @@ -0,0 +1,25 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.requirement; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** Annotation to allow @BackendRequirement to be repeatable. */ +@Retention(RetentionPolicy.RUNTIME) +public @interface BackendRequirements { + BackendRequirement[] value(); +} diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java new file mode 100644 index 00000000000..eae7067c161 --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java @@ -0,0 +1,32 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.requirement; + +public enum BackendType { + CASSANDRA("C*"), + DSE("Dse"), + ; + + final String friendlyName; + + BackendType(String friendlyName) { + this.friendlyName = friendlyName; + } + + public String getFriendlyName() { + return friendlyName; + } +} diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java new file mode 100644 index 00000000000..28a72bc92ad --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java @@ -0,0 +1,166 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.requirement; + +import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.testinfra.CassandraRequirement; +import com.datastax.oss.driver.api.testinfra.DseRequirement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Optional; +import java.util.stream.Collectors; +import org.junit.runner.Description; + +/** + * Used to unify the requirements specified by + * annotations @CassandraRequirement, @DseRequirment, @BackendRequirement + */ +public class VersionRequirement { + final BackendType backendType; + final Optional minInclusive; + final Optional maxExclusive; + final String description; + + public VersionRequirement( + BackendType backendType, String minInclusive, String maxExclusive, String description) { + this.backendType = backendType; + this.minInclusive = + minInclusive.isEmpty() ? Optional.empty() : Optional.of(Version.parse(minInclusive)); + this.maxExclusive = + maxExclusive.isEmpty() ? Optional.empty() : Optional.of(Version.parse(maxExclusive)); + this.description = description; + } + + public BackendType getBackendType() { + return backendType; + } + + public Optional getMinInclusive() { + return minInclusive; + } + + public Optional getMaxExclusive() { + return maxExclusive; + } + + public String readableString() { + final String versionRange; + if (minInclusive.isPresent() && maxExclusive.isPresent()) { + versionRange = + String.format("%s or greater, but less than %s", minInclusive.get(), maxExclusive.get()); + } else if (minInclusive.isPresent()) { + versionRange = String.format("%s or greater", minInclusive.get()); + } else if (maxExclusive.isPresent()) { + versionRange = String.format("less than %s", maxExclusive.get()); + } else { + versionRange = "any version"; + } + + if (!description.isEmpty()) { + return String.format("%s %s [%s]", backendType.getFriendlyName(), versionRange, description); + } else { + return String.format("%s %s", backendType.getFriendlyName(), versionRange); + } + } + + public static VersionRequirement fromBackendRequirement(BackendRequirement requirement) { + return new VersionRequirement( + requirement.type(), + requirement.minInclusive(), + requirement.maxExclusive(), + requirement.description()); + } + + public static VersionRequirement fromCassandraRequirement(CassandraRequirement requirement) { + return new VersionRequirement( + BackendType.CASSANDRA, requirement.min(), requirement.max(), requirement.description()); + } + + public static VersionRequirement fromDseRequirement(DseRequirement requirement) { + return new VersionRequirement( + BackendType.DSE, requirement.min(), requirement.max(), requirement.description()); + } + + public static Collection fromAnnotations(Description description) { + // collect all requirement annotation types + CassandraRequirement cassandraRequirement = + description.getAnnotation(CassandraRequirement.class); + DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class); + BackendRequirements backendRequirements = description.getAnnotation(BackendRequirements.class); + + // build list of required versions + Collection requirements = new ArrayList<>(); + if (cassandraRequirement != null) { + requirements.add(VersionRequirement.fromCassandraRequirement(cassandraRequirement)); + } + if (dseRequirement != null) { + requirements.add(VersionRequirement.fromDseRequirement(dseRequirement)); + } + if (backendRequirements != null) { + Arrays.stream(backendRequirements.value()) + .forEach(r -> requirements.add(VersionRequirement.fromBackendRequirement(r))); + } + return requirements; + } + + public static boolean meetsAny( + Collection requirements, + BackendType configuredBackend, + Version configuredVersion) { + // special case: if there are no requirements then any backend/version is sufficient + if (requirements.isEmpty()) { + return true; + } + + return requirements.stream() + .anyMatch( + requirement -> { + // requirement is different db type + if (requirement.getBackendType() != configuredBackend) { + return false; + } + + // configured version is less than requirement min + if (requirement.getMinInclusive().isPresent()) { + if (requirement.getMinInclusive().get().compareTo(configuredVersion) > 0) { + return false; + } + } + + // configured version is greater than or equal to requirement max + if (requirement.getMaxExclusive().isPresent()) { + if (requirement.getMaxExclusive().get().compareTo(configuredVersion) <= 0) { + return false; + } + } + + // backend type and version range match + return true; + }); + } + + public static String buildReasonString( + Collection requirements, BackendType backend, Version version) { + return String.format( + "Test requires one of:\n%s\nbut configuration is %s %s.", + requirements.stream() + .map(req -> String.format(" - %s", req.readableString())) + .collect(Collectors.joining("\n")), + backend.getFriendlyName(), + version); + } +} diff --git a/test-infra/src/test/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirementTest.java b/test-infra/src/test/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirementTest.java new file mode 100644 index 00000000000..51a362d2ce5 --- /dev/null +++ b/test-infra/src/test/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirementTest.java @@ -0,0 +1,184 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.requirement; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import java.util.Collections; +import java.util.List; +import org.junit.Test; + +public class VersionRequirementTest { + // backend aliases + private static BackendType CASSANDRA = BackendType.CASSANDRA; + private static BackendType DSE = BackendType.DSE; + + // version numbers + private static Version V_0_0_0 = Version.parse("0.0.0"); + private static Version V_0_1_0 = Version.parse("0.1.0"); + private static Version V_1_0_0 = Version.parse("1.0.0"); + private static Version V_1_0_1 = Version.parse("1.0.1"); + private static Version V_1_1_0 = Version.parse("1.1.0"); + private static Version V_2_0_0 = Version.parse("2.0.0"); + private static Version V_2_0_1 = Version.parse("2.0.1"); + private static Version V_3_0_0 = Version.parse("3.0.0"); + private static Version V_3_1_0 = Version.parse("3.1.0"); + private static Version V_4_0_0 = Version.parse("4.0.0"); + + // requirements + private static VersionRequirement CASSANDRA_ANY = new VersionRequirement(CASSANDRA, "", "", ""); + private static VersionRequirement CASSANDRA_FROM_1_0_0 = + new VersionRequirement(CASSANDRA, "1.0.0", "", ""); + private static VersionRequirement CASSANDRA_TO_1_0_0 = + new VersionRequirement(CASSANDRA, "", "1.0.0", ""); + private static VersionRequirement CASSANDRA_FROM_1_0_0_TO_2_0_0 = + new VersionRequirement(CASSANDRA, "1.0.0", "2.0.0", ""); + private static VersionRequirement CASSANDRA_FROM_1_1_0 = + new VersionRequirement(CASSANDRA, "1.1.0", "", ""); + private static VersionRequirement CASSANDRA_FROM_3_0_0_TO_3_1_0 = + new VersionRequirement(CASSANDRA, "3.0.0", "3.1.0", ""); + private static VersionRequirement DSE_ANY = new VersionRequirement(DSE, "", "", ""); + + @Test + public void empty_requirements() { + List req = Collections.emptyList(); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, DSE, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isTrue(); + } + + @Test + public void single_requirement_any_version() { + List anyCassandra = Collections.singletonList(CASSANDRA_ANY); + List anyDse = Collections.singletonList(DSE_ANY); + + assertThat(VersionRequirement.meetsAny(anyCassandra, CASSANDRA, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(anyCassandra, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(anyDse, DSE, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(anyDse, DSE, V_1_0_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(anyDse, CASSANDRA, V_0_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(anyDse, CASSANDRA, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(anyCassandra, DSE, V_0_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(anyCassandra, DSE, V_1_0_0)).isFalse(); + } + + @Test + public void single_requirement_min_only() { + List req = Collections.singletonList(CASSANDRA_FROM_1_0_0); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_1)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_1_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_1_0)).isFalse(); + } + + @Test + public void single_requirement_max_only() { + List req = Collections.singletonList(CASSANDRA_TO_1_0_0); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_1_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, DSE, V_0_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_1)).isFalse(); + } + + @Test + public void single_requirement_min_and_max() { + List req = Collections.singletonList(CASSANDRA_FROM_1_0_0_TO_2_0_0); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_1)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_1_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_1_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_1)).isFalse(); + } + + @Test + public void multi_requirement_any_version() { + List req = ImmutableList.of(CASSANDRA_ANY, DSE_ANY); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isTrue(); + } + + @Test + public void multi_db_requirement_min_one_any_other() { + List req = ImmutableList.of(CASSANDRA_FROM_1_0_0, DSE_ANY); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, DSE, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isFalse(); + } + + @Test + public void multi_requirement_two_ranges() { + List req = + ImmutableList.of(CASSANDRA_FROM_1_0_0_TO_2_0_0, CASSANDRA_FROM_3_0_0_TO_3_1_0); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_1_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_3_0_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_3_1_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_4_0_0)).isFalse(); + } + + @Test + public void multi_requirement_overlapping() { + List req = + ImmutableList.of(CASSANDRA_FROM_1_0_0_TO_2_0_0, CASSANDRA_FROM_1_1_0); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_1_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, DSE, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isFalse(); + } + + @Test + public void multi_requirement_not_range() { + List req = ImmutableList.of(CASSANDRA_TO_1_0_0, CASSANDRA_FROM_1_1_0); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_0_0_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_1_0)).isTrue(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_2_0_0)).isTrue(); + + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_0)).isFalse(); + assertThat(VersionRequirement.meetsAny(req, CASSANDRA, V_1_0_1)).isFalse(); + } +} From 6cf075fc68eccb06e38e3e26deee75f491fa0fe2 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 27 Jun 2023 10:46:46 -0500 Subject: [PATCH 248/395] JAVA-3061 Remove CqlVector, represent CQL vector types as Lists (#1656) --- core/revapi.json | 65 ++++++++++++- .../oss/driver/api/core/data/CqlVector.java | 91 ------------------- .../driver/api/core/data/GettableById.java | 5 +- .../driver/api/core/data/GettableByIndex.java | 4 +- .../driver/api/core/data/GettableByName.java | 5 +- .../driver/api/core/data/SettableById.java | 9 +- .../driver/api/core/data/SettableByIndex.java | 7 +- .../driver/api/core/data/SettableByName.java | 7 +- .../driver/api/core/type/ContainerType.java | 28 ++++++ .../oss/driver/api/core/type/DataTypes.java | 16 +++- .../oss/driver/api/core/type/ListType.java | 5 +- .../oss/driver/api/core/type/SetType.java | 5 +- .../oss/driver/api/core/type/VectorType.java | 25 +++++ .../api/core/type/codec/TypeCodecs.java | 11 +-- .../api/core/type/reflect/GenericType.java | 8 -- .../schema/parsing/DataTypeCqlNameParser.java | 4 +- .../core/type/DefaultVectorType.java} | 34 ++++--- .../{CqlVectorCodec.java => VectorCodec.java} | 76 ++++++++++------ .../codec/registry/CachingCodecRegistry.java | 56 +++++------- ...torCodecTest.java => VectorCodecTest.java} | 52 ++++++++--- 20 files changed, 290 insertions(+), 223 deletions(-) delete mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/type/ContainerType.java create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/type/VectorType.java rename core/src/main/java/com/datastax/oss/driver/{api/core/type/CqlVectorType.java => internal/core/type/DefaultVectorType.java} (64%) rename core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/{CqlVectorCodec.java => VectorCodec.java} (62%) rename core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/{CqlVectorCodecTest.java => VectorCodecTest.java} (62%) diff --git a/core/revapi.json b/core/revapi.json index af719e9987e..f844479cd29 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -6824,7 +6824,70 @@ "new": "class com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException", "superClass": "com.datastax.oss.driver.api.core.DriverException", "justification": "Make CodecNotFoundException to extend DriverException as all other driver exceptions do" - } + }, + { + "code": "java.class.removed", + "old": "class com.datastax.oss.driver.api.core.data.CqlVector", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getCqlVector(com.datastax.oss.driver.api.core.CqlIdentifier)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getCqlVector(int)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getCqlVector(java.lang.String)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method SelfT com.datastax.oss.driver.api.core.data.SettableById>::setCqlVector(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setCqlVector(int, com.datastax.oss.driver.api.core.data.CqlVector)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setCqlVector(java.lang.String, com.datastax.oss.driver.api.core.data.CqlVector)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.class.removed", + "old": "class com.datastax.oss.driver.api.core.type.CqlVectorType", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.returnTypeChanged", + "old": "method com.datastax.oss.driver.api.core.type.CqlVectorType com.datastax.oss.driver.api.core.type.DataTypes::vectorOf(com.datastax.oss.driver.api.core.type.DataType, int)", + "new": "method com.datastax.oss.driver.api.core.type.VectorType com.datastax.oss.driver.api.core.type.DataTypes::vectorOf(com.datastax.oss.driver.api.core.type.DataType, int)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.parameterTypeChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(===com.datastax.oss.driver.api.core.type.CqlVectorType===, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(===com.datastax.oss.driver.api.core.type.VectorType===, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.CqlVectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "Refactoring in JAVA-3061" + }, + { + "code": "java.method.removed", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "justification": "Refactoring in JAVA-3061" + } ] } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java deleted file mode 100644 index c34cc38a10a..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright DataStax, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.datastax.oss.driver.api.core.data; - -import com.datastax.oss.driver.shaded.guava.common.base.Joiner; -import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; -import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; -import java.util.Arrays; - -/** An n-dimensional vector defined in CQL */ -public class CqlVector { - - private final ImmutableList values; - - private CqlVector(ImmutableList values) { - this.values = values; - } - - public static Builder builder() { - return new Builder(); - } - - public Iterable getValues() { - return values; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } else if (o instanceof CqlVector) { - CqlVector that = (CqlVector) o; - return this.values.equals(that.values); - } else { - return false; - } - } - - @Override - public int hashCode() { - return Arrays.hashCode(values.toArray()); - } - - @Override - public String toString() { - - String contents = Joiner.on(", ").join(this.values); - return "CqlVector{" + contents + '}'; - } - - public static class Builder { - - private ImmutableList.Builder listBuilder; - - private Builder() { - listBuilder = new ImmutableList.Builder(); - } - - public Builder add(T element) { - listBuilder.add(element); - return this; - } - - public Builder add(T... elements) { - listBuilder.addAll(Iterators.forArray(elements)); - return this; - } - - public Builder addAll(Iterable iter) { - listBuilder.addAll(iter); - return this; - } - - public CqlVector build() { - return new CqlVector(listBuilder.build()); - } - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java index 7d2ea3a7f8b..6c6cf95a568 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java @@ -529,8 +529,9 @@ default CqlDuration getCqlDuration(@NonNull CqlIdentifier id) { * @throws IllegalArgumentException if the id is invalid. */ @Nullable - default CqlVector getCqlVector(@NonNull CqlIdentifier id) { - return getCqlVector(firstIndexOf(id)); + default List getVector( + @NonNull CqlIdentifier id, @NonNull Class elementsClass) { + return getVector(firstIndexOf(id), elementsClass); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java index 0da60bef285..a805342defc 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java @@ -444,8 +444,8 @@ default CqlDuration getCqlDuration(int i) { * @throws IndexOutOfBoundsException if the index is invalid. */ @Nullable - default CqlVector getCqlVector(int i) { - return get(i, CqlVector.class); + default List getVector(int i, @NonNull Class elementsClass) { + return get(i, GenericType.listOf(elementsClass)); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java index 40e5532f85a..3214994c04a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java @@ -525,8 +525,9 @@ default CqlDuration getCqlDuration(@NonNull String name) { * @throws IllegalArgumentException if the name is invalid. */ @Nullable - default CqlVector getCqlVector(@NonNull String name) { - return getCqlVector(firstIndexOf(name)); + default List getVector( + @NonNull String name, @NonNull Class elementsClass) { + return getList(firstIndexOf(name), elementsClass); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java index 58eb7098028..3c17f0cb6f1 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java @@ -560,7 +560,7 @@ default SelfT setCqlDuration(@NonNull CqlIdentifier id, @Nullable CqlDuration v) } /** - * Sets the value for all occurrences of {@code id} to the provided duration. + * Sets the value for all occurrences of {@code id} to the provided {@code vector}. * *

    By default, this works with CQL type {@code vector}. * @@ -571,10 +571,13 @@ default SelfT setCqlDuration(@NonNull CqlIdentifier id, @Nullable CqlDuration v) */ @NonNull @CheckReturnValue - default SelfT setCqlVector(@NonNull CqlIdentifier id, @Nullable CqlVector v) { + default SelfT setVector( + @NonNull CqlIdentifier id, + @Nullable List v, + @NonNull Class elementsClass) { SelfT result = null; for (Integer i : allIndicesOf(id)) { - result = (result == null ? this : result).setCqlVector(i, v); + result = (result == null ? this : result).setVector(i, v, elementsClass); } assert result != null; // allIndices throws if there are no results return result; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java index bdee1de7b6f..52bc92d4c09 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java @@ -415,7 +415,7 @@ default SelfT setCqlDuration(int i, @Nullable CqlDuration v) { } /** - * Sets the {@code i}th value to the provided duration. + * Sets the {@code i}th value to the provided vector. * *

    By default, this works with CQL type {@code vector}. * @@ -423,8 +423,9 @@ default SelfT setCqlDuration(int i, @Nullable CqlDuration v) { */ @NonNull @CheckReturnValue - default SelfT setCqlVector(int i, @Nullable CqlVector v) { - return set(i, v, CqlVector.class); + default SelfT setVector( + int i, @Nullable List v, @NonNull Class elementsClass) { + return set(i, v, GenericType.listOf(elementsClass)); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java index 26e5340bdce..559ad40cbff 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java @@ -559,7 +559,7 @@ default SelfT setCqlDuration(@NonNull String name, @Nullable CqlDuration v) { } /** - * Sets the value for all occurrences of {@code name} to the provided duration. + * Sets the value for all occurrences of {@code name} to the provided vector. * *

    By default, this works with CQL type {@code vector}. * @@ -570,10 +570,11 @@ default SelfT setCqlDuration(@NonNull String name, @Nullable CqlDuration v) { */ @NonNull @CheckReturnValue - default SelfT setCqlVector(@NonNull String name, @Nullable CqlVector v) { + default SelfT setVector( + @NonNull String name, @Nullable List v, @NonNull Class elementsClass) { SelfT result = null; for (Integer i : allIndicesOf(name)) { - result = (result == null ? this : result).setCqlVector(i, v); + result = (result == null ? this : result).setVector(i, v, elementsClass); } assert result != null; // allIndices throws if there are no results return result; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/ContainerType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/ContainerType.java new file mode 100644 index 00000000000..79c16b25e05 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/ContainerType.java @@ -0,0 +1,28 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.type; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * Representation of a type which "contains" some other type. This might be a collection type or it + * could be some other kind of container; the term is deliberately left somewhat vague. + */ +public interface ContainerType { + + @NonNull + DataType getElementType(); +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java index f8cc7042516..6f28ceda45a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java @@ -23,6 +23,7 @@ import com.datastax.oss.driver.internal.core.type.DefaultMapType; import com.datastax.oss.driver.internal.core.type.DefaultSetType; import com.datastax.oss.driver.internal.core.type.DefaultTupleType; +import com.datastax.oss.driver.internal.core.type.DefaultVectorType; import com.datastax.oss.driver.internal.core.type.PrimitiveType; import com.datastax.oss.driver.shaded.guava.common.base.Splitter; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -65,14 +66,19 @@ public static DataType custom(@NonNull String className) { if (className.equals("org.apache.cassandra.db.marshal.DurationType")) return DURATION; /* Vector support is currently implemented as a custom type but is also parameterized */ - if (className.startsWith(CqlVectorType.CQLVECTOR_CLASS_NAME)) { + if (className.startsWith(DefaultVectorType.VECTOR_CLASS_NAME)) { List params = paramSplitter.splitToList( className.substring( - CqlVectorType.CQLVECTOR_CLASS_NAME.length() + 1, className.length() - 1)); + DefaultVectorType.VECTOR_CLASS_NAME.length() + 1, className.length() - 1)); DataType subType = classNameParser.parse(params.get(0), AttachmentPoint.NONE); int dimensions = Integer.parseInt(params.get(1)); - return new CqlVectorType(subType, dimensions); + if (dimensions <= 0) { + throw new IllegalArgumentException( + String.format( + "Request to create vector of size %d, size must be positive", dimensions)); + } + return new DefaultVectorType(subType, dimensions); } return new DefaultCustomType(className); } @@ -135,7 +141,7 @@ public static TupleType tupleOf(@NonNull DataType... componentTypes) { return new DefaultTupleType(ImmutableList.copyOf(Arrays.asList(componentTypes))); } - public static CqlVectorType vectorOf(DataType subtype, int dimensions) { - return new CqlVectorType(subtype, dimensions); + public static VectorType vectorOf(DataType subtype, int dimensions) { + return new DefaultVectorType(subtype, dimensions); } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/ListType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/ListType.java index 1bafb1693d7..3ea946387fb 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/ListType.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/ListType.java @@ -18,10 +18,7 @@ import com.datastax.oss.protocol.internal.ProtocolConstants; import edu.umd.cs.findbugs.annotations.NonNull; -public interface ListType extends DataType { - - @NonNull - DataType getElementType(); +public interface ListType extends DataType, ContainerType { boolean isFrozen(); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/SetType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/SetType.java index eadd0a702e3..c4bb43c1a37 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/SetType.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/SetType.java @@ -18,10 +18,7 @@ import com.datastax.oss.protocol.internal.ProtocolConstants; import edu.umd.cs.findbugs.annotations.NonNull; -public interface SetType extends DataType { - - @NonNull - DataType getElementType(); +public interface SetType extends DataType, ContainerType { boolean isFrozen(); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/VectorType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/VectorType.java new file mode 100644 index 00000000000..657ea9d690f --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/VectorType.java @@ -0,0 +1,25 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.type; + +/** + * Type representing a Cassandra vector type as described in CEP-30. At the moment this is + * implemented as a custom type so we include the CustomType interface as well. + */ +public interface VectorType extends CustomType, ContainerType { + + int getDimensions(); +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java index 07fbf309988..e824e7f41fc 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java @@ -16,21 +16,19 @@ package com.datastax.oss.driver.api.core.type.codec; import com.datastax.oss.driver.api.core.data.CqlDuration; -import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; -import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.CustomType; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.TupleType; import com.datastax.oss.driver.api.core.type.UserDefinedType; +import com.datastax.oss.driver.api.core.type.VectorType; import com.datastax.oss.driver.internal.core.type.codec.BigIntCodec; import com.datastax.oss.driver.internal.core.type.codec.BlobCodec; import com.datastax.oss.driver.internal.core.type.codec.BooleanCodec; import com.datastax.oss.driver.internal.core.type.codec.CounterCodec; import com.datastax.oss.driver.internal.core.type.codec.CqlDurationCodec; -import com.datastax.oss.driver.internal.core.type.codec.CqlVectorCodec; import com.datastax.oss.driver.internal.core.type.codec.CustomCodec; import com.datastax.oss.driver.internal.core.type.codec.DateCodec; import com.datastax.oss.driver.internal.core.type.codec.DecimalCodec; @@ -51,6 +49,7 @@ import com.datastax.oss.driver.internal.core.type.codec.UdtCodec; import com.datastax.oss.driver.internal.core.type.codec.UuidCodec; import com.datastax.oss.driver.internal.core.type.codec.VarIntCodec; +import com.datastax.oss.driver.internal.core.type.codec.VectorCodec; import com.datastax.oss.driver.shaded.guava.common.base.Charsets; import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import edu.umd.cs.findbugs.annotations.NonNull; @@ -208,9 +207,9 @@ public static TypeCodec tupleOf(@NonNull TupleType cqlType) { return new TupleCodec(cqlType); } - public static TypeCodec> vectorOf( - @NonNull CqlVectorType type, @NonNull TypeCodec subtypeCodec) { - return new CqlVectorCodec( + public static TypeCodec> vectorOf( + @NonNull VectorType type, @NonNull TypeCodec subtypeCodec) { + return new VectorCodec( DataTypes.vectorOf(subtypeCodec.getCqlType(), type.getDimensions()), subtypeCodec); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java index db573b3451b..a1977e39f23 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java @@ -16,7 +16,6 @@ package com.datastax.oss.driver.api.core.type.reflect; import com.datastax.oss.driver.api.core.data.CqlDuration; -import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.GettableByIndex; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; @@ -166,13 +165,6 @@ public static GenericType> mapOf( return new GenericType<>(token); } - @NonNull - public static GenericType> vectorOf(@NonNull GenericType elementType) { - TypeToken> token = - new TypeToken>() {}.where(new TypeParameter() {}, elementType.token); - return new GenericType<>(token); - } - @NonNull public static GenericType arrayOf(@NonNull Class componentType) { TypeToken token = diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java index 76a2301522d..b5f36c89111 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeCqlNameParser.java @@ -16,13 +16,13 @@ package com.datastax.oss.driver.internal.core.metadata.schema.parsing; import com.datastax.oss.driver.api.core.CqlIdentifier; -import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metadata.schema.ShallowUserDefinedType; import com.datastax.oss.driver.internal.core.type.DefaultTupleType; +import com.datastax.oss.driver.internal.core.type.DefaultVectorType; import com.datastax.oss.driver.internal.core.type.codec.ParseUtils; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -145,7 +145,7 @@ private DataType parse( } DataType subType = parse(parameters.get(0), keyspaceId, false, userTypes, context); int dimensions = Integer.parseInt(parameters.get(1)); - return new CqlVectorType(subType, dimensions); + return new DefaultVectorType(subType, dimensions); } throw new IllegalArgumentException("Could not parse type name " + toParse); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java similarity index 64% rename from core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java rename to core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java index 528a688451a..2517e7db30e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/CqlVectorType.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java @@ -13,37 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.datastax.oss.driver.api.core.type; +package com.datastax.oss.driver.internal.core.type; import com.datastax.oss.driver.api.core.detach.AttachmentPoint; +import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.VectorType; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Objects; +import net.jcip.annotations.Immutable; -public class CqlVectorType implements CustomType { +@Immutable +public class DefaultVectorType implements VectorType { - public static final String CQLVECTOR_CLASS_NAME = "org.apache.cassandra.db.marshal.VectorType"; + public static final String VECTOR_CLASS_NAME = "org.apache.cassandra.db.marshal.VectorType"; private final DataType subtype; private final int dimensions; - public CqlVectorType(DataType subtype, int dimensions) { + public DefaultVectorType(DataType subtype, int dimensions) { this.dimensions = dimensions; this.subtype = subtype; } - public int getDimensions() { - return this.dimensions; + /* ============== ContainerType interface ============== */ + @Override + public DataType getElementType() { + return this.subtype; } - public DataType getSubtype() { - return this.subtype; + /* ============== VectorType interface ============== */ + @Override + public int getDimensions() { + return this.dimensions; } + /* ============== CustomType interface ============== */ @NonNull @Override public String getClassName() { - return CQLVECTOR_CLASS_NAME; + return VECTOR_CLASS_NAME; } @NonNull @@ -52,12 +61,13 @@ public String asCql(boolean includeFrozen, boolean pretty) { return String.format("'%s(%d)'", getClassName(), getDimensions()); } + /* ============== General class implementation ============== */ @Override public boolean equals(Object o) { if (o == this) { return true; - } else if (o instanceof CqlVectorType) { - CqlVectorType that = (CqlVectorType) o; + } else if (o instanceof DefaultVectorType) { + DefaultVectorType that = (DefaultVectorType) o; return that.subtype.equals(this.subtype) && that.dimensions == this.dimensions; } else { return false; @@ -71,7 +81,7 @@ public int hashCode() { @Override public String toString() { - return String.format("CqlVector(%s, %d)", getSubtype(), getDimensions()); + return String.format("Vector(%s, %d)", getElementType(), getDimensions()); } @Override diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java similarity index 62% rename from core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java rename to core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java index 4b739862d33..75b3e46ddfd 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java @@ -16,35 +16,37 @@ package com.datastax.oss.driver.internal.core.type.codec; import com.datastax.oss.driver.api.core.ProtocolVersion; -import com.datastax.oss.driver.api.core.data.CqlVector; -import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.VectorType; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import com.datastax.oss.driver.shaded.guava.common.base.Splitter; -import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; import com.datastax.oss.driver.shaded.guava.common.collect.Streams; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; -public class CqlVectorCodec implements TypeCodec> { +public class VectorCodec implements TypeCodec> { - private final CqlVectorType cqlType; - private final GenericType> javaType; + private final VectorType cqlType; + private final GenericType> javaType; private final TypeCodec subtypeCodec; - public CqlVectorCodec(CqlVectorType cqlType, TypeCodec subtypeCodec) { + public VectorCodec(VectorType cqlType, TypeCodec subtypeCodec) { this.cqlType = cqlType; this.subtypeCodec = subtypeCodec; - this.javaType = GenericType.vectorOf(subtypeCodec.getJavaType()); + this.javaType = GenericType.listOf(subtypeCodec.getJavaType()); } @NonNull @Override - public GenericType> getJavaType() { + public GenericType> getJavaType() { return this.javaType; } @@ -57,15 +59,34 @@ public DataType getCqlType() { @Nullable @Override public ByteBuffer encode( - @Nullable CqlVector value, @NonNull ProtocolVersion protocolVersion) { + @Nullable List value, @NonNull ProtocolVersion protocolVersion) { if (value == null || cqlType.getDimensions() <= 0) { return null; } ByteBuffer[] valueBuffs = new ByteBuffer[cqlType.getDimensions()]; - Iterator values = value.getValues().iterator(); + Iterator values = value.iterator(); int allValueBuffsSize = 0; for (int i = 0; i < cqlType.getDimensions(); ++i) { - ByteBuffer valueBuff = this.subtypeCodec.encode(values.next(), protocolVersion); + ByteBuffer valueBuff; + SubtypeT valueObj; + + try { + valueObj = values.next(); + } catch (NoSuchElementException nsee) { + throw new IllegalArgumentException( + String.format( + "Not enough elements; must provide elements for %d dimensions", + cqlType.getDimensions())); + } + + try { + valueBuff = this.subtypeCodec.encode(valueObj, protocolVersion); + } catch (ClassCastException e) { + throw new IllegalArgumentException("Invalid type for element: " + valueObj.getClass()); + } + if (valueBuff == null) { + throw new NullPointerException("Vector elements cannot encode to CQL NULL"); + } allValueBuffsSize += valueBuff.limit(); valueBuff.rewind(); valueBuffs[i] = valueBuff; @@ -82,7 +103,7 @@ public ByteBuffer encode( @Nullable @Override - public CqlVector decode( + public List decode( @Nullable ByteBuffer bytes, @NonNull ProtocolVersion protocolVersion) { if (bytes == null || bytes.remaining() == 0) { return null; @@ -101,35 +122,38 @@ Elements should at least precede themselves with their size (along the lines of cqlType.getDimensions(), bytes.remaining())); } - ImmutableList.Builder builder = ImmutableList.builder(); + List rv = new ArrayList(cqlType.getDimensions()); for (int i = 0; i < cqlType.getDimensions(); ++i) { ByteBuffer slice = bytes.slice(); slice.limit(elementSize); - builder.add(this.subtypeCodec.decode(slice, protocolVersion)); + rv.add(this.subtypeCodec.decode(slice, protocolVersion)); bytes.position(bytes.position() + elementSize); } /* Restore the input ByteBuffer to its original state */ bytes.rewind(); - return CqlVector.builder().addAll(builder.build()).build(); + return rv; } @NonNull @Override - public String format(@Nullable CqlVector value) { - return value == null ? "NULL" : Iterables.toString(value.getValues()); + public String format(@Nullable List value) { + return value == null ? "NULL" : Iterables.toString(value); } @Nullable @Override - public CqlVector parse(@Nullable String value) { - if (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL")) return null; - - ImmutableList values = - Streams.stream(Splitter.on(", ").split(value.substring(1, value.length() - 1))) - .map(subtypeCodec::parse) - .collect(ImmutableList.toImmutableList()); - return CqlVector.builder().addAll(values).build(); + public List parse(@Nullable String value) { + return (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL")) + ? null + : this.from(value); + } + + private List from(@Nullable String value) { + + return Streams.stream(Splitter.on(", ").split(value.substring(1, value.length() - 1))) + .map(subtypeCodec::parse) + .collect(Collectors.toCollection(ArrayList::new)); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java index 18b1f55e106..ca282c3e355 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java @@ -16,18 +16,9 @@ package com.datastax.oss.driver.internal.core.type.codec.registry; import com.datastax.oss.driver.api.core.data.CqlDuration; -import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; -import com.datastax.oss.driver.api.core.type.CqlVectorType; -import com.datastax.oss.driver.api.core.type.CustomType; -import com.datastax.oss.driver.api.core.type.DataType; -import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.core.type.ListType; -import com.datastax.oss.driver.api.core.type.MapType; -import com.datastax.oss.driver.api.core.type.SetType; -import com.datastax.oss.driver.api.core.type.TupleType; -import com.datastax.oss.driver.api.core.type.UserDefinedType; +import com.datastax.oss.driver.api.core.type.*; import com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; @@ -342,7 +333,7 @@ protected GenericType inspectType(@NonNull Object value, @Nullable DataType c } GenericType elementType = inspectType( - firstElement, cqlType == null ? null : ((ListType) cqlType).getElementType()); + firstElement, cqlType == null ? null : ((ContainerType) cqlType).getElementType()); return GenericType.listOf(elementType); } } else if (value instanceof Set) { @@ -547,6 +538,18 @@ protected DataType inferCqlTypeFromValue(@NonNull Object value) { return null; } + private TypeCodec getElementCodec( + ContainerType cqlType, TypeToken token, boolean isJavaCovariant) { + + DataType elementCqlType = cqlType.getElementType(); + if (token.getType() instanceof ParameterizedType) { + Type[] typeArguments = ((ParameterizedType) token.getType()).getActualTypeArguments(); + GenericType elementJavaType = GenericType.of(typeArguments[0]); + return uncheckedCast(codecFor(elementCqlType, elementJavaType, isJavaCovariant)); + } + return codecFor(elementCqlType); + } + // Try to create a codec when we haven't found it in the cache @NonNull protected TypeCodec createCodec( @@ -561,26 +564,12 @@ protected TypeCodec createCodec( } else { // Both non-null TypeToken token = javaType.__getToken(); if (cqlType instanceof ListType && List.class.isAssignableFrom(token.getRawType())) { - DataType elementCqlType = ((ListType) cqlType).getElementType(); - TypeCodec elementCodec; - if (token.getType() instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) token.getType()).getActualTypeArguments(); - GenericType elementJavaType = GenericType.of(typeArguments[0]); - elementCodec = uncheckedCast(codecFor(elementCqlType, elementJavaType, isJavaCovariant)); - } else { - elementCodec = codecFor(elementCqlType); - } + TypeCodec elementCodec = + getElementCodec((ContainerType) cqlType, token, isJavaCovariant); return TypeCodecs.listOf(elementCodec); } else if (cqlType instanceof SetType && Set.class.isAssignableFrom(token.getRawType())) { - DataType elementCqlType = ((SetType) cqlType).getElementType(); - TypeCodec elementCodec; - if (token.getType() instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) token.getType()).getActualTypeArguments(); - GenericType elementJavaType = GenericType.of(typeArguments[0]); - elementCodec = uncheckedCast(codecFor(elementCqlType, elementJavaType, isJavaCovariant)); - } else { - elementCodec = codecFor(elementCqlType); - } + TypeCodec elementCodec = + getElementCodec((ContainerType) cqlType, token, isJavaCovariant); return TypeCodecs.setOf(elementCodec); } else if (cqlType instanceof MapType && Map.class.isAssignableFrom(token.getRawType())) { DataType keyCqlType = ((MapType) cqlType).getKeyType(); @@ -604,11 +593,10 @@ protected TypeCodec createCodec( } else if (cqlType instanceof UserDefinedType && UdtValue.class.isAssignableFrom(token.getRawType())) { return TypeCodecs.udtOf((UserDefinedType) cqlType); - } else if (cqlType instanceof CqlVectorType - && CqlVector.class.isAssignableFrom(token.getRawType())) { - CqlVectorType vectorType = (CqlVectorType) cqlType; - TypeCodec subtypeCodec = codecFor(vectorType.getSubtype()); - return TypeCodecs.vectorOf((CqlVectorType) cqlType, subtypeCodec); + } else if (cqlType instanceof VectorType && List.class.isAssignableFrom(token.getRawType())) { + VectorType vectorType = (VectorType) cqlType; + TypeCodec elementCodec = getElementCodec(vectorType, token, isJavaCovariant); + return TypeCodecs.vectorOf(vectorType, elementCodec); } else if (cqlType instanceof CustomType && ByteBuffer.class.isAssignableFrom(token.getRawType())) { return TypeCodecs.custom(cqlType); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java similarity index 62% rename from core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java rename to core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java index eac142f6ebe..9b463dcb53e 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/CqlVectorCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java @@ -18,23 +18,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.datastax.oss.driver.api.core.data.CqlVector; -import com.datastax.oss.driver.api.core.type.CqlVectorType; import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.driver.api.core.type.VectorType; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.internal.core.type.DefaultVectorType; +import com.google.common.collect.Lists; +import java.util.List; import org.junit.Test; -public class CqlVectorCodecTest extends CodecTestBase> { +public class VectorCodecTest extends CodecTestBase> { - private static final CqlVector VECTOR = CqlVector.builder().add(1.0f, 2.5f).build(); + private static final List VECTOR = Lists.newArrayList(1.0f, 2.5f); private static final String VECTOR_HEX_STRING = "0x" + "3f800000" + "40200000"; private static final String FORMATTED_VECTOR = "[1.0, 2.5]"; - public CqlVectorCodecTest() { - CqlVectorType vectorType = DataTypes.vectorOf(DataTypes.FLOAT, 2); + public VectorCodecTest() { + VectorType vectorType = DataTypes.vectorOf(DataTypes.FLOAT, 2); this.codec = TypeCodecs.vectorOf(vectorType, TypeCodecs.FLOAT); } @@ -44,6 +46,26 @@ public void should_encode() { assertThat(encode(null)).isNull(); } + /** Too few eleements will cause an exception, extra elements will be silently ignored */ + @Test + public void should_throw_on_encode_with_too_few_elements() { + assertThatThrownBy(() -> encode(VECTOR.subList(0, 1))) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void should_throw_on_encode_with_empty_list() { + assertThatThrownBy(() -> encode(Lists.newArrayList())) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void should_encode_with_too_many_elements() { + List doubleVector = Lists.newArrayList(VECTOR); + doubleVector.addAll(VECTOR); + assertThat(encode(doubleVector)).isEqualTo(VECTOR_HEX_STRING); + } + @Test public void should_decode() { assertThat(decode(VECTOR_HEX_STRING)).isEqualTo(VECTOR); @@ -52,7 +74,7 @@ public void should_decode() { } @Test - public void decode_throws_if_too_few_bytes() { + public void should_throw_on_decode_if_too_few_bytes() { // Dropping 4 bytes would knock off exactly 1 float, anything less than that would be something // we couldn't parse a float out of for (int i = 1; i <= 3; ++i) { @@ -80,30 +102,30 @@ public void should_parse() { @Test public void should_accept_data_type() { - assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 2))).isTrue(); + assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 2))).isTrue(); assertThat(codec.accepts(DataTypes.INT)).isFalse(); } @Test public void should_accept_vector_type_correct_dimension_only() { - assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 0))).isFalse(); - assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 1))).isFalse(); - assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, 2))).isTrue(); + assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 0))).isFalse(); + assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 1))).isFalse(); + assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 2))).isTrue(); for (int i = 3; i < 1000; ++i) { - assertThat(codec.accepts(new CqlVectorType(DataTypes.FLOAT, i))).isFalse(); + assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, i))).isFalse(); } } @Test public void should_accept_generic_type() { - assertThat(codec.accepts(GenericType.vectorOf(GenericType.FLOAT))).isTrue(); - assertThat(codec.accepts(GenericType.vectorOf(GenericType.INTEGER))).isFalse(); + assertThat(codec.accepts(GenericType.listOf(GenericType.FLOAT))).isTrue(); + assertThat(codec.accepts(GenericType.listOf(GenericType.INTEGER))).isFalse(); assertThat(codec.accepts(GenericType.of(Integer.class))).isFalse(); } @Test public void should_accept_raw_type() { - assertThat(codec.accepts(CqlVector.class)).isTrue(); + assertThat(codec.accepts(List.class)).isTrue(); assertThat(codec.accepts(Integer.class)).isFalse(); } From 7d01a5b424ac8898f2e3ba1c598cbaf505b9b4c9 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Fri, 16 Jun 2023 17:32:40 -0700 Subject: [PATCH 249/395] JAVA-3068: Use fully qualified table CQL in should_not_allow_unset_value_when_protocol_less_than_v4 to work around intermittent server error --- .../oss/driver/core/cql/BatchStatementIT.java | 15 +++++++++++---- .../oss/driver/core/cql/BoundStatementCcmIT.java | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java index 358ed2b0f02..cc960b6c27c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.cql; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; @@ -338,16 +339,20 @@ public void should_fail_counter_batch_with_non_counter_increment() { sessionRule.session().execute(batchStatement); } - @Test(expected = IllegalStateException.class) + @Test public void should_not_allow_unset_value_when_protocol_less_than_v4() { // CREATE TABLE test (k0 text, k1 int, v int, PRIMARY KEY (k0, k1)) DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") .build(); - try (CqlSession v3Session = SessionUtils.newSession(ccmRule, sessionRule.keyspace(), loader)) { + try (CqlSession v3Session = SessionUtils.newSession(ccmRule, loader)) { + // Intentionally use fully qualified table here to avoid warnings as these are not supported + // by v3 protocol version, see JAVA-3068 PreparedStatement prepared = - v3Session.prepare("INSERT INTO test (k0, k1, v) values (?, ?, ?)"); + v3Session.prepare( + String.format( + "INSERT INTO %s.test (k0, k1, v) values (?, ?, ?)", sessionRule.keyspace())); BatchStatementBuilder builder = BatchStatement.builder(DefaultBatchType.LOGGED); builder.addStatements( @@ -361,7 +366,9 @@ public void should_not_allow_unset_value_when_protocol_less_than_v4() { .unset(2) .build()); - v3Session.execute(builder.build()); + assertThatThrownBy(() -> v3Session.execute(builder.build())) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Unset value at index"); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java index 75748d37a6c..106b2823dc1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.core.cql; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assumptions.assumeThat; import com.datastax.oss.driver.api.core.ConsistencyLevel; @@ -126,19 +127,25 @@ public void setupSchema() { .build()); } - @Test(expected = IllegalStateException.class) + @Test public void should_not_allow_unset_value_when_protocol_less_than_v4() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") .build(); - try (CqlSession v3Session = SessionUtils.newSession(ccmRule, sessionRule.keyspace(), loader)) { - PreparedStatement prepared = v3Session.prepare("INSERT INTO test2 (k, v0) values (?, ?)"); + try (CqlSession v3Session = SessionUtils.newSession(ccmRule, loader)) { + // Intentionally use fully qualified table here to avoid warnings as these are not supported + // by v3 protocol version, see JAVA-3068 + PreparedStatement prepared = + v3Session.prepare( + String.format("INSERT INTO %s.test2 (k, v0) values (?, ?)", sessionRule.keyspace())); BoundStatement boundStatement = prepared.boundStatementBuilder().setString(0, name.getMethodName()).unset(1).build(); - v3Session.execute(boundStatement); + assertThatThrownBy(() -> v3Session.execute(boundStatement)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Unset value at index"); } } From dec8ac9f8d8f2b19d9675310dbda1edf47358874 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 15 Jun 2023 00:10:24 -0500 Subject: [PATCH 250/395] JAVA-3062: Figure out a better solution for PreparedStatementIT tests around JAVA-3058 PreparedStatementIT.java: - Make tests resistant to JVM GC clearing items from prepared statement cache mid-test PreparedStatementCachingIT.java: - Prepared statement tests related to caching - Uses custom session builder and driver context to use strong statement cache - Move to IsolatedTests category because it uses system properties - Consolidate to single invalidationResultSetTest method - Verify exact set of types change events seen - Best-effort check no duplicated type-change/cache-removal events were fired SessionUtils.java - SESSION_BUILDER_CLASS_PROPERTY property should be read dynamically --- .../core/cql/PreparedStatementCachingIT.java | 403 ++++++++++++++++++ .../driver/core/cql/PreparedStatementIT.java | 180 ++------ .../api/testinfra/session/SessionUtils.java | 21 +- 3 files changed, 446 insertions(+), 158 deletions(-) create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java new file mode 100644 index 00000000000..879d4264734 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java @@ -0,0 +1,403 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.cql; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.codahale.metrics.Gauge; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.cql.PrepareRequest; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; +import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; +import com.datastax.oss.driver.api.core.session.SessionBuilder; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.categories.IsolatedTests; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareSyncProcessor; +import com.datastax.oss.driver.internal.core.metadata.schema.events.TypeChangeEvent; +import com.datastax.oss.driver.internal.core.session.BuiltInRequestProcessors; +import com.datastax.oss.driver.internal.core.session.RequestProcessor; +import com.datastax.oss.driver.internal.core.session.RequestProcessorRegistry; +import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; +import com.datastax.oss.driver.shaded.guava.common.cache.RemovalListener; +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// These tests must be isolated because setup modifies SessionUtils.SESSION_BUILDER_CLASS_PROPERTY +@Category(IsolatedTests.class) +public class PreparedStatementCachingIT { + + private CustomCcmRule ccmRule = CustomCcmRule.builder().build(); + + private SessionRule sessionRule = + SessionRule.builder(ccmRule) + .withConfigLoader( + SessionUtils.configLoaderBuilder() + .withInt(DefaultDriverOption.REQUEST_PAGE_SIZE, 2) + .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofSeconds(30)) + .build()) + .build(); + + @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); + + private static class PreparedStatementRemovalEvent { + + private final ByteBuffer queryId; + + public PreparedStatementRemovalEvent(ByteBuffer queryId) { + this.queryId = queryId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof PreparedStatementRemovalEvent)) return false; + PreparedStatementRemovalEvent that = (PreparedStatementRemovalEvent) o; + return Objects.equals(queryId, that.queryId); + } + + @Override + public int hashCode() { + return Objects.hash(queryId); + } + + @Override + public String toString() { + return "PreparedStatementRemovalEvent{" + "queryId=" + queryId + '}'; + } + } + + private static class TestCqlPrepareAsyncProcessor extends CqlPrepareAsyncProcessor { + + private static final Logger LOG = + LoggerFactory.getLogger(PreparedStatementCachingIT.TestCqlPrepareAsyncProcessor.class); + + private static RemovalListener> + buildCacheRemoveCallback(@NonNull Optional context) { + return (evt) -> { + try { + CompletableFuture future = evt.getValue(); + ByteBuffer queryId = Uninterruptibles.getUninterruptibly(future).getId(); + context.ifPresent( + ctx -> ctx.getEventBus().fire(new PreparedStatementRemovalEvent(queryId))); + } catch (Exception e) { + LOG.error("Unable to register removal handler", e); + } + }; + } + + public TestCqlPrepareAsyncProcessor(@NonNull Optional context) { + // Default CqlPrepareAsyncProcessor uses weak values here as well. We avoid doing so + // to prevent cache entries from unexpectedly disappearing mid-test. + super( + CacheBuilder.newBuilder().removalListener(buildCacheRemoveCallback(context)).build(), + context); + } + } + + private static class TestDefaultDriverContext extends DefaultDriverContext { + public TestDefaultDriverContext( + DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { + super(configLoader, programmaticArguments); + } + + @Override + protected RequestProcessorRegistry buildRequestProcessorRegistry() { + // Re-create the processor cache to insert the TestCqlPrepareAsyncProcessor with it's strong + // prepared statement cache, see JAVA-3062 + List> processors = + BuiltInRequestProcessors.createDefaultProcessors(this); + processors.removeIf((processor) -> processor instanceof CqlPrepareAsyncProcessor); + processors.removeIf((processor) -> processor instanceof CqlPrepareSyncProcessor); + CqlPrepareAsyncProcessor asyncProcessor = new TestCqlPrepareAsyncProcessor(Optional.of(this)); + processors.add(2, asyncProcessor); + processors.add(3, new CqlPrepareSyncProcessor(asyncProcessor)); + return new RequestProcessorRegistry( + getSessionName(), processors.toArray(new RequestProcessor[0])); + } + } + + private static class TestSessionBuilder extends SessionBuilder { + + @Override + protected Object wrap(@NonNull CqlSession defaultSession) { + return defaultSession; + } + + @Override + protected DriverContext buildContext( + DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) { + return new TestDefaultDriverContext(configLoader, programmaticArguments); + } + } + + @BeforeClass + public static void setup() { + System.setProperty( + SessionUtils.SESSION_BUILDER_CLASS_PROPERTY, PreparedStatementCachingIT.class.getName()); + } + + @AfterClass + public static void teardown() { + System.clearProperty(SessionUtils.SESSION_BUILDER_CLASS_PROPERTY); + } + + public static SessionBuilder builder() { + return new TestSessionBuilder(); + } + + private void invalidationResultSetTest( + Consumer setupTestSchema, Set expectedChangedTypes) { + invalidationTestInner( + setupTestSchema, + "select f from test_table_1 where e = ?", + "select h from test_table_2 where g = ?", + expectedChangedTypes); + } + + private void invalidationVariableDefsTest( + Consumer setupTestSchema, + boolean isCollection, + Set expectedChangedTypes) { + String condition = isCollection ? "contains ?" : "= ?"; + invalidationTestInner( + setupTestSchema, + String.format("select e from test_table_1 where f %s allow filtering", condition), + String.format("select g from test_table_2 where h %s allow filtering", condition), + expectedChangedTypes); + } + + private void invalidationTestInner( + Consumer setupTestSchema, + String preparedStmtQueryType1, + String preparedStmtQueryType2, + Set expectedChangedTypes) { + + try (CqlSession session = sessionWithCacheSizeMetric()) { + + assertThat(getPreparedCacheSize(session)).isEqualTo(0); + setupTestSchema.accept(session); + + session.prepare(preparedStmtQueryType1); + ByteBuffer queryId2 = session.prepare(preparedStmtQueryType2).getId(); + assertThat(getPreparedCacheSize(session)).isEqualTo(2); + + CountDownLatch preparedStmtCacheRemoveLatch = new CountDownLatch(1); + CountDownLatch typeChangeEventLatch = new CountDownLatch(expectedChangedTypes.size()); + + DefaultDriverContext ctx = (DefaultDriverContext) session.getContext(); + Map changedTypes = new ConcurrentHashMap<>(); + AtomicReference> removedQueryIds = + new AtomicReference<>(Optional.empty()); + AtomicReference> typeChangeEventError = + new AtomicReference<>(Optional.empty()); + AtomicReference> removedQueryEventError = + new AtomicReference<>(Optional.empty()); + ctx.getEventBus() + .register( + TypeChangeEvent.class, + (e) -> { + // expect one event per type changed and for every parent type that nests it + if (Boolean.TRUE.equals( + changedTypes.putIfAbsent(e.oldType.getName().toString(), true))) { + // store an error if we see duplicate change event + // any non-empty error will fail the test so it's OK to do this multiple times + typeChangeEventError.set(Optional.of("Duplicate type change event " + e)); + } + typeChangeEventLatch.countDown(); + }); + ctx.getEventBus() + .register( + PreparedStatementRemovalEvent.class, + (e) -> { + if (!removedQueryIds.compareAndSet(Optional.empty(), Optional.of(e.queryId))) { + // store an error if we see multiple cache invalidation events + // any non-empty error will fail the test so it's OK to do this multiple times + removedQueryEventError.set( + Optional.of("Unable to set reference for PS removal event")); + } + preparedStmtCacheRemoveLatch.countDown(); + }); + + // alter test_type_2 to trigger cache invalidation and above events + session.execute("ALTER TYPE test_type_2 add i blob"); + + // wait for latches and fail if they don't reach zero before timeout + assertThat( + Uninterruptibles.awaitUninterruptibly( + preparedStmtCacheRemoveLatch, 10, TimeUnit.SECONDS)) + .withFailMessage("preparedStmtCacheRemoveLatch did not trigger before timeout") + .isTrue(); + assertThat(Uninterruptibles.awaitUninterruptibly(typeChangeEventLatch, 10, TimeUnit.SECONDS)) + .withFailMessage("typeChangeEventLatch did not trigger before timeout") + .isTrue(); + + /* Okay, the latch triggered so cache processing should now be done. Let's validate :allthethings: */ + assertThat(changedTypes.keySet()).isEqualTo(expectedChangedTypes); + assertThat(removedQueryIds.get()).isNotEmpty().get().isEqualTo(queryId2); + assertThat(getPreparedCacheSize(session)).isEqualTo(1); + + // check no errors were seen in callback (and report those as fail msgs) + // if something is broken these may still succeed due to timing + // but shouldn't intermittently fail if the code is working properly + assertThat(typeChangeEventError.get()) + .withFailMessage(() -> typeChangeEventError.get().get()) + .isEmpty(); + assertThat(removedQueryEventError.get()) + .withFailMessage(() -> removedQueryEventError.get().get()) + .isEmpty(); + } + } + + Consumer setupCacheEntryTestBasic = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); + session.execute("CREATE TABLE test_table_2 (g int primary key, h frozen)"); + }; + + @Test + public void should_invalidate_cache_entry_on_basic_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestBasic, ImmutableSet.of("test_type_2")); + } + + @Test + public void should_invalidate_cache_entry_on_basic_udt_change_variable_defs() { + invalidationVariableDefsTest(setupCacheEntryTestBasic, false, ImmutableSet.of("test_type_2")); + } + + Consumer setupCacheEntryTestCollection = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute( + "CREATE TABLE test_table_1 (e int primary key, f list>)"); + session.execute( + "CREATE TABLE test_table_2 (g int primary key, h list>)"); + }; + + @Test + public void should_invalidate_cache_entry_on_collection_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestCollection, ImmutableSet.of("test_type_2")); + } + + @Test + public void should_invalidate_cache_entry_on_collection_udt_change_variable_defs() { + invalidationVariableDefsTest( + setupCacheEntryTestCollection, true, ImmutableSet.of("test_type_2")); + } + + Consumer setupCacheEntryTestTuple = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute( + "CREATE TABLE test_table_1 (e int primary key, f tuple)"); + session.execute( + "CREATE TABLE test_table_2 (g int primary key, h tuple)"); + }; + + @Test + public void should_invalidate_cache_entry_on_tuple_udt_change_result_set() { + invalidationResultSetTest(setupCacheEntryTestTuple, ImmutableSet.of("test_type_2")); + } + + @Test + public void should_invalidate_cache_entry_on_tuple_udt_change_variable_defs() { + invalidationVariableDefsTest(setupCacheEntryTestTuple, false, ImmutableSet.of("test_type_2")); + } + + Consumer setupCacheEntryTestNested = + (session) -> { + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TYPE test_type_2 (c int, d text)"); + session.execute("CREATE TYPE test_type_3 (e frozen, f int)"); + session.execute("CREATE TYPE test_type_4 (g int, h frozen)"); + session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); + session.execute("CREATE TABLE test_table_2 (g int primary key, h frozen)"); + }; + + @Test + public void should_invalidate_cache_entry_on_nested_udt_change_result_set() { + invalidationResultSetTest( + setupCacheEntryTestNested, ImmutableSet.of("test_type_2", "test_type_4")); + } + + @Test + public void should_invalidate_cache_entry_on_nested_udt_change_variable_defs() { + invalidationVariableDefsTest( + setupCacheEntryTestNested, false, ImmutableSet.of("test_type_2", "test_type_4")); + } + + /* ========================= Infrastructure copied from PreparedStatementIT ========================= */ + private CqlSession sessionWithCacheSizeMetric() { + return SessionUtils.newSession( + ccmRule, + sessionRule.keyspace(), + SessionUtils.configLoaderBuilder() + .withInt(DefaultDriverOption.REQUEST_PAGE_SIZE, 2) + .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofSeconds(30)) + .withStringList( + DefaultDriverOption.METRICS_SESSION_ENABLED, + ImmutableList.of(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE.getPath())) + .build()); + } + + @SuppressWarnings("unchecked") + private static long getPreparedCacheSize(CqlSession session) { + return session + .getMetrics() + .flatMap(metrics -> metrics.getSessionMetric(DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE)) + .map(metric -> ((Gauge) metric).getValue()) + .orElseThrow( + () -> + new AssertionError( + "Could not access metric " + + DefaultSessionMetric.CQL_PREPARED_CACHE_SIZE.getPath())); + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index c3494a6ee96..490158980fb 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -41,20 +41,14 @@ import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; -import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; -import com.datastax.oss.driver.internal.core.metadata.schema.events.TypeChangeEvent; import com.datastax.oss.driver.internal.core.metadata.token.DefaultTokenMap; import com.datastax.oss.driver.internal.core.metadata.token.TokenFactory; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; -import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import com.datastax.oss.protocol.internal.util.Bytes; import com.google.common.collect.ImmutableList; import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.CompletionStage; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; import junit.framework.TestCase; import org.assertj.core.api.AbstractThrowableAssert; import org.junit.Before; @@ -377,9 +371,15 @@ public void should_return_same_instance_when_repreparing_query() { assertThat(getPreparedCacheSize(session)).isEqualTo(0); String query = "SELECT * FROM prepared_statement_test WHERE a = ?"; - // When - PreparedStatement preparedStatement1 = session.prepare(query); - PreparedStatement preparedStatement2 = session.prepare(query); + // Send prepare requests, keep hold of CompletionStage objects to prevent them being removed + // from CqlPrepareAsyncProcessor#cache, see JAVA-3062 + CompletionStage preparedStatement1Future = session.prepareAsync(query); + CompletionStage preparedStatement2Future = session.prepareAsync(query); + + PreparedStatement preparedStatement1 = + CompletableFutures.getUninterruptibly(preparedStatement1Future); + PreparedStatement preparedStatement2 = + CompletableFutures.getUninterruptibly(preparedStatement2Future); // Then assertThat(preparedStatement1).isSameAs(preparedStatement2); @@ -394,11 +394,17 @@ public void should_create_separate_instances_for_differently_formatted_queries() // Given assertThat(getPreparedCacheSize(session)).isEqualTo(0); - // When + // Send prepare requests, keep hold of CompletionStage objects to prevent them being removed + // from CqlPrepareAsyncProcessor#cache, see JAVA-3062 + CompletionStage preparedStatement1Future = + session.prepareAsync("SELECT * FROM prepared_statement_test WHERE a = ?"); + CompletionStage preparedStatement2Future = + session.prepareAsync("select * from prepared_statement_test where a = ?"); + PreparedStatement preparedStatement1 = - session.prepare("SELECT * FROM prepared_statement_test WHERE a = ?"); + CompletableFutures.getUninterruptibly(preparedStatement1Future); PreparedStatement preparedStatement2 = - session.prepare("select * from prepared_statement_test where a = ?"); + CompletableFutures.getUninterruptibly(preparedStatement2Future); // Then assertThat(preparedStatement1).isNotSameAs(preparedStatement2); @@ -414,9 +420,17 @@ public void should_create_separate_instances_for_different_statement_parameters( SimpleStatement statement = SimpleStatement.newInstance("SELECT * FROM prepared_statement_test"); - // When - PreparedStatement preparedStatement1 = session.prepare(statement.setPageSize(1)); - PreparedStatement preparedStatement2 = session.prepare(statement.setPageSize(4)); + // Send prepare requests, keep hold of CompletionStage objects to prevent them being removed + // from CqlPrepareAsyncProcessor#cache, see JAVA-3062 + CompletionStage preparedStatement1Future = + session.prepareAsync(statement.setPageSize(1)); + CompletionStage preparedStatement2Future = + session.prepareAsync(statement.setPageSize(4)); + + PreparedStatement preparedStatement1 = + CompletableFutures.getUninterruptibly(preparedStatement1Future); + PreparedStatement preparedStatement2 = + CompletableFutures.getUninterruptibly(preparedStatement2Future); // Then assertThat(preparedStatement1).isNotSameAs(preparedStatement2); @@ -481,142 +495,6 @@ public void handle_id_changes_on_reprepare() { assertableReprepareAfterIdChange().doesNotThrowAnyException(); } - private void invalidationResultSetTest(Consumer createFn) { - - try (CqlSession session = sessionWithCacheSizeMetric()) { - - assertThat(getPreparedCacheSize(session)).isEqualTo(0); - createFn.accept(session); - - session.prepare("select f from test_table_1 where e = ?"); - session.prepare("select h from test_table_2 where g = ?"); - assertThat(getPreparedCacheSize(session)).isEqualTo(2); - - CountDownLatch latch = new CountDownLatch(1); - DefaultDriverContext ctx = (DefaultDriverContext) session.getContext(); - ctx.getEventBus() - .register( - TypeChangeEvent.class, - (e) -> { - assertThat(e.oldType.getName().toString()).isEqualTo("test_type_2"); - latch.countDown(); - }); - - session.execute("ALTER TYPE test_type_2 add i blob"); - Uninterruptibles.awaitUninterruptibly(latch, 2, TimeUnit.SECONDS); - - assertThat(getPreparedCacheSize(session)).isEqualTo(1); - } - } - - private void invalidationVariableDefsTest(Consumer createFn, boolean isCollection) { - - try (CqlSession session = sessionWithCacheSizeMetric()) { - - assertThat(getPreparedCacheSize(session)).isEqualTo(0); - createFn.accept(session); - - String fStr = isCollection ? "f contains ?" : "f = ?"; - session.prepare(String.format("select e from test_table_1 where %s allow filtering", fStr)); - String hStr = isCollection ? "h contains ?" : "h = ?"; - session.prepare(String.format("select g from test_table_2 where %s allow filtering", hStr)); - assertThat(getPreparedCacheSize(session)).isEqualTo(2); - - CountDownLatch latch = new CountDownLatch(1); - DefaultDriverContext ctx = (DefaultDriverContext) session.getContext(); - ctx.getEventBus() - .register( - TypeChangeEvent.class, - (e) -> { - assertThat(e.oldType.getName().toString()).isEqualTo("test_type_2"); - latch.countDown(); - }); - - session.execute("ALTER TYPE test_type_2 add i blob"); - Uninterruptibles.awaitUninterruptibly(latch, 2, TimeUnit.SECONDS); - - assertThat(getPreparedCacheSize(session)).isEqualTo(1); - } - } - - Consumer setupCacheEntryTestBasic = - (session) -> { - session.execute("CREATE TYPE test_type_1 (a text, b int)"); - session.execute("CREATE TYPE test_type_2 (c int, d text)"); - session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); - session.execute("CREATE TABLE test_table_2 (g int primary key, h frozen)"); - }; - - @Test - public void should_invalidate_cache_entry_on_basic_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestBasic); - } - - @Test - public void should_invalidate_cache_entry_on_basic_udt_change_variable_defs() { - invalidationVariableDefsTest(setupCacheEntryTestBasic, false); - } - - Consumer setupCacheEntryTestCollection = - (session) -> { - session.execute("CREATE TYPE test_type_1 (a text, b int)"); - session.execute("CREATE TYPE test_type_2 (c int, d text)"); - session.execute( - "CREATE TABLE test_table_1 (e int primary key, f list>)"); - session.execute( - "CREATE TABLE test_table_2 (g int primary key, h list>)"); - }; - - @Test - public void should_invalidate_cache_entry_on_collection_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestCollection); - } - - @Test - public void should_invalidate_cache_entry_on_collection_udt_change_variable_defs() { - invalidationVariableDefsTest(setupCacheEntryTestCollection, true); - } - - Consumer setupCacheEntryTestTuple = - (session) -> { - session.execute("CREATE TYPE test_type_1 (a text, b int)"); - session.execute("CREATE TYPE test_type_2 (c int, d text)"); - session.execute( - "CREATE TABLE test_table_1 (e int primary key, f tuple)"); - session.execute( - "CREATE TABLE test_table_2 (g int primary key, h tuple)"); - }; - - @Test - public void should_invalidate_cache_entry_on_tuple_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestTuple); - } - - @Test - public void should_invalidate_cache_entry_on_tuple_udt_change_variable_defs() { - invalidationVariableDefsTest(setupCacheEntryTestTuple, false); - } - - Consumer setupCacheEntryTestNested = - (session) -> { - session.execute("CREATE TYPE test_type_1 (a text, b int)"); - session.execute("CREATE TYPE test_type_2 (c int, d text)"); - session.execute("CREATE TYPE test_type_3 (e frozen, f int)"); - session.execute("CREATE TYPE test_type_4 (g int, h frozen)"); - session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); - session.execute("CREATE TABLE test_table_2 (g int primary key, h frozen)"); - }; - - @Test - public void should_invalidate_cache_entry_on_nested_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestNested); - } - - @Test - public void should_invalidate_cache_entry_on_nested_udt_change_variable_defs() { - invalidationVariableDefsTest(setupCacheEntryTestNested, false); - } - @Test public void should_infer_routing_information_when_partition_key_is_bound() { should_infer_routing_information_when_partition_key_is_bound( diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java index 3b9824698fe..bc4aa0dbb7c 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionUtils.java @@ -61,39 +61,46 @@ * SessionRule} provides a simpler alternative. */ public class SessionUtils { + + public static final String SESSION_BUILDER_CLASS_PROPERTY = "session.builder"; + private static final Logger LOG = LoggerFactory.getLogger(SessionUtils.class); private static final AtomicInteger keyspaceId = new AtomicInteger(); private static final String DEFAULT_SESSION_CLASS_NAME = CqlSession.class.getName(); - private static final String SESSION_BUILDER_CLASS = - System.getProperty("session.builder", DEFAULT_SESSION_CLASS_NAME); + + private static String getSessionBuilderClass() { + return System.getProperty(SESSION_BUILDER_CLASS_PROPERTY, DEFAULT_SESSION_CLASS_NAME); + } @SuppressWarnings("unchecked") public static SessionBuilder baseBuilder() { + String sessionBuilderClass = getSessionBuilderClass(); try { - Class clazz = Class.forName(SESSION_BUILDER_CLASS); + Class clazz = Class.forName(sessionBuilderClass); Method m = clazz.getMethod("builder"); return (SessionBuilder) m.invoke(null); } catch (Exception e) { LOG.warn( "Could not construct SessionBuilder from {} using builder(), using default " + "implementation.", - SESSION_BUILDER_CLASS, + sessionBuilderClass, e); return (SessionBuilder) CqlSession.builder(); } } public static ProgrammaticDriverConfigLoaderBuilder configLoaderBuilder() { + String sessionBuilderClass = getSessionBuilderClass(); try { - Class clazz = Class.forName(SESSION_BUILDER_CLASS); + Class clazz = Class.forName(sessionBuilderClass); Method m = clazz.getMethod("configLoaderBuilder"); return (ProgrammaticDriverConfigLoaderBuilder) m.invoke(null); } catch (Exception e) { - if (!SESSION_BUILDER_CLASS.equals(DEFAULT_SESSION_CLASS_NAME)) { + if (!sessionBuilderClass.equals(DEFAULT_SESSION_CLASS_NAME)) { LOG.warn( "Could not construct ProgrammaticDriverConfigLoaderBuilder from {} using " + "configLoaderBuilder(), using default implementation.", - SESSION_BUILDER_CLASS, + sessionBuilderClass, e); } return DriverConfigLoader.programmaticBuilder(); From 56a480620c3af81a10742b55a73483349876bae6 Mon Sep 17 00:00:00 2001 From: Chris Lin <99268912+chrislin22@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:11:34 -0400 Subject: [PATCH 251/395] fxied typo on branch closing --- .github/workflows/snyk-pr-cleanup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snyk-pr-cleanup.yml b/.github/workflows/snyk-pr-cleanup.yml index 7cf018a59fc..e6866195dcd 100644 --- a/.github/workflows/snyk-pr-cleanup.yml +++ b/.github/workflows/snyk-pr-cleanup.yml @@ -5,7 +5,7 @@ on: types: - closed branches: - - snyk-monitor + - 4.x workflow_dispatch: jobs: From c20e2aee4afdeb20bc6fdeafaae42b67478306b4 Mon Sep 17 00:00:00 2001 From: Chris Lin <99268912+chrislin22@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:36:35 -0400 Subject: [PATCH 252/395] Update .github/workflows/snyk-pr-cleanup.yml Co-authored-by: Madhavan --- .github/workflows/snyk-pr-cleanup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snyk-pr-cleanup.yml b/.github/workflows/snyk-pr-cleanup.yml index e6866195dcd..9c3136bef82 100644 --- a/.github/workflows/snyk-pr-cleanup.yml +++ b/.github/workflows/snyk-pr-cleanup.yml @@ -5,7 +5,7 @@ on: types: - closed branches: - - 4.x + - 4.x workflow_dispatch: jobs: From 1bb721dfb397b81c8e3fc33b738df1358de94ada Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Tue, 6 Jun 2023 18:20:51 -0700 Subject: [PATCH 253/395] JAVA-3042: Support testing against Java17 Add property 'testJavaHome' to specify a different JDK for surefire/failsafe to run tests to facilitate testing with different JDKs. pom.xml: - Add '--add-opens java.base/jdk.internal.util.random=ALL-UNNAMED' as maven-surefire-plugin argLine to support deep reflection for mockito, only loaded for JDK17 Dependency updates: - jacoco-maven-plugin -> 0.8.10, resolves "Error while instrumenting path/to/class" with JDK17 - maven-bundle-plugin -> 5.1.1, resolves java.util.ConcurrentModificationException [FELIX-6259] with JDK17 - blockhound-junit-platform -> 1.0.8.RELEASE, earlier version did not pick up -XX:+AllowRedefinitionToAddDeleteMethods properly Jenkinsfile: - Add matrix axis for JABBER_VERSION for each of JDK8, JDK11, JDK17 - Always run maven with JDK8, use testJavaHome to set JDK version for testing --- Jenkinsfile | 46 ++++++++++++++++++++++++------ core/pom.xml | 2 ++ integration-tests/pom.xml | 15 ++-------- mapper-runtime/pom.xml | 1 + osgi-tests/pom.xml | 2 ++ pom.xml | 59 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 100 insertions(+), 25 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1859ceb7689..3ecb70e0d30 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -18,6 +18,24 @@ def initializeEnvironment() { env.MAVEN_HOME = "${env.HOME}/.mvn/apache-maven-3.3.9" env.PATH = "${env.MAVEN_HOME}/bin:${env.PATH}" + + /* + * As of JAVA-3042 JAVA_HOME is always set to JDK8 and this is currently necessary for mvn compile and DSE Search/Graph. + * To facilitate testing with JDK11/17 we feed the appropriate JAVA_HOME into the maven build via commandline. + * + * Maven command-line flags: + * - -DtestJavaHome=/path/to/java/home: overrides JAVA_HOME for surefire/failsafe tests, defaults to environment JAVA_HOME. + * - -Ptest-jdk-N: enables profile for running tests with a specific JDK version (substitute N for 8/11/17). + * + * Note test-jdk-N is also automatically loaded based off JAVA_HOME SDK version so testing with an older SDK is not supported. + * + * Environment variables: + * - JAVA_HOME: Path to JDK used for mvn (all steps except surefire/failsafe), Cassandra, DSE. + * - JAVA8_HOME: Path to JDK8 used for Cassandra/DSE if ccm determines JAVA_HOME is not compatible with the chosen backend. + * - TEST_JAVA_HOME: PATH to JDK used for surefire/failsafe testing. + * - TEST_JAVA_VERSION: TEST_JAVA_HOME SDK version number [8/11/17], used to configure test-jdk-N profile in maven (see above) + */ + env.JAVA_HOME = sh(label: 'Get JAVA_HOME',script: '''#!/bin/bash -le . ${JABBA_SHELL} jabba which ${JABBA_VERSION}''', returnStdout: true).trim() @@ -25,9 +43,15 @@ def initializeEnvironment() { . ${JABBA_SHELL} jabba which 1.8''', returnStdout: true).trim() + env.TEST_JAVA_HOME = sh(label: 'Get TEST_JAVA_HOME',script: '''#!/bin/bash -le + . ${JABBA_SHELL} + jabba which ${JABBA_VERSION}''', returnStdout: true).trim() + env.TEST_JAVA_VERSION = sh(label: 'Get TEST_JAVA_VERSION',script: '''#!/bin/bash -le + echo "${JABBA_VERSION##*.}"''', returnStdout: true).trim() + sh label: 'Download Apache CassandraⓇ or DataStax Enterprise',script: '''#!/bin/bash -le . ${JABBA_SHELL} - jabba use ${JABBA_VERSION} + jabba use 1.8 . ${CCM_ENVIRONMENT_SHELL} ${SERVER_VERSION} ''' @@ -53,7 +77,7 @@ ENVIRONMENT_EOF set +o allexport . ${JABBA_SHELL} - jabba use ${JABBA_VERSION} + jabba use 1.8 java -version mvn -v @@ -80,7 +104,7 @@ def executeTests() { set +o allexport . ${JABBA_SHELL} - jabba use ${JABBA_VERSION} + jabba use 1.8 if [ "${JABBA_VERSION}" != "1.8" ]; then SKIP_JAVADOCS=true @@ -94,7 +118,9 @@ def executeTests() { fi printenv | sort - mvn -B -V ${INTEGRATION_TESTS_FILTER_ARGUMENT} verify \ + mvn -B -V ${INTEGRATION_TESTS_FILTER_ARGUMENT} -T 1 verify \ + -Ptest-jdk-${TEST_JAVA_VERSION} \ + -DtestJavaHome=${TEST_JAVA_HOME} \ -DfailIfNoTests=false \ -Dmaven.test.failure.ignore=true \ -Dmaven.javadoc.skip=${SKIP_JAVADOCS} \ @@ -403,15 +429,17 @@ pipeline { '4.0', // Development Apache CassandraⓇ 'dse-6.8.30' // Current DataStax Enterprise } + axis { + name 'JABBA_VERSION' + values '1.8', // jdk8 + 'openjdk@1.11', // jdk11 + 'openjdk@1.17' // jdk17 + } } agent { label "${OS_VERSION}" } - environment { - // Per-commit builds are only going to run against JDK8 - JABBA_VERSION = '1.8' - } stages { stage('Initialize-Environment') { @@ -431,7 +459,7 @@ pipeline { } stage('Build-Driver') { steps { - buildDriver(env.JABBA_VERSION) + buildDriver('default') } } stage('Execute-Tests') { diff --git a/core/pom.xml b/core/pom.xml index d78ff6a3f02..db2af9ed156 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -248,6 +248,8 @@ maven-surefire-plugin + ${testing.jvm}/bin/java + ${mockitoopens.argline} 1 diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 112ac7e73bc..16b900a0fb2 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -229,6 +229,7 @@ integration-test + ${testing.jvm}/bin/java com.datastax.oss.driver.categories.ParallelizableTests classes 8 @@ -245,6 +246,7 @@ com.datastax.oss.driver.categories.ParallelizableTests, com.datastax.oss.driver.categories.IsolatedTests ${project.build.directory}/failsafe-reports/failsafe-summary-serial.xml ${skipSerialITs} + ${testing.jvm}/bin/java @@ -260,6 +262,7 @@ ${project.build.directory}/failsafe-reports/failsafe-summary-isolated.xml ${skipIsolatedITs} ${blockhound.argline} + ${testing.jvm}/bin/java @@ -322,16 +325,4 @@ - - - jdk 13+ - - [13,) - - - - -XX:+AllowRedefinitionToAddDeleteMethods - - - diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 2e5f74f83b7..b98fd5028c1 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -122,6 +122,7 @@ maven-surefire-plugin + ${testing.jvm}/bin/java 1 diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index c1aebc6718b..cfa28c25dba 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -220,6 +220,7 @@ maven-surefire-plugin + ${testing.jvm}/bin/java ${project.basedir}/src/test/resources/logback-test.xml @@ -237,6 +238,7 @@ + ${testing.jvm}/bin/java ${project.basedir}/src/test/resources/logback-test.xml diff --git a/pom.xml b/pom.xml index b56f22d6454..eae8a54ac55 100644 --- a/pom.xml +++ b/pom.xml @@ -433,12 +433,12 @@ io.projectreactor.tools blockhound - 1.0.4.RELEASE + 1.0.8.RELEASE io.projectreactor.tools blockhound-junit-platform - 1.0.4.RELEASE + 1.0.8.RELEASE @@ -533,12 +533,12 @@ org.jacoco jacoco-maven-plugin - 0.8.5 + 0.8.10 org.apache.felix maven-bundle-plugin - 4.2.1 + 5.1.1 org.revapi @@ -936,6 +936,57 @@ height="0" width="0" style="display:none;visibility:hidden"> true + + + test-jdk-environment + + + !testJavaHome + + + + ${env.JAVA_HOME} + + + + + test-jdk-specified + + + testJavaHome + + + + ${testJavaHome} + + + + + test-jdk-8 + + [8,) + + + + + test-jdk-11 + + [11,) + + + + + test-jdk-17 + + [17,) + + + + -XX:+AllowRedefinitionToAddDeleteMethods + + --add-opens java.base/jdk.internal.util.random=ALL-UNNAMED + + From a572d5f6ac0adeb07d0b4b0fae90cbcb3b22a9b4 Mon Sep 17 00:00:00 2001 From: Dom Del Nano Date: Fri, 7 Jul 2023 15:32:52 -0700 Subject: [PATCH 254/395] Update native protocol documentation to use a valid (capitalized) protocol version (#1637) --- manual/core/native_protocol/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index d64aaccda85..b28c72f6300 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -62,7 +62,8 @@ the [configuration](../configuration/): ``` datastax-java-driver { advanced.protocol { - version = v3 + # The V in the version parameter must be capitalized + version = V3 } } ``` From fc79bb7ae57a3c1fbd9500418402a4bbec0d6665 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 7 Jul 2023 17:40:04 -0500 Subject: [PATCH 255/395] Follow-up to previous commit --- .../core/DefaultProtocolVersionRegistryTest.java | 10 ++++++++++ manual/core/native_protocol/README.md | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java index 9d81a3bdd3d..0bf571da20c 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java @@ -24,6 +24,7 @@ import static com.datastax.oss.driver.internal.core.DefaultProtocolFeature.DATE_TYPE; import static com.datastax.oss.driver.internal.core.DefaultProtocolFeature.SMALLINT_AND_TINYINT_TYPES; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.datastax.dse.driver.api.core.DseProtocolVersion; import com.datastax.dse.driver.api.core.metadata.DseNodeProperties; @@ -51,6 +52,15 @@ public void should_find_version_by_name() { assertThat(registry.fromName("DSE_V1")).isEqualTo(DseProtocolVersion.DSE_V1); } + + @Test + public void should_fail_to_find_version_by_name_different_case() { + assertThatThrownBy(() -> registry.fromName("v4")).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> registry.fromName("dse_v1")).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> registry.fromName("dDSE_v1")).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> registry.fromName("dse_v1")).isInstanceOf(IllegalArgumentException.class); + } + @Test public void should_downgrade_if_lower_version_available() { Optional downgraded = registry.downgrade(V4); diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index b28c72f6300..2bc075be3be 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -62,12 +62,14 @@ the [configuration](../configuration/): ``` datastax-java-driver { advanced.protocol { - # The V in the version parameter must be capitalized version = V3 } } ``` +Note that the protocol version you specify above is case sensitive so make sure to only use uppercase letters. +"V3" is correct, "v3" is not. + If you force a version that is too high for the server, you'll get an error: ``` From e2fb42d82949dfb161809ef3c2d5d563419cee24 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 7 Jul 2023 23:17:05 -0500 Subject: [PATCH 256/395] JAVA-3061 Re-introduce an improved CqlVector, add support for accessing vectors directly as float arrays (#1666) --- core/revapi.json | 65 +++++- .../oss/driver/api/core/data/CqlVector.java | 193 +++++++++++++++++ .../driver/api/core/data/GettableById.java | 2 +- .../driver/api/core/data/GettableByIndex.java | 5 +- .../driver/api/core/data/GettableByName.java | 4 +- .../driver/api/core/data/SettableById.java | 4 +- .../driver/api/core/data/SettableByIndex.java | 6 +- .../driver/api/core/data/SettableByName.java | 6 +- .../api/core/type/codec/ExtraTypeCodecs.java | 8 + .../api/core/type/codec/TypeCodecs.java | 8 +- .../api/core/type/reflect/GenericType.java | 18 ++ .../internal/core/type/codec/VectorCodec.java | 38 ++-- .../vector/AbstractVectorToArrayCodec.java | 140 +++++++++++++ .../vector/FloatVectorToArrayCodec.java | 105 ++++++++++ .../codec/registry/CachingCodecRegistry.java | 83 +++++++- .../driver/api/core/data/CqlVectorTest.java | 198 ++++++++++++++++++ .../core/type/codec/VectorCodecTest.java | 26 +-- ...CachingCodecRegistryTestDataProviders.java | 50 +++++ 18 files changed, 901 insertions(+), 58 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/AbstractVectorToArrayCodec.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/FloatVectorToArrayCodec.java create mode 100644 core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java diff --git a/core/revapi.json b/core/revapi.json index f844479cd29..63e2cef5a1e 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -6887,7 +6887,70 @@ "code": "java.method.removed", "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", "justification": "Refactoring in JAVA-3061" - } + }, + { + "code": "java.class.removed", + "old": "class com.datastax.oss.driver.api.core.data.CqlVector.Builder", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.removed", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector.Builder com.datastax.oss.driver.api.core.data.CqlVector::builder()", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.removed", + "old": "method java.lang.Iterable com.datastax.oss.driver.api.core.data.CqlVector::getValues()", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "class com.datastax.oss.driver.api.core.data.CqlVector", + "new": "class com.datastax.oss.driver.api.core.data.CqlVector", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.parameterTypeChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(===com.datastax.oss.driver.api.core.type.CqlVectorType===, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(===com.datastax.oss.driver.api.core.type.VectorType===, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.CqlVectorType, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "new": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.CqlVectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.CqlVectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(===com.datastax.oss.driver.api.core.type.reflect.GenericType===)", + "new": "parameter com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(===com.datastax.oss.driver.api.core.type.reflect.GenericType===)", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "justification": "Refactorings in PR 1666" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "justification": "Refactorings in PR 1666" + } ] } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java new file mode 100644 index 00000000000..152d0f40823 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java @@ -0,0 +1,193 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.data; + +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; +import com.datastax.oss.driver.shaded.guava.common.base.Predicates; +import com.datastax.oss.driver.shaded.guava.common.base.Splitter; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; +import com.datastax.oss.driver.shaded.guava.common.collect.Streams; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Representation of a vector as defined in CQL. + * + *

    A CQL vector is a fixed-length array of non-null numeric values. These properties don't map + * cleanly to an existing class in the standard JDK Collections hierarchy so we provide this value + * object instead. Like other value object collections returned by the driver instances of this + * class are not immutable; think of these value objects as a representation of a vector stored in + * the database as an initial step in some additional computation. + * + *

    While we don't implement any Collection APIs we do implement Iterable. We also attempt to play + * nice with the Streams API in order to better facilitate integration with data pipelines. Finally, + * where possible we've tried to make the API of this class similar to the equivalent methods on + * {@link List}. + */ +public class CqlVector implements Iterable { + + /** + * Create a new CqlVector containing the specified values. + * + * @param vals the collection of values to wrap. + * @return a CqlVector wrapping those values + */ + public static CqlVector newInstance(V... vals) { + + // Note that Array.asList() guarantees the return of an array which implements RandomAccess + return new CqlVector(Arrays.asList(vals)); + } + + /** + * Create a new CqlVector that "wraps" an existing ArrayList. Modifications to the passed + * ArrayList will also be reflected in the returned CqlVector. + * + * @param list the collection of values to wrap. + * @return a CqlVector wrapping those values + */ + public static CqlVector newInstance(List list) { + Preconditions.checkArgument(list != null, "Input list should not be null"); + return new CqlVector(list); + } + + /** + * Create a new CqlVector instance from the specified string representation. Note that this method + * is intended to mirror {@link #toString()}; passing this method the output from a toString + * call on some CqlVector should return a CqlVector that is equal to the origin instance. + * + * @param str a String representation of a CqlVector + * @param subtypeCodec + * @return a new CqlVector built from the String representation + */ + public static CqlVector from( + @NonNull String str, @NonNull TypeCodec subtypeCodec) { + Preconditions.checkArgument(str != null, "Cannot create CqlVector from null string"); + Preconditions.checkArgument(!str.isEmpty(), "Cannot create CqlVector from empty string"); + ArrayList vals = + Streams.stream(Splitter.on(", ").split(str.substring(1, str.length() - 1))) + .map(subtypeCodec::parse) + .collect(Collectors.toCollection(ArrayList::new)); + return new CqlVector(vals); + } + + private final List list; + + private CqlVector(@NonNull List list) { + + Preconditions.checkArgument( + Iterables.all(list, Predicates.notNull()), "CqlVectors cannot contain null values"); + this.list = list; + } + + /** + * Retrieve the value at the specified index. Modelled after {@link List#get(int)} + * + * @param idx the index to retrieve + * @return the value at the specified index + */ + public T get(int idx) { + return list.get(idx); + } + + /** + * Update the value at the specified index. Modelled after {@link List#set(int, Object)} + * + * @param idx the index to set + * @param val the new value for the specified index + * @return the old value for the specified index + */ + public T set(int idx, T val) { + return list.set(idx, val); + } + + /** + * Return the size of this vector. Modelled after {@link List#size()} + * + * @return the vector size + */ + public int size() { + return this.list.size(); + } + + /** + * Return a CqlVector consisting of the contents of a portion of this vector. Modelled after + * {@link List#subList(int, int)} + * + * @param from the index to start from (inclusive) + * @param to the index to end on (exclusive) + * @return a new CqlVector wrapping the sublist + */ + public CqlVector subVector(int from, int to) { + return new CqlVector(this.list.subList(from, to)); + } + + /** + * Return a boolean indicating whether the vector is empty. Modelled after {@link List#isEmpty()} + * + * @return true if the list is empty, false otherwise + */ + public boolean isEmpty() { + return this.list.isEmpty(); + } + + /** + * Create an {@link Iterator} for this vector + * + * @return the generated iterator + */ + @Override + public Iterator iterator() { + return this.list.iterator(); + } + + /** + * Create a {@link Stream} of the values in this vector + * + * @return the Stream instance + */ + public Stream stream() { + return this.list.stream(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof CqlVector) { + CqlVector that = (CqlVector) o; + return this.list.equals(that.list); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(list); + } + + @Override + public String toString() { + return Iterables.toString(this.list); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java index 6c6cf95a568..1b4197667e9 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java @@ -529,7 +529,7 @@ default CqlDuration getCqlDuration(@NonNull CqlIdentifier id) { * @throws IllegalArgumentException if the id is invalid. */ @Nullable - default List getVector( + default CqlVector getVector( @NonNull CqlIdentifier id, @NonNull Class elementsClass) { return getVector(firstIndexOf(id), elementsClass); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java index a805342defc..0efb003ca24 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java @@ -444,8 +444,9 @@ default CqlDuration getCqlDuration(int i) { * @throws IndexOutOfBoundsException if the index is invalid. */ @Nullable - default List getVector(int i, @NonNull Class elementsClass) { - return get(i, GenericType.listOf(elementsClass)); + default CqlVector getVector( + int i, @NonNull Class elementsClass) { + return get(i, GenericType.vectorOf(elementsClass)); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java index 3214994c04a..377f8292002 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java @@ -525,9 +525,9 @@ default CqlDuration getCqlDuration(@NonNull String name) { * @throws IllegalArgumentException if the name is invalid. */ @Nullable - default List getVector( + default CqlVector getVector( @NonNull String name, @NonNull Class elementsClass) { - return getList(firstIndexOf(name), elementsClass); + return getVector(firstIndexOf(name), elementsClass); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java index 3c17f0cb6f1..84055b0e964 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java @@ -571,9 +571,9 @@ default SelfT setCqlDuration(@NonNull CqlIdentifier id, @Nullable CqlDuration v) */ @NonNull @CheckReturnValue - default SelfT setVector( + default SelfT setVector( @NonNull CqlIdentifier id, - @Nullable List v, + @Nullable CqlVector v, @NonNull Class elementsClass) { SelfT result = null; for (Integer i : allIndicesOf(id)) { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java index 52bc92d4c09..01e6d5cdf58 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java @@ -423,9 +423,9 @@ default SelfT setCqlDuration(int i, @Nullable CqlDuration v) { */ @NonNull @CheckReturnValue - default SelfT setVector( - int i, @Nullable List v, @NonNull Class elementsClass) { - return set(i, v, GenericType.listOf(elementsClass)); + default SelfT setVector( + int i, @Nullable CqlVector v, @NonNull Class elementsClass) { + return set(i, v, GenericType.vectorOf(elementsClass)); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java index 559ad40cbff..a78753789e3 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java @@ -570,8 +570,10 @@ default SelfT setCqlDuration(@NonNull String name, @Nullable CqlDuration v) { */ @NonNull @CheckReturnValue - default SelfT setVector( - @NonNull String name, @Nullable List v, @NonNull Class elementsClass) { + default SelfT setVector( + @NonNull String name, + @Nullable CqlVector v, + @NonNull Class elementsClass) { SelfT result = null; for (Integer i : allIndicesOf(name)) { result = (result == null ? this : result).setVector(i, v, elementsClass); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.java index 6bf044ebf03..65571e01f75 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.java @@ -16,8 +16,10 @@ package com.datastax.oss.driver.api.core.type.codec; import com.datastax.oss.driver.api.core.session.SessionBuilder; +import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.internal.core.type.DefaultVectorType; import com.datastax.oss.driver.internal.core.type.codec.SimpleBlobCodec; import com.datastax.oss.driver.internal.core.type.codec.TimestampCodec; import com.datastax.oss.driver.internal.core.type.codec.extras.OptionalCodec; @@ -36,6 +38,7 @@ import com.datastax.oss.driver.internal.core.type.codec.extras.time.PersistentZonedTimestampCodec; import com.datastax.oss.driver.internal.core.type.codec.extras.time.TimestampMillisCodec; import com.datastax.oss.driver.internal.core.type.codec.extras.time.ZonedTimestampCodec; +import com.datastax.oss.driver.internal.core.type.codec.extras.vector.FloatVectorToArrayCodec; import com.fasterxml.jackson.databind.ObjectMapper; import edu.umd.cs.findbugs.annotations.NonNull; import java.nio.ByteBuffer; @@ -479,4 +482,9 @@ public static TypeCodec json( @NonNull Class javaType, @NonNull ObjectMapper objectMapper) { return new JsonCodec<>(javaType, objectMapper); } + + /** Builds a new codec that maps CQL float vectors of the specified size to an array of floats. */ + public static TypeCodec floatVectorToArray(int dimensions) { + return new FloatVectorToArrayCodec(new DefaultVectorType(DataTypes.FLOAT, dimensions)); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java index e824e7f41fc..d4cf3ddb0c0 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.api.core.type.codec; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.CustomType; @@ -207,12 +208,17 @@ public static TypeCodec tupleOf(@NonNull TupleType cqlType) { return new TupleCodec(cqlType); } - public static TypeCodec> vectorOf( + public static TypeCodec> vectorOf( @NonNull VectorType type, @NonNull TypeCodec subtypeCodec) { return new VectorCodec( DataTypes.vectorOf(subtypeCodec.getCqlType(), type.getDimensions()), subtypeCodec); } + public static TypeCodec> vectorOf( + int dimensions, @NonNull TypeCodec subtypeCodec) { + return new VectorCodec(DataTypes.vectorOf(subtypeCodec.getCqlType(), dimensions), subtypeCodec); + } + /** * Builds a new codec that maps a CQL user defined type to the driver's {@link UdtValue}, for the * given type definition. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java index a1977e39f23..350e869ae52 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.api.core.type.reflect; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.GettableByIndex; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; @@ -147,6 +148,23 @@ public static GenericType> setOf(@NonNull GenericType elementType) return new GenericType<>(token); } + @NonNull + public static GenericType> vectorOf( + @NonNull Class elementType) { + TypeToken> token = + new TypeToken>() {}.where( + new TypeParameter() {}, TypeToken.of(elementType)); + return new GenericType<>(token); + } + + @NonNull + public static GenericType> vectorOf( + @NonNull GenericType elementType) { + TypeToken> token = + new TypeToken>() {}.where(new TypeParameter() {}, elementType.token); + return new GenericType<>(token); + } + @NonNull public static GenericType> mapOf( @NonNull Class keyType, @NonNull Class valueType) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java index 75b3e46ddfd..a94ae728725 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java @@ -16,13 +16,13 @@ package com.datastax.oss.driver.internal.core.type.codec; import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.VectorType; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.reflect.GenericType; -import com.datastax.oss.driver.shaded.guava.common.base.Splitter; +import com.datastax.oss.driver.internal.core.type.DefaultVectorType; import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; -import com.datastax.oss.driver.shaded.guava.common.collect.Streams; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; @@ -30,23 +30,26 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; -import java.util.stream.Collectors; -public class VectorCodec implements TypeCodec> { +public class VectorCodec implements TypeCodec> { private final VectorType cqlType; - private final GenericType> javaType; + private final GenericType> javaType; private final TypeCodec subtypeCodec; - public VectorCodec(VectorType cqlType, TypeCodec subtypeCodec) { + public VectorCodec(@NonNull VectorType cqlType, @NonNull TypeCodec subtypeCodec) { this.cqlType = cqlType; this.subtypeCodec = subtypeCodec; - this.javaType = GenericType.listOf(subtypeCodec.getJavaType()); + this.javaType = GenericType.vectorOf(subtypeCodec.getJavaType()); + } + + public VectorCodec(int dimensions, @NonNull TypeCodec subtypeCodec) { + this(new DefaultVectorType(subtypeCodec.getCqlType(), dimensions), subtypeCodec); } @NonNull @Override - public GenericType> getJavaType() { + public GenericType> getJavaType() { return this.javaType; } @@ -59,7 +62,7 @@ public DataType getCqlType() { @Nullable @Override public ByteBuffer encode( - @Nullable List value, @NonNull ProtocolVersion protocolVersion) { + @Nullable CqlVector value, @NonNull ProtocolVersion protocolVersion) { if (value == null || cqlType.getDimensions() <= 0) { return null; } @@ -103,7 +106,7 @@ public ByteBuffer encode( @Nullable @Override - public List decode( + public CqlVector decode( @Nullable ByteBuffer bytes, @NonNull ProtocolVersion protocolVersion) { if (bytes == null || bytes.remaining() == 0) { return null; @@ -133,27 +136,20 @@ Elements should at least precede themselves with their size (along the lines of /* Restore the input ByteBuffer to its original state */ bytes.rewind(); - return rv; + return CqlVector.newInstance(rv); } @NonNull @Override - public String format(@Nullable List value) { + public String format(@Nullable CqlVector value) { return value == null ? "NULL" : Iterables.toString(value); } @Nullable @Override - public List parse(@Nullable String value) { + public CqlVector parse(@Nullable String value) { return (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL")) ? null - : this.from(value); - } - - private List from(@Nullable String value) { - - return Streams.stream(Splitter.on(", ").split(value.substring(1, value.length() - 1))) - .map(subtypeCodec::parse) - .collect(Collectors.toCollection(ArrayList::new)); + : CqlVector.from(value, this.subtypeCodec); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/AbstractVectorToArrayCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/AbstractVectorToArrayCodec.java new file mode 100644 index 00000000000..79db9f6bc8a --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/AbstractVectorToArrayCodec.java @@ -0,0 +1,140 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type.codec.extras.vector; + +import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.VectorType; +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.util.Objects; + +/** Common super-class for all codecs which map a CQL vector type onto a primitive array */ +public abstract class AbstractVectorToArrayCodec implements TypeCodec { + + @NonNull protected final VectorType cqlType; + @NonNull protected final GenericType javaType; + + /** + * @param cqlType The CQL type. Must be a list type. + * @param arrayType The Java type. Must be an array class. + */ + protected AbstractVectorToArrayCodec( + @NonNull VectorType cqlType, @NonNull GenericType arrayType) { + this.cqlType = Objects.requireNonNull(cqlType, "cqlType cannot be null"); + this.javaType = Objects.requireNonNull(arrayType, "arrayType cannot be null"); + if (!arrayType.isArray()) { + throw new IllegalArgumentException("Expecting Java array class, got " + arrayType); + } + } + + @NonNull + @Override + public GenericType getJavaType() { + return this.javaType; + } + + @NonNull + @Override + public DataType getCqlType() { + return this.cqlType; + } + + @Nullable + @Override + public ByteBuffer encode(@Nullable ArrayT array, @NonNull ProtocolVersion protocolVersion) { + if (array == null) { + return null; + } + int length = Array.getLength(array); + int totalSize = length * sizeOfComponentType(); + ByteBuffer output = ByteBuffer.allocate(totalSize); + for (int i = 0; i < length; i++) { + serializeElement(output, array, i, protocolVersion); + } + output.flip(); + return output; + } + + @Nullable + @Override + public ArrayT decode(@Nullable ByteBuffer bytes, @NonNull ProtocolVersion protocolVersion) { + if (bytes == null || bytes.remaining() == 0) { + throw new IllegalArgumentException( + "Input ByteBuffer must not be null and must have non-zero remaining bytes"); + } + ByteBuffer input = bytes.duplicate(); + int length = this.cqlType.getDimensions(); + int elementSize = sizeOfComponentType(); + ArrayT array = newInstance(); + for (int i = 0; i < length; i++) { + // Null elements can happen on the decode path, but we cannot tolerate them + if (elementSize < 0) { + throw new NullPointerException("Primitive arrays cannot store null elements"); + } else { + deserializeElement(input, array, i, protocolVersion); + } + } + return array; + } + + /** + * Creates a new array instance with a size matching the specified vector. + * + * @return a new array instance with a size matching the specified vector. + */ + @NonNull + protected abstract ArrayT newInstance(); + + /** + * Return the size in bytes of the array component type. + * + * @return the size in bytes of the array component type. + */ + protected abstract int sizeOfComponentType(); + + /** + * Write the {@code index}th element of {@code array} to {@code output}. + * + * @param output The ByteBuffer to write to. + * @param array The array to read from. + * @param index The element index. + * @param protocolVersion The protocol version to use. + */ + protected abstract void serializeElement( + @NonNull ByteBuffer output, + @NonNull ArrayT array, + int index, + @NonNull ProtocolVersion protocolVersion); + + /** + * Read the {@code index}th element of {@code array} from {@code input}. + * + * @param input The ByteBuffer to read from. + * @param array The array to write to. + * @param index The element index. + * @param protocolVersion The protocol version to use. + */ + protected abstract void deserializeElement( + @NonNull ByteBuffer input, + @NonNull ArrayT array, + int index, + @NonNull ProtocolVersion protocolVersion); +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/FloatVectorToArrayCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/FloatVectorToArrayCodec.java new file mode 100644 index 00000000000..80c035e96d3 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/vector/FloatVectorToArrayCodec.java @@ -0,0 +1,105 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type.codec.extras.vector; + +import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.type.VectorType; +import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.internal.core.type.codec.FloatCodec; +import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; +import com.datastax.oss.driver.shaded.guava.common.base.Splitter; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Objects; + +/** A codec that maps CQL vectors to the Java type {@code float[]}. */ +public class FloatVectorToArrayCodec extends AbstractVectorToArrayCodec { + + public FloatVectorToArrayCodec(VectorType type) { + super(type, GenericType.of(float[].class)); + } + + @Override + public boolean accepts(@NonNull Class javaClass) { + Objects.requireNonNull(javaClass); + return float[].class.equals(javaClass); + } + + @Override + public boolean accepts(@NonNull Object value) { + Objects.requireNonNull(value); + return value instanceof float[]; + } + + @NonNull + @Override + protected float[] newInstance() { + return new float[cqlType.getDimensions()]; + } + + @Override + protected int sizeOfComponentType() { + return 4; + } + + @Override + protected void serializeElement( + @NonNull ByteBuffer output, + @NonNull float[] array, + int index, + @NonNull ProtocolVersion protocolVersion) { + output.putFloat(array[index]); + } + + @Override + protected void deserializeElement( + @NonNull ByteBuffer input, + @NonNull float[] array, + int index, + @NonNull ProtocolVersion protocolVersion) { + array[index] = input.getFloat(); + } + + @NonNull + @Override + public String format(@Nullable float[] value) { + return value == null ? "NULL" : Arrays.toString(value); + } + + @Nullable + @Override + public float[] parse(@Nullable String str) { + Preconditions.checkArgument(str != null, "Cannot create float array from null string"); + Preconditions.checkArgument(!str.isEmpty(), "Cannot create float array from empty string"); + + FloatCodec codec = new FloatCodec(); + float[] rv = this.newInstance(); + Iterator strIter = + Splitter.on(", ").trimResults().split(str.substring(1, str.length() - 1)).iterator(); + for (int i = 0; i < rv.length; ++i) { + String strVal = strIter.next(); + if (strVal == null) { + throw new IllegalArgumentException("Null element observed in float array string"); + } + Float f = codec.parse(strVal); + rv[i] = f.floatValue(); + } + return rv; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java index ca282c3e355..cb5d45255e1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java @@ -16,6 +16,7 @@ package com.datastax.oss.driver.internal.core.type.codec.registry; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.*; @@ -371,6 +372,23 @@ protected GenericType inspectType(@NonNull Object value, @Nullable DataType c inspectType(firstValue, cqlType == null ? null : ((MapType) cqlType).getValueType()); return GenericType.mapOf(keyType, valueType); } + } else if (value instanceof CqlVector) { + CqlVector vector = (CqlVector) value; + if (vector.isEmpty()) { + return cqlType == null ? JAVA_TYPE_FOR_EMPTY_CQLVECTORS : inferJavaTypeFromCqlType(cqlType); + } else { + Object firstElement = vector.iterator().next(); + if (firstElement == null) { + throw new IllegalArgumentException( + "Can't infer vector codec because the first element is null " + + "(note that CQL does not allow null values in collections)"); + } + GenericType elementType = + (GenericType) + inspectType( + firstElement, cqlType == null ? null : ((VectorType) cqlType).getElementType()); + return GenericType.vectorOf(elementType); + } } else { // There's not much more we can do return GenericType.of(value.getClass()); @@ -390,6 +408,11 @@ protected GenericType inferJavaTypeFromCqlType(@NonNull DataType cqlType) { DataType valueType = ((MapType) cqlType).getValueType(); return GenericType.mapOf( inferJavaTypeFromCqlType(keyType), inferJavaTypeFromCqlType(valueType)); + } else if (cqlType instanceof VectorType) { + DataType elementType = ((VectorType) cqlType).getElementType(); + GenericType numberType = + (GenericType) inferJavaTypeFromCqlType(elementType); + return GenericType.vectorOf(numberType); } switch (cqlType.getProtocolCode()) { case ProtocolConstants.DataType.CUSTOM: @@ -492,6 +515,22 @@ protected DataType inferCqlTypeFromValue(@NonNull Object value) { return null; } return DataTypes.mapOf(keyType, valueType); + } else if (value instanceof CqlVector) { + CqlVector vector = (CqlVector) value; + if (vector.isEmpty()) { + return CQL_TYPE_FOR_EMPTY_VECTORS; + } + Object firstElement = vector.iterator().next(); + if (firstElement == null) { + throw new IllegalArgumentException( + "Can't infer vector codec because the first element is null " + + "(note that CQL does not allow null values in collections)"); + } + DataType elementType = inferCqlTypeFromValue(firstElement); + if (elementType == null) { + return null; + } + return DataTypes.vectorOf(elementType, vector.size()); } Class javaClass = value.getClass(); if (ByteBuffer.class.isAssignableFrom(javaClass)) { @@ -538,7 +577,7 @@ protected DataType inferCqlTypeFromValue(@NonNull Object value) { return null; } - private TypeCodec getElementCodec( + private TypeCodec getElementCodecForCqlAndJavaType( ContainerType cqlType, TypeToken token, boolean isJavaCovariant) { DataType elementCqlType = cqlType.getElementType(); @@ -550,6 +589,14 @@ private TypeCodec getElementCodec( return codecFor(elementCqlType); } + private TypeCodec getElementCodecForJavaType( + ParameterizedType parameterizedType, boolean isJavaCovariant) { + + Type[] typeArguments = parameterizedType.getActualTypeArguments(); + GenericType elementType = GenericType.of(typeArguments[0]); + return codecFor(elementType, isJavaCovariant); + } + // Try to create a codec when we haven't found it in the cache @NonNull protected TypeCodec createCodec( @@ -565,11 +612,11 @@ protected TypeCodec createCodec( TypeToken token = javaType.__getToken(); if (cqlType instanceof ListType && List.class.isAssignableFrom(token.getRawType())) { TypeCodec elementCodec = - getElementCodec((ContainerType) cqlType, token, isJavaCovariant); + getElementCodecForCqlAndJavaType((ContainerType) cqlType, token, isJavaCovariant); return TypeCodecs.listOf(elementCodec); } else if (cqlType instanceof SetType && Set.class.isAssignableFrom(token.getRawType())) { TypeCodec elementCodec = - getElementCodec((ContainerType) cqlType, token, isJavaCovariant); + getElementCodecForCqlAndJavaType((ContainerType) cqlType, token, isJavaCovariant); return TypeCodecs.setOf(elementCodec); } else if (cqlType instanceof MapType && Map.class.isAssignableFrom(token.getRawType())) { DataType keyCqlType = ((MapType) cqlType).getKeyType(); @@ -593,9 +640,14 @@ protected TypeCodec createCodec( } else if (cqlType instanceof UserDefinedType && UdtValue.class.isAssignableFrom(token.getRawType())) { return TypeCodecs.udtOf((UserDefinedType) cqlType); - } else if (cqlType instanceof VectorType && List.class.isAssignableFrom(token.getRawType())) { + } else if (cqlType instanceof VectorType + && CqlVector.class.isAssignableFrom(token.getRawType())) { VectorType vectorType = (VectorType) cqlType; - TypeCodec elementCodec = getElementCodec(vectorType, token, isJavaCovariant); + /* For a vector type we'll always get back an instance of TypeCodec due to the + * type of CqlVector... but getElementCodecForCqlAndJavaType() is a generalized function that can't + * return this more precise type. Thus the cast here. */ + TypeCodec elementCodec = + uncheckedCast(getElementCodecForCqlAndJavaType(vectorType, token, isJavaCovariant)); return TypeCodecs.vectorOf(vectorType, elementCodec); } else if (cqlType instanceof CustomType && ByteBuffer.class.isAssignableFrom(token.getRawType())) { @@ -612,15 +664,13 @@ protected TypeCodec createCodec(@NonNull GenericType javaType, boolean isJ TypeToken token = javaType.__getToken(); if (List.class.isAssignableFrom(token.getRawType()) && token.getType() instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) token.getType()).getActualTypeArguments(); - GenericType elementType = GenericType.of(typeArguments[0]); - TypeCodec elementCodec = codecFor(elementType, isJavaCovariant); + TypeCodec elementCodec = + getElementCodecForJavaType((ParameterizedType) token.getType(), isJavaCovariant); return TypeCodecs.listOf(elementCodec); } else if (Set.class.isAssignableFrom(token.getRawType()) && token.getType() instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) token.getType()).getActualTypeArguments(); - GenericType elementType = GenericType.of(typeArguments[0]); - TypeCodec elementCodec = codecFor(elementType, isJavaCovariant); + TypeCodec elementCodec = + getElementCodecForJavaType((ParameterizedType) token.getType(), isJavaCovariant); return TypeCodecs.setOf(elementCodec); } else if (Map.class.isAssignableFrom(token.getRawType()) && token.getType() instanceof ParameterizedType) { @@ -631,6 +681,9 @@ protected TypeCodec createCodec(@NonNull GenericType javaType, boolean isJ TypeCodec valueCodec = codecFor(valueType, isJavaCovariant); return TypeCodecs.mapOf(keyCodec, valueCodec); } + /* Note that this method cannot generate TypeCodec instances for any CqlVector type. VectorCodec needs + * to know the dimensions of the vector it will be operating on and there's no way to determine that from + * the Java type alone. */ throw new CodecNotFoundException(null, javaType); } @@ -652,6 +705,11 @@ protected TypeCodec createCodec(@NonNull DataType cqlType) { TypeCodec keyCodec = codecFor(keyType); TypeCodec valueCodec = codecFor(valueType); return TypeCodecs.mapOf(keyCodec, valueCodec); + } else if (cqlType instanceof VectorType) { + VectorType vectorType = (VectorType) cqlType; + TypeCodec elementCodec = + uncheckedCast(codecFor(vectorType.getElementType())); + return TypeCodecs.vectorOf(vectorType, elementCodec); } else if (cqlType instanceof TupleType) { return TypeCodecs.tupleOf((TupleType) cqlType); } else if (cqlType instanceof UserDefinedType) { @@ -687,8 +745,11 @@ private static TypeCodec uncheckedCast( GenericType.setOf(Boolean.class); private static final GenericType> JAVA_TYPE_FOR_EMPTY_MAPS = GenericType.mapOf(Boolean.class, Boolean.class); + private static final GenericType> JAVA_TYPE_FOR_EMPTY_CQLVECTORS = + GenericType.vectorOf(Number.class); private static final DataType CQL_TYPE_FOR_EMPTY_LISTS = DataTypes.listOf(DataTypes.BOOLEAN); private static final DataType CQL_TYPE_FOR_EMPTY_SETS = DataTypes.setOf(DataTypes.BOOLEAN); private static final DataType CQL_TYPE_FOR_EMPTY_MAPS = DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN); + private static final DataType CQL_TYPE_FOR_EMPTY_VECTORS = DataTypes.vectorOf(DataTypes.INT, 0); } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java new file mode 100644 index 00000000000..ecf8f1249d0 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java @@ -0,0 +1,198 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.assertj.core.util.Lists; +import org.junit.Test; + +public class CqlVectorTest { + + private static final Float[] VECTOR_ARGS = {1.0f, 2.5f}; + + private void validate_built_vector(CqlVector vec) { + + assertThat(vec.size()).isEqualTo(2); + assertThat(vec.isEmpty()).isFalse(); + assertThat(vec.get(0)).isEqualTo(VECTOR_ARGS[0]); + assertThat(vec.get(1)).isEqualTo(VECTOR_ARGS[1]); + } + + @Test + public void should_build_vector_from_elements() { + + validate_built_vector(CqlVector.newInstance(VECTOR_ARGS)); + } + + @Test + public void should_build_vector_from_list() { + + validate_built_vector(CqlVector.newInstance(Lists.newArrayList(VECTOR_ARGS))); + } + + @Test + public void should_build_vector_from_tostring_output() { + + CqlVector vector1 = CqlVector.newInstance(VECTOR_ARGS); + CqlVector vector2 = CqlVector.from(vector1.toString(), TypeCodecs.FLOAT); + assertThat(vector2).isEqualTo(vector1); + } + + @Test + public void should_throw_from_null_string() { + + assertThatThrownBy( + () -> { + CqlVector.from(null, TypeCodecs.FLOAT); + }) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void should_throw_from_empty_string() { + + assertThatThrownBy( + () -> { + CqlVector.from("", TypeCodecs.FLOAT); + }) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void should_throw_when_building_with_nulls() { + + assertThatThrownBy( + () -> { + CqlVector.newInstance(1.1f, null, 2.2f); + }) + .isInstanceOf(IllegalArgumentException.class); + + Float[] theArray = new Float[] {1.1f, null, 2.2f}; + assertThatThrownBy( + () -> { + CqlVector.newInstance(theArray); + }) + .isInstanceOf(IllegalArgumentException.class); + + List theList = Lists.newArrayList(1.1f, null, 2.2f); + assertThatThrownBy( + () -> { + CqlVector.newInstance(theList); + }) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void should_build_empty_vector() { + + CqlVector vector = CqlVector.newInstance(); + assertThat(vector.isEmpty()).isTrue(); + assertThat(vector.size()).isEqualTo(0); + } + + @Test + public void should_behave_mostly_like_a_list() { + + CqlVector vector = CqlVector.newInstance(VECTOR_ARGS); + assertThat(vector.get(0)).isEqualTo(VECTOR_ARGS[0]); + Float newVal = VECTOR_ARGS[0] * 2; + vector.set(0, newVal); + assertThat(vector.get(0)).isEqualTo(newVal); + assertThat(vector.isEmpty()).isFalse(); + assertThat(vector.size()).isEqualTo(2); + assertThat(Iterators.toArray(vector.iterator(), Float.class)).isEqualTo(VECTOR_ARGS); + } + + @Test + public void should_play_nicely_with_streams() { + + CqlVector vector = CqlVector.newInstance(VECTOR_ARGS); + List results = + vector.stream() + .map((f) -> f * 2) + .collect(Collectors.toCollection(() -> new ArrayList())); + for (int i = 0; i < vector.size(); ++i) { + assertThat(results.get(i)).isEqualTo(vector.get(i) * 2); + } + } + + @Test + public void should_reflect_changes_to_mutable_list() { + + List theList = Lists.newArrayList(1.1f, 2.2f, 3.3f); + CqlVector vector = CqlVector.newInstance(theList); + assertThat(vector.size()).isEqualTo(3); + assertThat(vector.get(2)).isEqualTo(3.3f); + + float newVal1 = 4.4f; + theList.set(2, newVal1); + assertThat(vector.size()).isEqualTo(3); + assertThat(vector.get(2)).isEqualTo(newVal1); + + float newVal2 = 5.5f; + theList.add(newVal2); + assertThat(vector.size()).isEqualTo(4); + assertThat(vector.get(3)).isEqualTo(newVal2); + } + + @Test + public void should_reflect_changes_to_array() { + + Float[] theArray = new Float[] {1.1f, 2.2f, 3.3f}; + CqlVector vector = CqlVector.newInstance(theArray); + assertThat(vector.size()).isEqualTo(3); + assertThat(vector.get(2)).isEqualTo(3.3f); + + float newVal1 = 4.4f; + theArray[2] = newVal1; + assertThat(vector.size()).isEqualTo(3); + assertThat(vector.get(2)).isEqualTo(newVal1); + } + + @Test + public void should_correctly_compare_vectors() { + + Float[] args = VECTOR_ARGS.clone(); + CqlVector vector1 = CqlVector.newInstance(args); + CqlVector vector2 = CqlVector.newInstance(args); + CqlVector vector3 = CqlVector.newInstance(Lists.newArrayList(args)); + assertThat(vector1).isNotSameAs(vector2); + assertThat(vector1).isEqualTo(vector2); + assertThat(vector1).isNotSameAs(vector3); + assertThat(vector1).isEqualTo(vector3); + + Float[] differentArgs = args.clone(); + float newVal = differentArgs[0] * 2; + differentArgs[0] = newVal; + CqlVector vector4 = CqlVector.newInstance(differentArgs); + assertThat(vector1).isNotSameAs(vector4); + assertThat(vector1).isNotEqualTo(vector4); + + Float[] biggerArgs = Arrays.copyOf(args, args.length + 1); + biggerArgs[biggerArgs.length - 1] = newVal; + CqlVector vector5 = CqlVector.newInstance(biggerArgs); + assertThat(vector1).isNotSameAs(vector5); + assertThat(vector1).isNotEqualTo(vector5); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java index 9b463dcb53e..82ec7b5ed67 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java @@ -18,18 +18,20 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.VectorType; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import com.datastax.oss.driver.internal.core.type.DefaultVectorType; -import com.google.common.collect.Lists; -import java.util.List; +import java.util.Arrays; import org.junit.Test; -public class VectorCodecTest extends CodecTestBase> { +public class VectorCodecTest extends CodecTestBase> { - private static final List VECTOR = Lists.newArrayList(1.0f, 2.5f); + private static final Float[] VECTOR_ARGS = {1.0f, 2.5f}; + + private static final CqlVector VECTOR = CqlVector.newInstance(VECTOR_ARGS); private static final String VECTOR_HEX_STRING = "0x" + "3f800000" + "40200000"; @@ -49,21 +51,21 @@ public void should_encode() { /** Too few eleements will cause an exception, extra elements will be silently ignored */ @Test public void should_throw_on_encode_with_too_few_elements() { - assertThatThrownBy(() -> encode(VECTOR.subList(0, 1))) + assertThatThrownBy(() -> encode(VECTOR.subVector(0, 1))) .isInstanceOf(IllegalArgumentException.class); } @Test public void should_throw_on_encode_with_empty_list() { - assertThatThrownBy(() -> encode(Lists.newArrayList())) + assertThatThrownBy(() -> encode(CqlVector.newInstance())) .isInstanceOf(IllegalArgumentException.class); } @Test public void should_encode_with_too_many_elements() { - List doubleVector = Lists.newArrayList(VECTOR); - doubleVector.addAll(VECTOR); - assertThat(encode(doubleVector)).isEqualTo(VECTOR_HEX_STRING); + Float[] doubledVectorContents = Arrays.copyOf(VECTOR_ARGS, VECTOR_ARGS.length * 2); + System.arraycopy(VECTOR_ARGS, 0, doubledVectorContents, VECTOR_ARGS.length, VECTOR_ARGS.length); + assertThat(encode(CqlVector.newInstance(doubledVectorContents))).isEqualTo(VECTOR_HEX_STRING); } @Test @@ -118,14 +120,14 @@ public void should_accept_vector_type_correct_dimension_only() { @Test public void should_accept_generic_type() { - assertThat(codec.accepts(GenericType.listOf(GenericType.FLOAT))).isTrue(); - assertThat(codec.accepts(GenericType.listOf(GenericType.INTEGER))).isFalse(); + assertThat(codec.accepts(GenericType.vectorOf(GenericType.FLOAT))).isTrue(); + assertThat(codec.accepts(GenericType.vectorOf(GenericType.INTEGER))).isFalse(); assertThat(codec.accepts(GenericType.of(Integer.class))).isFalse(); } @Test public void should_accept_raw_type() { - assertThat(codec.accepts(List.class)).isTrue(); + assertThat(codec.accepts(CqlVector.class)).isTrue(); assertThat(codec.accepts(Integer.class)).isFalse(); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java index 64bbd800c92..a0d0b77ca87 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java @@ -17,6 +17,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.DataTypes; @@ -285,6 +286,55 @@ public static Object[][] collectionsWithCqlAndJavaTypes() ImmutableMap.of( ImmutableMap.of(udtValue, udtValue), ImmutableMap.of(tupleValue, tupleValue)) }, + // vectors + { + DataTypes.vectorOf(DataTypes.INT, 1), + GenericType.vectorOf(Integer.class), + GenericType.vectorOf(Integer.class), + CqlVector.newInstance(1) + }, + { + DataTypes.vectorOf(DataTypes.BIGINT, 1), + GenericType.vectorOf(Long.class), + GenericType.vectorOf(Long.class), + CqlVector.newInstance(1l) + }, + { + DataTypes.vectorOf(DataTypes.SMALLINT, 1), + GenericType.vectorOf(Short.class), + GenericType.vectorOf(Short.class), + CqlVector.newInstance((short) 1) + }, + { + DataTypes.vectorOf(DataTypes.TINYINT, 1), + GenericType.vectorOf(Byte.class), + GenericType.vectorOf(Byte.class), + CqlVector.newInstance((byte) 1) + }, + { + DataTypes.vectorOf(DataTypes.FLOAT, 1), + GenericType.vectorOf(Float.class), + GenericType.vectorOf(Float.class), + CqlVector.newInstance(1.0f) + }, + { + DataTypes.vectorOf(DataTypes.DOUBLE, 1), + GenericType.vectorOf(Double.class), + GenericType.vectorOf(Double.class), + CqlVector.newInstance(1.0d) + }, + { + DataTypes.vectorOf(DataTypes.DECIMAL, 1), + GenericType.vectorOf(BigDecimal.class), + GenericType.vectorOf(BigDecimal.class), + CqlVector.newInstance(BigDecimal.ONE) + }, + { + DataTypes.vectorOf(DataTypes.VARINT, 1), + GenericType.vectorOf(BigInteger.class), + GenericType.vectorOf(BigInteger.class), + CqlVector.newInstance(BigInteger.ONE) + }, }; } From ced78da9d7bade3859952de83509f8223a784020 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 7 Jul 2023 18:56:41 -0500 Subject: [PATCH 257/395] Formatting fix --- .../core/DefaultProtocolVersionRegistryTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java index 0bf571da20c..05de9989572 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/DefaultProtocolVersionRegistryTest.java @@ -52,13 +52,15 @@ public void should_find_version_by_name() { assertThat(registry.fromName("DSE_V1")).isEqualTo(DseProtocolVersion.DSE_V1); } - @Test public void should_fail_to_find_version_by_name_different_case() { assertThatThrownBy(() -> registry.fromName("v4")).isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> registry.fromName("dse_v1")).isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> registry.fromName("dDSE_v1")).isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> registry.fromName("dse_v1")).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> registry.fromName("dse_v1")) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> registry.fromName("dDSE_v1")) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> registry.fromName("dse_v1")) + .isInstanceOf(IllegalArgumentException.class); } @Test From f3ff47180f30d86fa2bff2d53126c4f07a86b8a4 Mon Sep 17 00:00:00 2001 From: hhughes Date: Mon, 10 Jul 2023 17:07:12 -0700 Subject: [PATCH 258/395] JAVA-3085: Tell graal to initialize com.datastax.oss.driver.internal.core.util.Dependency at build-time (#1674) --- .../com.datastax.oss/java-driver-core/native-image.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties index b2fb10d32c8..7900d35f81a 100644 --- a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties +++ b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties @@ -4,4 +4,5 @@ Args=-H:IncludeResources=reference\\.conf \ -H:IncludeResources=application\\.properties \ -H:IncludeResources=.*Driver\\.properties \ -H:DynamicProxyConfigurationResources=${.}/proxy.json \ - -H:ReflectionConfigurationResources=${.}/reflection.json + -H:ReflectionConfigurationResources=${.}/reflection.json \ + --initialize-at-build-time=com.datastax.oss.driver.internal.core.util.Dependency From 63ed4ce61cc531592190a0764cdb0d0c3686efe5 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 11 Jul 2023 00:23:43 -0500 Subject: [PATCH 259/395] JAVA-3000 Native protocol docs still list C* 4.0 as unreleased, v5 in beta (#1673) --- manual/core/native_protocol/README.md | 21 +++++++++------------ manual/developer/native_protocol/README.md | 6 ++---- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 2bc075be3be..23df7ed9eec 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -24,18 +24,15 @@ only available with specific protocol versions. Java driver 4 supports protocol versions 3 to 5. By default, the version is negotiated with the first node the driver connects to: -| Cassandra version | Negotiated protocol version with driver 4 ¹ | -|---------------------|-------------------------------------------------| -| 2.1.x | v3 | -| 2.2.x | v4 | -| 3.x | v4 | -| 4.x ² | v5 | +| Cassandra version | Negotiated protocol version with driver 4 ¹ | +|-------------------|-------------------------------------------------| +| 2.1.x | v3 | +| 2.2.x | v4 | +| 3.x | v4 | +| 4.x | v5 | *(1) for previous driver versions, see the [3.x documentation][driver3]* -*(2) at the time of writing, Cassandra 4 is not released yet. Protocol v5 support is still in beta, -and must be enabled explicitly (negotiation will yield v4).* - Since version 4.5.0, the driver can also use DSE protocols when all nodes are running a version of DSE. The table below shows the protocol matrix for these cases: @@ -43,10 +40,10 @@ DSE. The table below shows the protocol matrix for these cases: |---------------------|-------------------------------------------------| | 4.7/4.8 | v3 | | 5.0 | v4 | -| 5.1 | DSE_V1 ³ | -| 6.0/6.7/6.8 | DSE_V2 ³ | +| 5.1 | DSE_V1 ² | +| 6.0/6.7/6.8 | DSE_V2 ² | -*(3) DSE Protocols are chosen before other Cassandra native protocols.* +*(2) DSE Protocols are chosen before other Cassandra native protocols.* ### Controlling the protocol version diff --git a/manual/developer/native_protocol/README.md b/manual/developer/native_protocol/README.md index 11c936d272b..cbda8f794ff 100644 --- a/manual/developer/native_protocol/README.md +++ b/manual/developer/native_protocol/README.md @@ -9,10 +9,8 @@ This part of the code lives in its own project: The protocol specifications are available in [native-protocol/src/main/resources](https://github.com/datastax/native-protocol/tree/1.x/src/main/resources). -These files originally come from Cassandra, we copy them over for easy access. Note that, if the -latest version is a beta (this is the case for v5 at the time of writing -- September 2019), the -specification might not be up to date. Always compare with the latest revision in -[cassandra/doc](https://github.com/apache/cassandra/tree/trunk/doc). +These files originally come from Cassandra, we copy them over for easy access. Authoritative specifications can +always be found in [cassandra/doc](https://github.com/apache/cassandra/tree/trunk/doc). For a broad overview of how protocol types are used in the driver, let's step through an example: From dfc1164ef3fb76e212daf577a85b5381198890f6 Mon Sep 17 00:00:00 2001 From: hhughes Date: Wed, 12 Jul 2023 07:52:33 -0700 Subject: [PATCH 260/395] JAVA-3070: Make CqlVector and CqlDuration serializable (#1676) --- .../oss/driver/api/core/data/CqlDuration.java | 8 ++- .../oss/driver/api/core/data/CqlVector.java | 62 ++++++++++++++++++- .../driver/api/core/data/CqlDurationTest.java | 15 +++++ .../driver/api/core/data/CqlVectorTest.java | 36 +++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java index 8ec509ea7f6..5bb07b92923 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlDuration.java @@ -20,6 +20,7 @@ import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.Serializable; import java.time.Duration; import java.time.Period; import java.time.temporal.ChronoUnit; @@ -42,7 +43,9 @@ * in time, regardless of the calendar). */ @Immutable -public final class CqlDuration implements TemporalAmount { +public final class CqlDuration implements TemporalAmount, Serializable { + + private static final long serialVersionUID = 1L; @VisibleForTesting static final long NANOS_PER_MICRO = 1000L; @VisibleForTesting static final long NANOS_PER_MILLI = 1000 * NANOS_PER_MICRO; @@ -75,8 +78,11 @@ public final class CqlDuration implements TemporalAmount { private static final ImmutableList TEMPORAL_UNITS = ImmutableList.of(ChronoUnit.MONTHS, ChronoUnit.DAYS, ChronoUnit.NANOS); + /** @serial */ private final int months; + /** @serial */ private final int days; + /** @serial */ private final long nanoseconds; private CqlDuration(int months, int days, long nanoseconds) { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java index 152d0f40823..2889ea5eb24 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java @@ -22,6 +22,12 @@ import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; import com.datastax.oss.driver.shaded.guava.common.collect.Streams; import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; @@ -44,7 +50,7 @@ * where possible we've tried to make the API of this class similar to the equivalent methods on * {@link List}. */ -public class CqlVector implements Iterable { +public class CqlVector implements Iterable, Serializable { /** * Create a new CqlVector containing the specified values. @@ -190,4 +196,58 @@ public int hashCode() { public String toString() { return Iterables.toString(this.list); } + + /** + * Serialization proxy for CqlVector. Allows serialization regardless of implementation of list + * field. + * + * @param inner type of CqlVector, assume Number is always Serializable. + */ + private static class SerializationProxy implements Serializable { + + private static final long serialVersionUID = 1; + + private transient List list; + + SerializationProxy(CqlVector vector) { + this.list = vector.list; + } + + // Reconstruct CqlVector's list of elements. + private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + int size = stream.readInt(); + list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add((T) stream.readObject()); + } + } + + // Return deserialized proxy object as CqlVector. + private Object readResolve() throws ObjectStreamException { + return new CqlVector(list); + } + + // Write size of CqlVector followed by items in order. + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + + stream.writeInt(list.size()); + for (T item : list) { + stream.writeObject(item); + } + } + } + + /** @serialData The number of elements in the vector, followed by each element in-order. */ + private Object writeReplace() { + return new SerializationProxy(this); + } + + private void readObject(@SuppressWarnings("unused") ObjectInputStream stream) + throws InvalidObjectException { + // Should never be called since we serialized a proxy + throw new InvalidObjectException("Proxy required"); + } } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java index 56c0b00b5e3..f5c263f0594 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlDurationTest.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.fail; import com.datastax.oss.driver.TestDataProviders; +import com.datastax.oss.driver.internal.SerializationHelper; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.time.ZonedDateTime; @@ -190,4 +191,18 @@ public void should_subtract_from_temporal() { assertThat(dateTime.minus(CqlDuration.from("1h15s15ns"))) .isEqualTo("2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]"); } + + @Test + public void should_serialize_and_deserialize() throws Exception { + CqlDuration initial = CqlDuration.from("3mo2d15s"); + CqlDuration deserialized = SerializationHelper.serializeAndDeserialize(initial); + assertThat(deserialized).isEqualTo(initial); + } + + @Test + public void should_serialize_and_deserialize_negative() throws Exception { + CqlDuration initial = CqlDuration.from("-2d15m"); + CqlDuration deserialized = SerializationHelper.serializeAndDeserialize(initial); + assertThat(deserialized).isEqualTo(initial); + } } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java index ecf8f1249d0..75dfbc26e42 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java @@ -19,9 +19,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; +import com.datastax.oss.driver.internal.SerializationHelper; import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import org.assertj.core.util.Lists; @@ -195,4 +198,37 @@ public void should_correctly_compare_vectors() { assertThat(vector1).isNotSameAs(vector5); assertThat(vector1).isNotEqualTo(vector5); } + + @Test + public void should_serialize_and_deserialize() throws Exception { + CqlVector initial = CqlVector.newInstance(VECTOR_ARGS); + CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); + assertThat(deserialized).isEqualTo(initial); + } + + @Test + public void should_serialize_and_deserialize_empty_vector() throws Exception { + CqlVector initial = CqlVector.newInstance(Collections.emptyList()); + CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); + assertThat(deserialized).isEqualTo(initial); + } + + @Test + public void should_serialize_and_deserialize_unserializable_list() throws Exception { + CqlVector initial = + CqlVector.newInstance( + new AbstractList() { + @Override + public Float get(int index) { + return VECTOR_ARGS[index]; + } + + @Override + public int size() { + return VECTOR_ARGS.length; + } + }); + CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); + assertThat(deserialized).isEqualTo(initial); + } } From 41991c898dc479d413967faafc3ae9f7ab969aba Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 12 Jul 2023 13:38:32 -0500 Subject: [PATCH 261/395] JAVA-3083: Doc updates for new features in 4.17.0 (#1677) --- manual/core/README.md | 58 ++++++++-------- manual/core/custom_codecs/README.md | 12 ++++ upgrade_guide/README.md | 101 +++++++++++++++++++++------- 3 files changed, 120 insertions(+), 51 deletions(-) diff --git a/manual/core/README.md b/manual/core/README.md index 8cc6b670b99..349a810f3aa 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -231,34 +231,35 @@ See [AccessibleByName] for an explanation of the conversion rules. ##### CQL to Java type mapping -| CQL3 data type | Getter name | Java type | See also | -|---------------------|----------------|----------------------|-------------------------------------| -| ascii | getString | java.lang.String | | -| bigint | getLong | long | | -| blob | getByteBuffer | java.nio.ByteBuffer | | -| boolean | getBoolean | boolean | | -| counter | getLong | long | | -| date | getLocalDate | java.time.LocalDate | [Temporal types](temporal_types/) | -| decimal | getBigDecimal | java.math.BigDecimal | | -| double | getDouble | double | | -| duration | getCqlDuration | [CqlDuration] | [Temporal types](temporal_types/) | -| float | getFloat | float | | -| inet | getInetAddress | java.net.InetAddress | | -| int | getInt | int | | -| list | getList | java.util.List | | -| map | getMap | java.util.Map | | -| set | getSet | java.util.Set | | -| smallint | getShort | short | | -| text | getString | java.lang.String | | -| time | getLocalTime | java.time.LocalTime | [Temporal types](temporal_types/) | -| timestamp | getInstant | java.time.Instant | [Temporal types](temporal_types/) | -| timeuuid | getUuid | java.util.UUID | | -| tinyint | getByte | byte | | -| tuple | getTupleValue | [TupleValue] | [Tuples](tuples/) | -| user-defined types | getUDTValue | [UDTValue] | [User-defined types](udts/) | -| uuid | getUuid | java.util.UUID | | -| varchar | getString | java.lang.String | | -| varint | getBigInteger | java.math.BigInteger | | +| CQL3 data type | Getter name | Java type | See also | +|--------------------|----------------|----------------------|-----------------------------------| +| ascii | getString | java.lang.String | | +| bigint | getLong | long | | +| blob | getByteBuffer | java.nio.ByteBuffer | | +| boolean | getBoolean | boolean | | +| counter | getLong | long | | +| date | getLocalDate | java.time.LocalDate | [Temporal types](temporal_types/) | +| decimal | getBigDecimal | java.math.BigDecimal | | +| double | getDouble | double | | +| duration | getCqlDuration | [CqlDuration] | [Temporal types](temporal_types/) | +| float | getFloat | float | | +| inet | getInetAddress | java.net.InetAddress | | +| int | getInt | int | | +| list | getList | java.util.List | | +| map | getMap | java.util.Map | | +| set | getSet | java.util.Set | | +| smallint | getShort | short | | +| text | getString | java.lang.String | | +| time | getLocalTime | java.time.LocalTime | [Temporal types](temporal_types/) | +| timestamp | getInstant | java.time.Instant | [Temporal types](temporal_types/) | +| timeuuid | getUuid | java.util.UUID | | +| tinyint | getByte | byte | | +| tuple | getTupleValue | [TupleValue] | [Tuples](tuples/) | +| user-defined types | getUDTValue | [UDTValue] | [User-defined types](udts/) | +| uuid | getUuid | java.util.UUID | | +| varchar | getString | java.lang.String | | +| varint | getBigInteger | java.math.BigInteger | | +| vector | getVector | [CqlVector] | [Custom Codecs](custom_codecs/) | Sometimes the driver has to infer a CQL type from a Java type (for example when handling the values of [simple statements](statements/simple/)); for those that have multiple CQL equivalents, it makes @@ -322,6 +323,7 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { [AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html [GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html [CqlDuration]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlDuration.html +[CqlVector]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlVector.html [TupleValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/TupleValue.html [UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html [SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index 92a0274577b..ae873d0b60d 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -256,6 +256,17 @@ that maps instances of that class to Json strings, using a newly-allocated, defa It is also possible to pass a custom `ObjectMapper` instance using [ExtraTypeCodecs.json(Class, ObjectMapper)] instead. +#### Mapping CQL vectors to Java array + +By default, the driver maps CQL `vector` to the [CqlVector] value type. If you prefer to deal with +arrays, the driver offers the following codec: + +| Codec | CQL type | Java type | +|-------------------------------------------|-----------------|-----------| +| [ExtraTypeCodecs.floatVectorToArray(int)] | `vector` | `float[]` | + +This release only provides a codec for vectors containing float values. + ### Writing codecs If none of the driver built-in codecs above suits you, it is also possible to roll your own. @@ -707,6 +718,7 @@ private static String formatRow(Row row) { [ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- [ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- [ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- +[ExtraTypeCodecs.floatVectorToArray(int)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#floatVectorToArray-int- [TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB [TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 785f51290da..6310f220c3d 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,5 +1,60 @@ ## Upgrade guide +### 4.17.0 + +#### Beta support for Java17 + +With the completion of [JAVA-3042](https://datastax-oss.atlassian.net/browse/JAVA-3042) the driver now passes our automated test matrix for Java driver releases. +While all features function normally when run with Java 17 tests, we do not offer full support for this +platform until we've received feedback from other users in the ecosystem. + +If you discover an issue with the Java driver running on Java 17, please let us know. We will triage and address Java 17 issues. + +#### Updated API for vector search + +The 4.16.0 release introduced support for the CQL `vector` datatype. This release modifies the `CqlVector` +value type used to represent a CQL vector to make it easier to use. `CqlVector` now implements the Iterable interface +as well as several methods modelled on the JDK's List interface. For more, see +[JAVA-3060](https://datastax-oss.atlassian.net/browse/JAVA-3060). + +The builder interface was replaced with factory methods that resemble similar methods on `CqlDuration`. +For example, the following code will create a keyspace and table, populate that table with some data, and then execute +a query that will return a `vector` type. This data is retrieved directly via `Row.getVector()` and the resulting +`CqlVector` value object can be interrogated directly. + +```java +try (CqlSession session = new CqlSessionBuilder().withLocalDatacenter("datacenter1").build()) { + + session.execute("DROP KEYSPACE IF EXISTS test"); + session.execute("CREATE KEYSPACE test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}"); + session.execute("CREATE TABLE test.foo(i int primary key, j vector)"); + session.execute("CREAT CUSTOM INDEX ann_index ON test.foo(j) USING 'StorageAttachedIndex'"); + session.execute("INSERT INTO test.foo (i, j) VALUES (1, [8, 2.3, 58])"); + session.execute("INSERT INTO test.foo (i, j) VALUES (2, [1.2, 3.4, 5.6])"); + session.execute("INSERT INTO test.foo (i, j) VALUES (5, [23, 18, 3.9])"); + ResultSet rs=session.execute("SELECT j FROM test.foo WHERE j ann of [3.4, 7.8, 9.1] limit 1"); + for (Row row : rs){ + CqlVector v = row.getVector(0, Float.class); + System.out.println(v); + if (Iterables.size(v) != 3) { + throw new RuntimeException("Expected vector with three dimensions"); + } + } +} +``` + +You can also use the `CqlVector` type with prepared statements: + +```java +PreparedStatement preparedInsert = session.prepare("INSERT INTO test.foo (i, j) VALUES (?,?)"); +CqlVector vector = CqlVector.newInstance(1.4f, 2.5f, 3.6f); +session.execute(preparedInsert.bind(3, vector)); +``` + +In some cases, it makes sense to access the vector directly as an array of some numerical type. This version +supports such use cases by providing a codec which translates a CQL vector to and from a primitive array. Only float arrays are supported. +You can find more information about this codec in the manual documentation on [custom codecs](../manual/core/custom_codecs/) + ### 4.15.0 #### CodecNotFoundException now extends DriverException @@ -15,7 +70,7 @@ a logic such as below, it won't compile anymore: ```java try { - doSomethingWithDriver(); + doSomethingWithDriver(); } catch(DriverException e) { } catch(CodecNotFoundException e) { } @@ -25,7 +80,7 @@ You need to either reverse the catch order and catch `CodecNotFoundException` fi ```java try { - doSomethingWithDriver(); + doSomethingWithDriver(); } catch(CodecNotFoundException e) { } catch(DriverException e) { } @@ -35,7 +90,7 @@ Or catch only `DriverException`: ```java try { - doSomethingWithDriver(); + doSomethingWithDriver(); } catch(DriverException e) { } ``` @@ -229,16 +284,16 @@ The above can also be achieved by an adapter class as shown below: ```java public class NodeFilterToDistanceEvaluatorAdapter implements NodeDistanceEvaluator { - private final Predicate nodeFilter; + private final Predicate nodeFilter; - public NodeFilterToDistanceEvaluatorAdapter(@NonNull Predicate nodeFilter) { - this.nodeFilter = nodeFilter; - } + public NodeFilterToDistanceEvaluatorAdapter(@NonNull Predicate nodeFilter) { + this.nodeFilter = nodeFilter; + } - @Nullable @Override - public NodeDistance evaluateDistance(@NonNull Node node, @Nullable String localDc) { - return nodeFilter.test(node) ? null : NodeDistance.IGNORED; - } + @Nullable @Override + public NodeDistance evaluateDistance(@NonNull Node node, @Nullable String localDc) { + return nodeFilter.test(node) ? null : NodeDistance.IGNORED; + } } ``` @@ -531,7 +586,7 @@ import com.datastax.driver.core.Row; import com.datastax.driver.core.SimpleStatement; SimpleStatement statement = - new SimpleStatement("SELECT release_version FROM system.local"); + new SimpleStatement("SELECT release_version FROM system.local"); ResultSet resultSet = session.execute(statement); Row row = resultSet.one(); System.out.println(row.getString("release_version")); @@ -543,7 +598,7 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; SimpleStatement statement = - SimpleStatement.newInstance("SELECT release_version FROM system.local"); + SimpleStatement.newInstance("SELECT release_version FROM system.local"); ResultSet resultSet = session.execute(statement); Row row = resultSet.one(); System.out.println(row.getString("release_version")); @@ -606,9 +661,9 @@ datastax-java-driver { // Application code: SimpleStatement statement1 = - SimpleStatement.newInstance("...").setExecutionProfileName("profile1"); + SimpleStatement.newInstance("...").setExecutionProfileName("profile1"); SimpleStatement statement2 = - SimpleStatement.newInstance("...").setExecutionProfileName("profile2"); + SimpleStatement.newInstance("...").setExecutionProfileName("profile2"); ``` The configuration can be reloaded periodically at runtime: @@ -727,13 +782,13 @@ propagating its own consistency level to its bound statements: ```java PreparedStatement ps1 = - session.prepare( - SimpleStatement.newInstance("SELECT * FROM product WHERE sku = ?") - .setConsistencyLevel(DefaultConsistencyLevel.ONE)); + session.prepare( + SimpleStatement.newInstance("SELECT * FROM product WHERE sku = ?") + .setConsistencyLevel(DefaultConsistencyLevel.ONE)); PreparedStatement ps2 = - session.prepare( - SimpleStatement.newInstance("SELECT * FROM product WHERE sku = ?") - .setConsistencyLevel(DefaultConsistencyLevel.TWO)); + session.prepare( + SimpleStatement.newInstance("SELECT * FROM product WHERE sku = ?") + .setConsistencyLevel(DefaultConsistencyLevel.TWO)); assert ps1 != ps2; @@ -834,8 +889,8 @@ Optional ks = metadata.getKeyspace("test"); assert !ks.isPresent(); session.execute( - "CREATE KEYSPACE IF NOT EXISTS test " - + "WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}"); + "CREATE KEYSPACE IF NOT EXISTS test " + + "WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}"); // This is still the same metadata from before the CREATE ks = metadata.getKeyspace("test"); From 95e3f2f7752d87a6c6ed91fd6f2fa2937b35f868 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 12 Jul 2023 17:19:41 -0500 Subject: [PATCH 262/395] 4.17.0 release documentation updates (#1681) --- README.md | 4 +- bom/pom.xml | 18 ++--- changelog/README.md | 8 ++ core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- manual/case_sensitivity/README.md | 10 +-- manual/core/README.md | 28 +++---- manual/core/address_resolution/README.md | 2 +- manual/core/async/README.md | 2 +- manual/core/authentication/README.md | 18 ++--- manual/core/bom/README.md | 4 +- manual/core/configuration/README.md | 20 ++--- manual/core/control_connection/README.md | 2 +- manual/core/custom_codecs/README.md | 76 +++++++++---------- manual/core/detachable_types/README.md | 14 ++-- manual/core/dse/geotypes/README.md | 6 +- manual/core/dse/graph/README.md | 4 +- manual/core/dse/graph/fluent/README.md | 4 +- .../core/dse/graph/fluent/explicit/README.md | 12 +-- manual/core/dse/graph/results/README.md | 6 +- manual/core/dse/graph/script/README.md | 6 +- manual/core/idempotence/README.md | 4 +- manual/core/integration/README.md | 7 +- manual/core/load_balancing/README.md | 12 +-- manual/core/metadata/README.md | 6 +- manual/core/metadata/node/README.md | 28 +++---- manual/core/metadata/schema/README.md | 20 ++--- manual/core/metadata/token/README.md | 4 +- manual/core/native_protocol/README.md | 6 +- manual/core/non_blocking/README.md | 44 +++++------ manual/core/paging/README.md | 12 +-- manual/core/performance/README.md | 10 +-- manual/core/pooling/README.md | 2 +- manual/core/query_timestamps/README.md | 4 +- manual/core/reactive/README.md | 24 +++--- manual/core/reconnection/README.md | 8 +- manual/core/request_tracker/README.md | 4 +- manual/core/retries/README.md | 36 ++++----- manual/core/speculative_execution/README.md | 2 +- manual/core/ssl/README.md | 6 +- manual/core/statements/README.md | 8 +- manual/core/statements/batch/README.md | 6 +- .../statements/per_query_keyspace/README.md | 2 +- manual/core/statements/prepared/README.md | 8 +- manual/core/statements/simple/README.md | 6 +- manual/core/temporal_types/README.md | 8 +- manual/core/throttling/README.md | 6 +- manual/core/tracing/README.md | 12 +-- manual/core/tuples/README.md | 4 +- manual/core/udts/README.md | 4 +- manual/developer/common/concurrency/README.md | 4 +- manual/mapper/config/kotlin/README.md | 2 +- manual/mapper/config/record/README.md | 2 +- manual/mapper/config/scala/README.md | 2 +- manual/mapper/daos/README.md | 8 +- manual/mapper/daos/custom_types/README.md | 10 +-- manual/mapper/daos/delete/README.md | 18 ++--- manual/mapper/daos/getentity/README.md | 18 ++--- manual/mapper/daos/increment/README.md | 12 +-- manual/mapper/daos/insert/README.md | 14 ++-- manual/mapper/daos/null_saving/README.md | 10 +-- manual/mapper/daos/query/README.md | 24 +++--- manual/mapper/daos/queryprovider/README.md | 16 ++-- manual/mapper/daos/select/README.md | 28 +++---- manual/mapper/daos/setentity/README.md | 10 +-- .../daos/statement_attributes/README.md | 2 +- manual/mapper/daos/update/README.md | 12 +-- manual/mapper/entities/README.md | 36 ++++----- manual/mapper/mapper/README.md | 10 +-- manual/osgi/README.md | 6 +- manual/query_builder/README.md | 10 +-- manual/query_builder/condition/README.md | 2 +- manual/query_builder/delete/README.md | 4 +- manual/query_builder/insert/README.md | 2 +- manual/query_builder/relation/README.md | 4 +- manual/query_builder/schema/README.md | 2 +- .../query_builder/schema/aggregate/README.md | 2 +- .../query_builder/schema/function/README.md | 2 +- manual/query_builder/schema/index/README.md | 2 +- .../query_builder/schema/keyspace/README.md | 2 +- .../schema/materialized_view/README.md | 4 +- manual/query_builder/schema/table/README.md | 6 +- manual/query_builder/schema/type/README.md | 2 +- manual/query_builder/select/README.md | 4 +- manual/query_builder/term/README.md | 4 +- manual/query_builder/truncate/README.md | 2 +- manual/query_builder/update/README.md | 4 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 2 +- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 98 files changed, 442 insertions(+), 433 deletions(-) diff --git a/README.md b/README.md index 739baedced3..e8a85027ab9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the documentation for latest version through [DataStax Docs] or via the release tags, e.g. -[4.16.0](https://github.com/datastax/java-driver/tree/4.16.0).* +[4.17.0](https://github.com/datastax/java-driver/tree/4.17.0).* A modern, feature-rich and highly tunable Java client library for [Apache Cassandra®] \(2.1+) and [DataStax Enterprise] \(4.7+), and [DataStax Astra], using exclusively Cassandra's binary protocol @@ -86,7 +86,7 @@ See the [Cassandra error handling done right blog](https://www.datastax.com/blog * [Changelog] * [FAQ] -[API docs]: https://docs.datastax.com/en/drivers/java/4.14 +[API docs]: https://docs.datastax.com/en/drivers/java/4.17 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [@dsJavaDriver]: https://twitter.com/dsJavaDriver diff --git a/bom/pom.xml b/bom/pom.xml index 79ea3485cda..547658aea3b 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT com.datastax.oss diff --git a/changelog/README.md b/changelog/README.md index 30bb1194674..6c8c236a6a4 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -2,6 +2,14 @@ +### 4.17.0 + +- [improvement] JAVA-3070: Make CqlVector and CqlDuration serializable +- [improvement] JAVA-3085: Initialize c.d.o.d.i.core.util.Dependency at Graal native image build-time +- [improvement] JAVA-3061: CqlVector API improvements, add support for accessing vectors directly as float arrays +- [improvement] JAVA-3042: Enable automated testing for Java17 +- [improvement] JAVA-3050: Upgrade Netty to 4.1.94 + ### 4.16.0 - [improvement] JAVA-3058: Clear prepared statement cache on UDT type change event diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index fc89c2e7338..bfeb0234b14 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index db2af9ed156..e29d1e95325 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index bd7d0c811ef..c478f049dcf 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 85db139e7f4..8af4d4c9a6d 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 16b900a0fb2..45cc458a586 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-integration-tests jar diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index 865354f41df..15a71eb76c5 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -106,11 +106,11 @@ For "consuming" methods, string overloads are also provided for convenience, for * in other cases, the string is always assumed to be in CQL form, and converted on the fly with `CqlIdentifier.fromCql`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html -[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlIdentifier.html +[Row]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/UdtValue.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/AccessibleByName.html ### Good practices diff --git a/manual/core/README.md b/manual/core/README.md index 349a810f3aa..a11c5e624be 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -315,19 +315,19 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { } ``` -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html -[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html#builder-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlDuration.html -[CqlVector]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlVector.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/TupleValue.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html -[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- -[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession#builder()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html#builder-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlIdentifier.html +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/CqlDuration.html +[CqlVector]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/CqlVector.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/TupleValue.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/UdtValue.html +[SessionBuilder.addContactPoint()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- +[SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index fe8c967a62a..433ffe58a75 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -124,7 +124,7 @@ Cassandra node: domain name of the target instance. Then it performs a forward DNS lookup of the domain name; the EC2 DNS does the private/public switch automatically based on location). -[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html +[AddressTranslator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/addresstranslation/AddressTranslator.html [cassandra.yaml]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html [rpc_address]: https://docs.datastax.com/en/cassandra/3.x/cassandra/configuration/configCassandra_yaml.html?scroll=configCassandra_yaml__rpc_address diff --git a/manual/core/async/README.md b/manual/core/async/README.md index 1daecfd61ee..d64ee2c9b85 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -207,4 +207,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index 45742c3aac2..ebb52bfc5a8 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -227,13 +227,13 @@ session.execute(statement); [SASL]: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer -[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/auth/AuthProvider.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html -[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html -[ProgrammaticPlainTextAuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.html -[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html -[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html -[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- -[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- -[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- +[AuthProvider]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/auth/AuthProvider.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/context/DriverContext.html +[PlainTextAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/auth/PlainTextAuthProviderBase.html +[ProgrammaticPlainTextAuthProvider]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/auth/ProgrammaticPlainTextAuthProvider.html +[DseGssApiAuthProviderBase]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderBase.html +[ProgrammaticDseGssApiAuthProvider]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/auth/ProgrammaticDseGssApiAuthProvider.html +[ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- +[SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- +[SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- [reference.conf]: ../configuration/reference/ \ No newline at end of file diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index 935489beb7e..d0797264263 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -13,7 +13,7 @@ To import the driver's BOM, add the following section in your application's own com.datastax.oss java-driver-bom - 4.16.0 + 4.17.0 pom import @@ -65,7 +65,7 @@ good idea to extract a property to keep it in sync with the BOM: ```xml - 4.16.0 + 4.17.0 diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index 7dc9fd73afc..bccfb7d3fce 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -520,16 +520,16 @@ config.getDefaultProfile().getString(MyCustomOption.ADMIN_EMAIL); config.getDefaultProfile().getInt(MyCustomOption.AWESOMENESS_FACTOR); ``` -[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfig.html -[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html -[DriverOption]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverOption.html -[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html -[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- -[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- -[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- -[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- +[DriverConfig]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfig.html +[DriverExecutionProfile]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverExecutionProfile.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/context/DriverContext.html +[DriverOption]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverOption.html +[DefaultDriverOption]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DefaultDriverOption.html +[DriverConfigLoader]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[DriverConfigLoader.fromClasspath]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromClasspath-java.lang.String- +[DriverConfigLoader.fromFile]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromFile-java.io.File- +[DriverConfigLoader.fromUrl]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromUrl-java.net.URL- +[DriverConfigLoader.programmaticBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-- [Typesafe Config]: https://github.com/typesafehub/config [config standard behavior]: https://github.com/typesafehub/config#standard-behavior diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index d8a9cddc718..570919fdc94 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -23,4 +23,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index ae873d0b60d..e68e5d78029 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -671,13 +671,13 @@ private static String formatRow(Row row) { } ``` -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html -[format()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- -[parse()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- -[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html -[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[TypeCodec]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html +[format()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#format-JavaTypeT- +[parse()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodec.html#parse-java.lang.String- +[MappingCodec]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/MappingCodec.html +[SessionBuilder.addTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addTypeCodecs-com.datastax.oss.driver.api.core.type.codec.TypeCodec...- [Enums]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html [Enum.name()]: https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#name-- @@ -691,37 +691,37 @@ private static String formatRow(Row row) { [java.time.LocalDateTime]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html [java.time.ZoneId]: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html -[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html -[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY -[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY -[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY -[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY -[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY -[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY -[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY -[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY -[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC -[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- -[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM -[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC -[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC -[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM -[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC -[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- -[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED -[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- -[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- -[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- -[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- -[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- -[ExtraTypeCodecs.floatVectorToArray(int)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#floatVectorToArray-int- - -[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB -[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP +[ExtraTypeCodecs]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html +[ExtraTypeCodecs.BLOB_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BLOB_TO_ARRAY +[ExtraTypeCodecs.BOOLEAN_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BOOLEAN_LIST_TO_ARRAY +[ExtraTypeCodecs.BYTE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#BYTE_LIST_TO_ARRAY +[ExtraTypeCodecs.SHORT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#SHORT_LIST_TO_ARRAY +[ExtraTypeCodecs.INT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#INT_LIST_TO_ARRAY +[ExtraTypeCodecs.LONG_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LONG_LIST_TO_ARRAY +[ExtraTypeCodecs.FLOAT_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#FLOAT_LIST_TO_ARRAY +[ExtraTypeCodecs.DOUBLE_LIST_TO_ARRAY]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#DOUBLE_LIST_TO_ARRAY +[ExtraTypeCodecs.listToArrayOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#listToArrayOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_UTC +[ExtraTypeCodecs.timestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampAt-java.time.ZoneId- +[ExtraTypeCodecs.TIMESTAMP_MILLIS_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_SYSTEM +[ExtraTypeCodecs.TIMESTAMP_MILLIS_UTC]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#TIMESTAMP_MILLIS_UTC +[ExtraTypeCodecs.timestampMillisAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#timestampMillisAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_UTC +[ExtraTypeCodecs.zonedTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#zonedTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.LOCAL_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_SYSTEM +[ExtraTypeCodecs.LOCAL_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#LOCAL_TIMESTAMP_UTC +[ExtraTypeCodecs.localTimestampAt(ZoneId)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#localTimestampAt-java.time.ZoneId- +[ExtraTypeCodecs.ZONED_TIMESTAMP_PERSISTED]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#ZONED_TIMESTAMP_PERSISTED +[ExtraTypeCodecs.optionalOf(TypeCodec)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#optionalOf-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[ExtraTypeCodecs.enumNamesOf(Class)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumNamesOf-java.lang.Class- +[ExtraTypeCodecs.enumOrdinalsOf(Class)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#enumOrdinalsOf-java.lang.Class- +[ExtraTypeCodecs.json(Class)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class- +[ExtraTypeCodecs.json(Class, ObjectMapper)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#json-java.lang.Class-com.fasterxml.jackson.databind.ObjectMapper- +[ExtraTypeCodecs.floatVectorToArray(int)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/ExtraTypeCodecs.html#floatVectorToArray-int- + +[TypeCodecs.BLOB]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#BLOB +[TypeCodecs.TIMESTAMP]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#TIMESTAMP [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index a0f38d11f74..3218eecc5e6 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -137,13 +137,13 @@ Even then, the defaults used by detached objects might be good enough for you: Otherwise, just make sure you reattach objects any time you deserialize them or create them from scratch. -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html -[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT -[DataType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/DataType.html -[Detachable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/detach/Detachable.html -[Session]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html -[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html -[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html +[CodecRegistry#DEFAULT]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html#DEFAULT +[DataType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/DataType.html +[Detachable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/detach/Detachable.html +[Session]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html +[ColumnDefinition]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ColumnDefinition.html +[Row]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html [Java serialization]: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html [protocol specifications]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index 79470ec946b..79a4c034052 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -166,9 +166,9 @@ All geospatial types interoperate with three standard formats: [ESRI]: https://github.com/Esri/geometry-api-java -[LineString]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/data/geometry/LineString.html -[Point]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/data/geometry/Point.html -[Polygon]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/data/geometry/Polygon.html +[LineString]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/data/geometry/LineString.html +[Point]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/data/geometry/Point.html +[Polygon]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/data/geometry/Polygon.html [Well-known text]: https://en.wikipedia.org/wiki/Well-known_text [Well-known binary]: https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index bc9669634ee..9d6ef39f2f3 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -74,8 +74,8 @@ fluent API returns Apache TinkerPop™ types directly. [Apache TinkerPop™]: http://tinkerpop.apache.org/ -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html -[GraphSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/GraphSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html +[GraphSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/GraphSession.html [DSE developer guide]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphTOC.html [Gremlin]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dseGraphAbout.html#dseGraphAbout__what-is-cql diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index b7027490b33..9201470b6a5 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -109,8 +109,8 @@ All the DSE predicates are available on the driver side: .values("name"); ``` -[Search]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/predicates/Search.html -[Geo]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/predicates/Geo.html +[Search]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/predicates/Search.html +[Geo]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/predicates/Geo.html [Apache TinkerPop™]: http://tinkerpop.apache.org/ [TinkerPop DSL]: http://tinkerpop.apache.org/docs/current/reference/#dsl diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index b7741a0de2b..f3d8072dcb9 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -105,9 +105,9 @@ added in a future version. See also the [parent page](../) for topics common to all fluent traversals. -[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html -[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- -[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html -[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- -[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- +[FluentGraphStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html +[FluentGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#newInstance-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[FluentGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/FluentGraphStatement.html#builder-org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal- +[BatchGraphStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html +[BatchGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#newInstance-- +[BatchGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/BatchGraphStatement.html#builder-- diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index fa98525c756..9e1a357a443 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -137,8 +137,8 @@ If a type doesn't have a corresponding `asXxx()` method, use the variant that ta UUID uuid = graphNode.as(UUID.class); ``` -[GraphNode]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/GraphNode.html -[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/GraphResultSet.html -[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html +[GraphNode]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/GraphNode.html +[GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/GraphResultSet.html +[AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html [DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index b191cc7db7c..2b98664ea16 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -101,6 +101,6 @@ Note however that some types of queries can only be performed through the script * configuration; * DSE graph schema queries. -[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html -[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html +[ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index 8eb9135488a..3746825390a 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -60,5 +60,5 @@ assert bs.isIdempotent(); The query builder tries to infer idempotence automatically; refer to [its manual](../../query_builder/idempotence/) for more details. -[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- -[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- +[Statement.setIdempotent]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html#setIdempotent-java.lang.Boolean- +[StatementBuilder.setIdempotence]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setIdempotence-java.lang.Boolean- diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 02d0d97027b..32237df8818 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -562,6 +562,7 @@ Here are the recommended TinkerPop versions for each driver version:

    Driver versionTinkerPop version
    4.16.03.5.3
    4.15.03.5.3
    4.14.13.5.3
    4.14.03.4.10
    + @@ -666,6 +667,6 @@ The remaining core driver dependencies are the only ones that are truly mandator [guava]: https://github.com/google/guava/issues/2721 [annotation processing]: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#sthref65 -[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- -[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- -[Uuids]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/uuid/Uuids.html +[Session.getMetrics]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#getMetrics-- +[SessionBuilder.addContactPoint]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoint-java.net.InetSocketAddress- +[Uuids]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/uuid/Uuids.html diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index abc950fe378..2b60dcb1580 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -426,12 +426,12 @@ Then it uses the "closest" distance for any given node. For example: * policy1 changes its suggestion to IGNORED. node1 is set to REMOTE; * policy1 changes its suggestion to REMOTE. node1 stays at REMOTE. -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html -[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/context/DriverContext.html +[LoadBalancingPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.html [BasicLoadBalancingPolicy]: https://github.com/datastax/java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java -[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- -[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- -[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- -[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html +[getRoutingKeyspace()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKeyspace-- +[getRoutingToken()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Request.html#getRoutingToken-- +[getRoutingKey()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[NodeDistanceEvaluator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/loadbalancing/NodeDistanceEvaluator.html [`nodetool status`]: https://docs.datastax.com/en/dse/6.7/dse-dev/datastax_enterprise/tools/nodetool/toolsStatus.html [cqlsh]: https://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/startCqlshStandalone.html diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index 34358bfdf5e..1bb07483869 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -56,6 +56,6 @@ new keyspace in the schema metadata before the token metadata was updated. Schema and node state events are debounced. This allows you to control how often the metadata gets refreshed. See the [Performance](../performance/#debouncing) page for more details. -[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- -[Metadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- +[Metadata]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Metadata.html +[Node]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index ae66a468fd3..0f0b6176f42 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -129,17 +129,17 @@ beyond the scope of this document; if you're interested, study the `TopologyMoni the source code. -[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- -[Node]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html -[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- -[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- -[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- -[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- -[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- -[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- -[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- -[NodeState]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeState.html -[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html -[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html -[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- -[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html +[Metadata#getNodes]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Metadata.html#getNodes-- +[Node]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html +[Node#getState()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getState-- +[Node#getDatacenter()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getDatacenter-- +[Node#getRack()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getRack-- +[Node#getDistance()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getDistance-- +[Node#getExtras()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getExtras-- +[Node#getOpenConnections()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- +[Node#isReconnecting()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#isReconnecting-- +[NodeState]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/NodeState.html +[NodeStateListener]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/NodeStateListener.html +[NodeStateListenerBase]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/NodeStateListenerBase.html +[SessionBuilder.addNodeStateListener]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addNodeStateListener-com.datastax.oss.driver.api.core.metadata.NodeStateListener- +[DseNodeProperties]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/metadata/DseNodeProperties.html diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index c42e56e5735..ed2c4c70750 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -321,16 +321,16 @@ unavailable for the excluded keyspaces. If you issue schema-altering requests from the driver (e.g. `session.execute("CREATE TABLE ..")`), take a look at the [Performance](../../performance/#schema-updates) page for a few tips. -[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- -[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html -[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html -[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- -[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- -[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- -[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- -[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html -[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html -[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html +[Metadata#getKeyspaces]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Metadata.html#getKeyspaces-- +[SchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListener.html +[SchemaChangeListenerBase]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/schema/SchemaChangeListenerBase.html +[Session#setSchemaMetadataEnabled]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#setSchemaMetadataEnabled-java.lang.Boolean- +[Session#checkSchemaAgreementAsync]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#checkSchemaAgreementAsync-- +[SessionBuilder#addSchemaChangeListener]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addSchemaChangeListener-com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener- +[ExecutionInfo#isSchemaInAgreement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#isSchemaInAgreement-- +[com.datastax.dse.driver.api.core.metadata.schema]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/metadata/schema/package-frame.html +[DseFunctionMetadata]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadata.html +[DseAggregateMetadata]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadata.html [JAVA-750]: https://datastax-oss.atlassian.net/browse/JAVA-750 [java.util.regex.Pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index 475274fd4e4..1c6a9c08ae7 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -169,5 +169,5 @@ on [schema metadata](../schema/). If schema metadata is disabled or filtered, to also be unavailable for the excluded keyspaces. -[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 23df7ed9eec..73f5cad3f21 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -135,6 +135,6 @@ If you want to see the details of mixed cluster negotiation, enable `DEBUG` leve [protocol spec]: https://github.com/datastax/native-protocol/tree/1.x/src/main/resources [driver3]: https://docs.datastax.com/en/developer/java-driver/3.10/manual/native_protocol/ -[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- -[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- -[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- +[ExecutionInfo.getWarnings]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getWarnings-- +[Request.getCustomPayload]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Request.html#getCustomPayload-- +[AttachmentPoint.getProtocolVersion]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/detach/AttachmentPoint.html#getProtocolVersion-- diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 0960379936b..a40779f8e11 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -49,22 +49,22 @@ For example, calling any synchronous method declared in [`SyncCqlSession`], such will block until the result is available. These methods should never be used in non-blocking applications. -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` -[`execute`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`execute`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html#execute-com.datastax.oss.driver.api.core.cql.Statement- However, the asynchronous methods declared in [`AsyncCqlSession`], such as [`executeAsync`], are all safe for use in non-blocking applications; the statement execution and asynchronous result delivery is guaranteed to never block. -[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html -[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`AsyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html +[`executeAsync`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncCqlSession.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- The same applies to the methods declared in [`ReactiveSession`] such as [`executeReactive`]: the returned publisher will never block when subscribed to, until the final results are delivered to the subscriber. -[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[`executeReactive`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html#executeReactive-com.datastax.oss.driver.api.core.cql.Statement- There is one exception though: continuous paging queries (a feature specific to DSE) have a special execution model which uses internal locks for coordination. Although such locks are only held for @@ -77,10 +77,10 @@ reactive APIs like [`executeContinuouslyAsync`] and [`executeContinuouslyReactiv though, continuous paging is extremely efficient and can safely be used in most non-blocking contexts, unless they require strict lock-freedom. -[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html -[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html -[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- -[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- +[`ContinuousSession`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html +[`ContinuousReactiveSession`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html +[`executeContinuouslyAsync`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/continuous/ContinuousSession.html#executeContinuouslyAsync-com.datastax.oss.driver.api.core.cql.Statement- +[`executeContinuouslyReactive`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousReactiveSession.html#executeContinuouslyReactive-com.datastax.oss.driver.api.core.cql.Statement- #### Driver lock-free guarantees per session lifecycle phases @@ -110,8 +110,8 @@ Similarly, a call to [`SessionBuilder.build()`] should be considered blocking as calling thread and wait until the method returns. For this reason, calls to `SessionBuilder.build()` should be avoided in non-blocking applications. -[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- -[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- +[`SessionBuilder.buildAsync()`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#buildAsync-- +[`SessionBuilder.build()`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#build-- Once the session is initialized, however, the driver is guaranteed to be non-blocking during the session's lifecycle, and under normal operation, unless otherwise noted elsewhere in this document. @@ -121,8 +121,8 @@ during that phase. Therefore, calls to any method declared in [`AsyncAutoCloseab asynchronous ones like [`closeAsync()`], should also be preferably deferred until the application is shut down and lock-freedom enforcement is disabled. -[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html -[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- +[`AsyncAutoCloseable`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html +[`closeAsync()`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AsyncAutoCloseable.html#closeAsync-- #### Driver lock-free guarantees for specific components @@ -131,7 +131,7 @@ Certain driver components are not implemented in lock-free algorithms. For example, [`SafeInitNodeStateListener`] is implemented with internal locks for coordination. It should not be used if strict lock-freedom is enforced. -[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html +[`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html The same is valid for both built-in [request throttlers]: @@ -143,7 +143,7 @@ use locks internally, and depending on how many requests are being executed in p contention on these locks can be high: in short, if your application enforces strict lock-freedom, then these components should not be used. -[request throttlers]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html +[request throttlers]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html Other components may be lock-free, *except* for their first invocation. This is the case of the following items: @@ -151,8 +151,8 @@ following items: * All built-in implementations of [`TimestampGenerator`], upon instantiation; * The utility method [`Uuids.timeBased()`]. -[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/time/TimestampGenerator.html -[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- +[`TimestampGenerator`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[`Uuids.timeBased()`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/uuid/Uuids.html#timeBased-- Both components need to access native libraries when they get initialized and this may involve hitting the local filesystem, thus causing the initialization to become a blocking call. @@ -172,7 +172,7 @@ One component, the codec registry, can block when its [`register`] method is cal therefore advised that codecs should be registered during application startup exclusively. See the [custom codecs](../custom_codecs) section for more details about registering codecs. -[`register`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- +[`register`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/MutableCodecRegistry.html#register-com.datastax.oss.driver.api.core.type.codec.TypeCodec- Finally, a few internal components also use locks, but only during session initialization; once the session is ready, they are either discarded, or don't use locks anymore for the rest of the @@ -213,7 +213,7 @@ lock-freedom enforcement tools could report calls to that method, but it was imp these calls. Thanks to [JAVA-2449], released with driver 4.10.0, `Uuids.random()` became a non-blocking call and random UUIDs can now be safely generated in non-blocking applications. -[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- +[`Uuids.random()`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/uuid/Uuids.html#random-- [JAVA-2449]: https://datastax-oss.atlassian.net/browse/JAVA-2449 #### Driver lock-free guarantees when reloading the configuration @@ -228,8 +228,8 @@ detectors. If that is the case, it is advised to disable hot-reloading by settin `datastax-java-driver.basic.config-reload-interval` option to 0. See the manual page on [configuration](../configuration) for more information. -[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html -[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- +[`DriverConfigLoader`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html +[hot-reloading]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#supportsReloading-- #### Driver lock-free guarantees when connecting to DSE diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index d08d92e8f36..761a6bfbc66 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -253,12 +253,12 @@ protocol page size and the logical page size to the same value. The [driver examples] include two complete web service implementations demonstrating forward-only and offset paging. -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- -[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- -[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/paging/OffsetPager.html -[PagingState]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/PagingState.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncPagingIterable.hasMorePages]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#hasMorePages-- +[AsyncPagingIterable.fetchNextPage]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AsyncPagingIterable.html#fetchNextPage-- +[OffsetPager]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/paging/OffsetPager.html +[PagingState]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/PagingState.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index 90b379c59d6..aaaebdaa6c9 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -345,8 +345,8 @@ possible to reuse the same event loop group for I/O, admin tasks, and even your (the driver's internal code is fully asynchronous so it will never block any thread). The timer is the only one that will have to stay on a separate thread. -[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/AccessibleByName.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html -[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- -[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[AccessibleByName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/AccessibleByName.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlIdentifier.html +[CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[GenericType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index d0d2de7d128..ad9e6f97a02 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -170,5 +170,5 @@ you experience the issue, here's what to look out for: Try adding more connections per node. Thanks to the driver's hot-reload mechanism, you can do that at runtime and see the effects immediately. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html [CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index bc01ce41d4d..c851e023e14 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -187,9 +187,9 @@ Here is the order of precedence of all the methods described so far: 3. otherwise, if the timestamp generator assigned a timestamp, use it; 4. otherwise, let the server assign the timestamp. -[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/time/TimestampGenerator.html +[TimestampGenerator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/time/TimestampGenerator.html [gettimeofday]: http://man7.org/linux/man-pages/man2/settimeofday.2.html [JNR]: https://github.com/jnr/jnr-posix [Lightweight transactions]: https://docs.datastax.com/en/dse/6.0/cql/cql/cql_using/useInsertLWT.html -[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- +[Statement.setQueryTimestamp()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html#setQueryTimestamp-long- diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index 6073ac4bf98..d0182c4fbc2 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -367,18 +367,18 @@ Note that the driver already has a [built-in retry mechanism] that can transpare queries; the above example should be seen as a demonstration of application-level retries, when a more fine-grained control of what should be retried, and how, is required. -[CqlSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html -[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html -[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html -[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- -[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- -[wasApplied]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- -[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- -[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- -[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- +[CqlSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html +[ReactiveSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveSession.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ReactiveRow]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html +[Row]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html +[getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getColumnDefinitions-- +[getExecutionInfos]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#getExecutionInfos-- +[wasApplied]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html#wasApplied-- +[ReactiveRow.getColumnDefinitions]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getColumnDefinitions-- +[ReactiveRow.getExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#getExecutionInfo-- +[ReactiveRow.wasApplied]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveRow.html#wasApplied-- [built-in retry mechanism]: ../retries/ [request throttling]: ../throttling/ diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index c383b887fcc..b27dd19aa27 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -84,7 +84,7 @@ Note that the session is not accessible until it is fully ready: the `CqlSession call — or the future returned by `buildAsync()` — will not complete until the connection was established. -[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html -[DriverContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/context/DriverContext.html -[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html +[DriverContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/context/DriverContext.html +[ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index 4186139c0ba..0862654e53f 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -123,5 +123,5 @@ all FROM users WHERE user_id=? [v0=42] com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined column name all ``` -[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[RequestTracker]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/tracker/RequestTracker.html +[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index 6e150eb77e4..cdd3a5740a2 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -231,21 +231,21 @@ configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html -[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/DriverTimeoutException.html -[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html -[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/HeartbeatException.html -[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html -[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html -[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html -[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html -[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html -[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/retry/RetryDecision.html -[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/retry/RetryPolicy.html -[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/retry/RetryVerdict.html -[ServerError]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/ServerError.html -[TruncateException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/TruncateException.html -[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html -[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html -[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[ClosedConnectionException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/ClosedConnectionException.html +[DriverTimeoutException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/DriverTimeoutException.html +[FunctionFailureException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/FunctionFailureException.html +[HeartbeatException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/HeartbeatException.html +[ProtocolError]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/ProtocolError.html +[OverloadedException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/OverloadedException.html +[QueryValidationException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/QueryValidationException.html +[ReadFailureException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/ReadFailureException.html +[ReadTimeoutException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/ReadTimeoutException.html +[RetryDecision]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/retry/RetryDecision.html +[RetryPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/retry/RetryPolicy.html +[RetryVerdict]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/retry/RetryVerdict.html +[ServerError]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/ServerError.html +[TruncateException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/TruncateException.html +[UnavailableException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/UnavailableException.html +[WriteFailureException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/WriteFailureException.html +[WriteTimeoutException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/servererrors/WriteTimeoutException.html diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index cf6675e9dbf..53913a6eda7 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -250,4 +250,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index 2e293d7e346..37396c6d4c0 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -204,6 +204,6 @@ the box, but with a bit of custom development it is fairly easy to add. See [dsClientToNode]: https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html [pickle]: http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html [JSSE system properties]: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization -[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- -[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- -[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html +[SessionBuilder.withSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslEngineFactory-com.datastax.oss.driver.api.core.ssl.SslEngineFactory- +[SessionBuilder.withSslContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withSslContext-javax.net.ssl.SSLContext- +[ProgrammaticSslEngineFactory]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.html diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index 08646b77609..f02806fb940 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -59,7 +59,7 @@ the [configuration](../configuration/). Namely, these are: idempotent flag, quer consistency levels and page size. We recommended the configuration approach whenever possible (you can create execution profiles to capture common combinations of those options). -[Statement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html -[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/StatementBuilder.html -[execute]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- -[executeAsync]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- +[Statement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html +[StatementBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/StatementBuilder.html +[execute]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#execute-com.datastax.oss.driver.api.core.cql.Statement- +[executeAsync]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#executeAsync-com.datastax.oss.driver.api.core.cql.Statement- diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index 051a3a35df9..05e803770eb 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -61,8 +61,8 @@ In addition, simple statements with named parameters are currently not supported due to a [protocol limitation][CASSANDRA-10246] that will be fixed in a future version). If you try to execute such a batch, an `IllegalArgumentException` is thrown. -[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BatchStatement.html -[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- -[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BatchStatement.html +[BatchStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BatchStatement.html#newInstance-com.datastax.oss.driver.api.core.cql.BatchType- +[BatchStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BatchStatement.html#builder-com.datastax.oss.driver.api.core.cql.BatchType- [batch_dse]: http://docs.datastax.com/en/dse/6.7/cql/cql/cql_using/useBatch.html [CASSANDRA-10246]: https://issues.apache.org/jira/browse/CASSANDRA-10246 diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index 4100e864660..f9076b5b5b6 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -124,6 +124,6 @@ SimpleStatement statement = At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we'll probably deprecate `setRoutingKeyspace()`. -[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- +[token-aware routing]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- [CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index 29ad525fc42..d5a4739c11b 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -330,10 +330,10 @@ With Cassandra 4 and [native protocol](../../native_protocol/) v5, this issue is new version with the response; the driver updates its local cache transparently, and the client can observe the new columns in the result set. -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[Session.prepare]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [CASSANDRA-10786]: https://issues.apache.org/jira/browse/CASSANDRA-10786 [CASSANDRA-10813]: https://issues.apache.org/jira/browse/CASSANDRA-10813 [guava eviction]: https://github.com/google/guava/wiki/CachesExplained#reference-based-eviction -[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- -[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- +[PreparedStatement.bind]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#bind-java.lang.Object...- +[PreparedStatement.boundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/PreparedStatement.html#boundStatementBuilder-java.lang.Object...- diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index d4f62e0a207..df56698b4ee 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -182,6 +182,6 @@ session.execute( Or you could also use [prepared statements](../prepared/), which don't have this limitation since parameter types are known in advance. -[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SimpleStatement.html -[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- -[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- +[SimpleStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/SimpleStatement.html +[SimpleStatement.newInstance()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#newInstance-java.lang.String- +[SimpleStatement.builder()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/SimpleStatement.html#builder-java.lang.String- diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index 2bb0573ce90..2128f822694 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -146,7 +146,7 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]" ``` -[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/CqlDuration.html -[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM -[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[CqlDuration]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/CqlDuration.html +[TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM +[TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index f1496cbf176..0e1605dafb5 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -145,6 +145,6 @@ datastax-java-driver { If you enable `throttling.delay`, make sure to also check the associated extra options to correctly size the underlying histograms (`metrics.session.throttling.delay.*`). -[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/RequestThrottlingException.html -[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/RequestThrottlingException.html +[AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AllNodesFailedException.html +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index 858b089ffbe..f3154600f9f 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -113,9 +113,9 @@ for (TraceEvent event : trace.getEvents()) { If you call `getQueryTrace()` for a statement that didn't have tracing enabled, an exception is thrown. -[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html -[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/QueryTrace.html -[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- -[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- -[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- -[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[ExecutionInfo]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html +[QueryTrace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/QueryTrace.html +[Statement.setTracing()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html#setTracing-boolean- +[StatementBuilder.setTracing()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/StatementBuilder.html#setTracing-- +[ExecutionInfo.getTracingId()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getTracingId-- +[ExecutionInfo.getQueryTrace()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index e5bda3947a6..69c2f24a46b 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -139,5 +139,5 @@ BoundStatement bs = [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html -[TupleType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/TupleType.html -[TupleValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/TupleValue.html +[TupleType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/TupleType.html +[TupleValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/TupleValue.html diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index 99c34f234c4..f45cf658b89 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -135,5 +135,5 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/UdtValue.html +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index 36db9562032..a09d1c9fd63 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -101,8 +101,8 @@ public interface ExecutionInfo { When a public API method is blocking, this is generally clearly stated in its javadocs. -[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- -[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` +[`ExecutionInfo.getQueryTrace()`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html#getQueryTrace-- +[`SyncCqlSession`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/SyncCqlSession.html` `BlockingOperation` is a utility to check that those methods aren't called on I/O threads, which could introduce deadlocks. diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index 50809f8a7f2..4ee234ffa14 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -106,4 +106,4 @@ before compilation: [build.gradle]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/build.gradle [UserDao.kt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/kotlin/src/main/kotlin/com/datastax/examples/mapper/killrvideo/user/UserDao.kt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index 8d6f9621b47..7466812fc9b 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -27,7 +27,7 @@ You need to build with Java 14, and pass the `--enable-preview` flag to both the runtime JVM. See [pom.xml] in the example. -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html [DataStax-Examples/object-mapper-jvm/record]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/record [pom.xml]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/record/pom.xml diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index e0d1970c209..b043bd784ad 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -54,4 +54,4 @@ mapper builder. [DataStax-Examples/object-mapper-jvm/scala]: https://github.com/DataStax-Examples/object-mapper-jvm/tree/master/scala [build.sbt]: https://github.com/DataStax-Examples/object-mapper-jvm/blob/master/scala/build.sbt -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index c55a10cc3ba..e76dde55314 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -148,8 +148,8 @@ In this case, any annotations declared in `Dao1` would be chosen over `Dao2`. To control how the hierarchy is scanned, annotate interfaces with [@HierarchyScanStrategy]. -[@Dao]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html [Entity Inheritance]: ../entities/#inheritance diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index ed5fd69a535..75e9733cb2f 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -236,8 +236,8 @@ flag: With this configuration, if a DAO method declares a non built-in return type, it will be surfaced as a compiler error. -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html -[GenericType]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/MapperContext.html -[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html -[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/entity/EntityHelper.html +[GenericType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/reflect/GenericType.html +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/MapperContext.html +[MapperResultProducer]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/result/MapperResultProducer.html +[MapperResultProducerService]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/result/MapperResultProducerService.html diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index 6d4ad9854cc..10f4ad249d2 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -151,15 +151,15 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@Delete]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Delete.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@Delete]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Delete.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index 6c37bb1169b..cea11e34d17 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -130,15 +130,15 @@ If the return type doesn't match the parameter type (for example [PagingIterable [AsyncResultSet]), the mapper processor will issue a compile-time error. -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[GettableByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/GettableByName.html -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[GettableByName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/GettableByName.html +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[Row]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/UdtValue.html [Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index 1c2c1f24d3c..c8e90a51627 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -75,12 +75,12 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[@Increment]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Increment.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Increment]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Increment.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/CqlName.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index 2d4a08fb694..bfd95229e1b 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -108,13 +108,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Insert]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Insert]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[ResultSet#getExecutionInfo()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html#getExecutionInfo-- +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index aca631062db..e2858f43b4d 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -93,10 +93,10 @@ public interface UserDao extends InventoryDao { } ``` -[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[MapperException]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/MapperException.html -[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET -[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL +[@DefaultNullSavingStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/DefaultNullSavingStrategy.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[MapperException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/MapperException.html +[DO_NOT_SET]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#DO_NOT_SET +[SET_TO_NULL]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/entity/saving/NullSavingStrategy.html#SET_TO_NULL [CASSANDRA-7304]: https://issues.apache.org/jira/browse/CASSANDRA-7304 diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index d45063eb74c..0d4293b5f15 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -113,18 +113,18 @@ Then: query succeeds or not depends on whether the session that the mapper was built with has a [default keyspace]. -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Query]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Query.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[Row]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/Row.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Query]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Query.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[ResultSet#wasApplied()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[Row]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index e4958928c59..7c750bcce1f 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -137,11 +137,11 @@ Here is the full implementation: the desired [PagingIterable][PagingIterable]. -[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html -[providerClass]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- -[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- -[providerMethod]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- -[MapperContext]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/MapperContext.html -[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/EntityHelper.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html +[@QueryProvider]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html +[providerClass]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerClass-- +[entityHelpers]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#entityHelpers-- +[providerMethod]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/QueryProvider.html#providerMethod-- +[MapperContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/MapperContext.html +[EntityHelper]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/EntityHelper.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index 857e176552d..9d5357ad546 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -160,20 +160,20 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the [naming strategy](../../entities/#naming-strategy)). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html -[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- -[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- -[groupBy()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- -[limit()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- -[orderBy()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- -[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- -[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html -[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html -[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- -[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html +[allowFiltering()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html#allowFiltering-- +[customWhereClause()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html#customWhereClause-- +[groupBy()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html#groupBy-- +[limit()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html#limit-- +[orderBy()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html#orderBy-- +[perPartitionLimit()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html#perPartitionLimit-- +[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html +[PagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html +[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator-- +[MappedReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index de6701ada50..cedb6e3dc45 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -112,8 +112,8 @@ BoundStatement bind(Product product, BoundStatement statement); If you use a void method with [BoundStatement], the mapper processor will issue a compile-time warning. -[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html -[SettableByName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/SettableByName.html -[UdtValue]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/data/UdtValue.html +[@SetEntity]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/SetEntity.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[BoundStatementBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatementBuilder.html +[SettableByName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/SettableByName.html +[UdtValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/UdtValue.html diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index 141b619dd7f..aa11e065b4f 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -60,4 +60,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 610bc9fb4d7..6a14a4a6140 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -143,13 +143,13 @@ If a table was specified when creating the DAO, then the generated query targets Otherwise, it uses the default table name for the entity (which is determined by the name of the entity class and the naming convention). -[default keyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- -[@Update]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Update.html +[default keyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier- +[@Update]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Update.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html [Boolean]: https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Boolean.html [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html [CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html -[ResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/ResultSet.html -[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/cql/BoundStatement.html -[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html +[ResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html +[BoundStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html +[ReactiveResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index 72edc82ea66..b857203ef32 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -555,22 +555,22 @@ the same level. To control how the class hierarchy is scanned, annotate classes with [@HierarchyScanStrategy]. -[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html -[@CqlName]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/CqlName.html -[@Dao]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Dao.html -[@Entity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Entity.html -[NameConverter]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html -[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html -[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html -[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html -[@Computed]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Computed.html -[@Select]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Select.html -[@Insert]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Insert.html -[@Update]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Update.html -[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html -[@Query]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Query.html +[@ClusteringColumn]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/ClusteringColumn.html +[@CqlName]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/CqlName.html +[@Dao]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Dao.html +[@Entity]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Entity.html +[NameConverter]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/entity/naming/NameConverter.html +[NamingConvention]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/entity/naming/NamingConvention.html +[@NamingStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/NamingStrategy.html +[@PartitionKey]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PartitionKey.html +[@Computed]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Computed.html +[@Select]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Select.html +[@Insert]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Insert.html +[@Update]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Update.html +[@GetEntity]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/GetEntity.html +[@Query]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Query.html [aliases]: http://cassandra.apache.org/doc/latest/cql/dml.html?#aliases -[@Transient]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Transient.html -[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html -[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html -[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html +[@Transient]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Transient.html +[@TransientProperties]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/TransientProperties.html +[@HierarchyScanStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/HierarchyScanStrategy.html +[@PropertyStrategy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/PropertyStrategy.html diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 0a81816f9a3..18be59df1c4 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -230,8 +230,8 @@ InventoryMapper inventoryMapper = new InventoryMapperBuilder(session) You can also permanently disable validation of an individual entity by annotating it with `@SchemaHint(targetElement = NONE)`. -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html -[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html -[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html -[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html -[@Mapper]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/mapper/annotations/Mapper.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlIdentifier.html +[@DaoFactory]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/DaoFactory.html +[@DaoKeyspace]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/DaoKeyspace.html +[@DaoTable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/DaoTable.html +[@Mapper]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Mapper.html diff --git a/manual/osgi/README.md b/manual/osgi/README.md index 966d89c12a6..88254334f25 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -138,7 +138,7 @@ starting the driver: [driver configuration]: ../core/configuration [OSGi]:https://www.osgi.org [JNR]: https://github.com/jnr/jnr-posix -[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- +[withClassLoader()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withClassLoader-java.lang.ClassLoader- [JAVA-1127]:https://datastax-oss.atlassian.net/browse/JAVA-1127 -[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- -[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- +[DriverConfigLoader.fromDefaults(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#fromDefaults-java.lang.ClassLoader- +[DriverConfigLoader.programmaticBuilder(ClassLoader)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/config/DriverConfigLoader.html#programmaticBuilder-java.lang.ClassLoader- diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index 4677fb84145..b9ea6a36205 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -212,8 +212,8 @@ For a complete tour of the API, browse the child pages in this manual: * [Terms](term/) * [Idempotence](idempotence/) -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/CqlIdentifier.html -[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html -[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlIdentifier.html +[DseQueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/querybuilder/DseQueryBuilder.html +[DseSchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/querybuilder/DseSchemaBuilder.html diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index 01897774c85..0530b33d5bc 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -132,4 +132,4 @@ It is mutually exclusive with column conditions: if you previously specified col the statement, they will be ignored; conversely, adding a column condition cancels a previous IF EXISTS clause. -[Condition]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/condition/Condition.html +[Condition]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/condition/Condition.html diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index 2aff86a6825..031291c311f 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -141,5 +141,5 @@ deleteFrom("user") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index 269afba7437..ede99602af0 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -114,4 +114,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index c4d4990affa..3c72e28cbee 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -201,5 +201,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Relation]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/relation/Relation.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Relation]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/relation/Relation.html diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index de6d4bacd6c..e4021c3068f 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -44,4 +44,4 @@ element type: * [function](function/) * [aggregate](aggregate/) -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index fbdf36147e3..42f1952a105 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -76,4 +76,4 @@ dropAggregate("average").ifExists(); // DROP AGGREGATE IF EXISTS average ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index c77f6431b73..7d02f0f8349 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -92,4 +92,4 @@ dropFunction("log").ifExists(); // DROP FUNCTION IF EXISTS log ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index 9c590c1e79e..8541831c1f2 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -99,4 +99,4 @@ dropIndex("my_idx").ifExists(); // DROP INDEX IF EXISTS my_idx ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index a07af3479f4..25e165f32c1 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -83,6 +83,6 @@ dropKeyspace("cycling").ifExists(); // DROP KEYSPACE IF EXISTS cycling ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index 55c9cc41c07..7bcdda0bd3f 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -85,5 +85,5 @@ dropTable("cyclist_by_age").ifExists(); // DROP MATERIALIZED VIEW IF EXISTS cyclist_by_age ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[RelationStructure]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/schema/RelationStructure.html diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index a3000ee70db..8a68d676851 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -107,6 +107,6 @@ dropTable("cyclist_name").ifExists(); // DROP TABLE IF EXISTS cyclist_name ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html -[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html -[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[CreateTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.html +[AlterTableWithOptions]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/schema/AlterTableWithOptions.html diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index c5302843f7d..e474dc29419 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -88,4 +88,4 @@ dropTable("address").ifExists(); // DROP TYPE IF EXISTS address ``` -[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/SchemaBuilder.html diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index 42fd0410bcd..19f0085508a 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -391,5 +391,5 @@ selectFrom("user").all().allowFiltering(); // SELECT * FROM user ALLOW FILTERING ``` -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Selector]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/select/Selector.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Selector]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/select/Selector.html diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index 7fb94e0f31f..214dedb3274 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -105,5 +105,5 @@ This should be used with caution, as it's possible to generate invalid CQL that execution time; on the other hand, it can be used as a workaround to handle new CQL features that are not yet covered by the query builder. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index d877433dd2e..9b37160c0c9 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -17,4 +17,4 @@ Truncate truncate2 = truncate(CqlIdentifier.fromCql("mytable")); Note that, at this stage, the query is ready to build. After creating a TRUNCATE query it does not take any values. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index 1161d093bc4..d85f71f11cc 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -251,5 +251,5 @@ update("foo") Conditions are a common feature used by UPDATE and DELETE, so they have a [dedicated page](../condition) in this manual. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[Assignment]: https://docs.datastax.com/en/drivers/java/4.14/com/datastax/oss/driver/api/querybuilder/update/Assignment.html +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html +[Assignment]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/update/Assignment.html diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 60d66d06584..bfa72c7fa33 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index b98fd5028c1..104eb50bcde 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index ef4662d38ca..53ff1746e05 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index c038a1567c5..0096fbc7cd9 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index cfa28c25dba..1bce8e362a5 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index eae8a54ac55..83b9122c2c2 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 41395bda871..8a45cdf37c7 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 4c67bc35a1b..692285142ed 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.16.1-SNAPSHOT + 4.17.0-SNAPSHOT java-driver-test-infra bundle From c3f85ee7ba20f57a05ecd6d48a4aeada82055895 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 12 Jul 2023 17:34:30 -0500 Subject: [PATCH 263/395] [maven-release-plugin] prepare release 4.17.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 547658aea3b..5caea7d1b80 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-core-shaded - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-mapper-processor - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-mapper-runtime - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-query-builder - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-test-infra - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-metrics-micrometer - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss java-driver-metrics-microprofile - 4.17.0-SNAPSHOT + 4.17.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index bfeb0234b14..148d9626340 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index e29d1e95325..e16c4cab79a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index c478f049dcf..6287bbc2f2f 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 8af4d4c9a6d..de94f86bfd5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.17.0-SNAPSHOT + 4.17.0 java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 45cc458a586..1b58648ac49 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index bfa72c7fa33..6c9b632608d 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 104eb50bcde..ac1b3c69c8c 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 53ff1746e05..d0e4f4c9916 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 0096fbc7cd9..939ab981358 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 1bce8e362a5..4020913cacb 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 83b9122c2c2..c7eb22a8dee 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -1006,7 +1006,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.17.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 8a45cdf37c7..3d999ac0def 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 692285142ed..6b517768527 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0-SNAPSHOT + 4.17.0 java-driver-test-infra bundle From 8101fbf9ec91d952e90022606090a4be9f24aace Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 12 Jul 2023 17:34:38 -0500 Subject: [PATCH 264/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 5caea7d1b80..a60b9903fdc 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-bom pom @@ -31,42 +31,42 @@ com.datastax.oss java-driver-core - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-core-shaded - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-mapper-processor - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-mapper-runtime - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-query-builder - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-test-infra - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-metrics-micrometer - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss java-driver-metrics-microprofile - 4.17.0 + 4.17.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 148d9626340..5d0c902f31b 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-core-shaded DataStax Java driver for Apache Cassandra(R) - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index e16c4cab79a..c085bd1bcf0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-core bundle diff --git a/distribution/pom.xml b/distribution/pom.xml index 6287bbc2f2f..a1f857ac0f4 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index de94f86bfd5..00d07f29c16 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ java-driver-parent com.datastax.oss - 4.17.0 + 4.17.1-SNAPSHOT java-driver-examples DataStax Java driver for Apache Cassandra(R) - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 1b58648ac49..30f3207d06c 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 6c9b632608d..70a319b7775 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-mapper-processor DataStax Java driver for Apache Cassandra(R) - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index ac1b3c69c8c..e578cc4959f 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index d0e4f4c9916..e75c14e8c7e 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 939ab981358..af6f3b88616 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 4020913cacb..c80bca37e1d 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index c7eb22a8dee..0c20405b68e 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT pom DataStax Java driver for Apache Cassandra(R) A driver for Apache Cassandra(R) 2.1+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol versions 3 and above. @@ -1006,7 +1006,7 @@ height="0" width="0" style="display:none;visibility:hidden"> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.17.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 3d999ac0def..d5b53451712 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 6b517768527..474a915ffa1 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ com.datastax.oss java-driver-parent - 4.17.0 + 4.17.1-SNAPSHOT java-driver-test-infra bundle From 9d891b120069fd2029c4743c14bc7df248e2e14b Mon Sep 17 00:00:00 2001 From: hhughes Date: Thu, 13 Jul 2023 17:33:57 -0700 Subject: [PATCH 265/395] JAVA-3089: Forbid wildcard imports (#1680) --- .../type/codec/registry/CachingCodecRegistry.java | 11 ++++++++++- .../oss/driver/internal/core/os/JnrLibcTest.java | 2 +- .../datastax/oss/driver/mapper/DefaultKeyspaceIT.java | 4 ++-- pom.xml | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java index cb5d45255e1..34c503bfce5 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java @@ -19,7 +19,16 @@ import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; -import com.datastax.oss.driver.api.core.type.*; +import com.datastax.oss.driver.api.core.type.ContainerType; +import com.datastax.oss.driver.api.core.type.CustomType; +import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.driver.api.core.type.ListType; +import com.datastax.oss.driver.api.core.type.MapType; +import com.datastax.oss.driver.api.core.type.SetType; +import com.datastax.oss.driver.api.core.type.TupleType; +import com.datastax.oss.driver.api.core.type.UserDefinedType; +import com.datastax.oss.driver.api.core.type.VectorType; import com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrLibcTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrLibcTest.java index e3bf9a876db..9fd58a2b163 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrLibcTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrLibcTest.java @@ -15,7 +15,7 @@ */ package com.datastax.oss.driver.internal.core.os; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import java.time.Instant; import java.time.temporal.ChronoUnit; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultKeyspaceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultKeyspaceIT.java index 55f7aff9b62..8d9614bf97c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultKeyspaceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultKeyspaceIT.java @@ -15,7 +15,6 @@ */ package com.datastax.oss.driver.mapper; -import static com.datastax.oss.driver.api.mapper.MapperBuilder.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -25,6 +24,7 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; +import com.datastax.oss.driver.api.mapper.MapperBuilder; import com.datastax.oss.driver.api.mapper.MapperException; import com.datastax.oss.driver.api.mapper.annotations.Dao; import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; @@ -122,7 +122,7 @@ public void should_fail_to_insert_if_default_ks_and_dao_ks_not_provided() { () -> { InventoryMapperKsNotSet mapper = new DefaultKeyspaceIT_InventoryMapperKsNotSetBuilder(SESSION_RULE.session()) - .withCustomState(SCHEMA_VALIDATION_ENABLED_SETTING, false) + .withCustomState(MapperBuilder.SCHEMA_VALIDATION_ENABLED_SETTING, false) .build(); mapper.productDaoDefaultKsNotSet(); }) diff --git a/pom.xml b/pom.xml index 0c20405b68e..19adba12170 100644 --- a/pom.xml +++ b/pom.xml @@ -588,6 +588,7 @@ -Xep:FutureReturnValueIgnored:OFF -Xep:PreferJavaTimeOverload:OFF -Xep:AnnotateFormatMethod:OFF + -Xep:WildcardImport:WARN -XepExcludedPaths:.*/target/(?:generated-sources|generated-test-sources)/.* true From e8b25ab368a5cc8a59983ca8bd7b2020d07b19bd Mon Sep 17 00:00:00 2001 From: hhughes Date: Thu, 20 Jul 2023 12:16:13 -0700 Subject: [PATCH 266/395] JAVA-3077: ListenersIT intermittently failing with: Wanted but not invoked: schemaListener1.onSessionReady (#1670) ListenersIT.java: - Add 500ms wait on SchemaListener#onSessionReady call verification - Add latch to wait for MySchemaChangeListener#onSessionReady - Add some comments around which listeners/methods need synchronizations and why/not --- .../oss/driver/core/session/ListenersIT.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java index 690c00a0e9b..a7b847ad1e8 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/session/ListenersIT.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import com.datastax.oss.driver.api.core.CqlSession; @@ -33,9 +34,12 @@ import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -90,6 +94,9 @@ public void should_inject_session_in_listeners() throws Exception { .build()) .build()) { + // These NodeStateListeners are wrapped with SafeInitNodeStateListener which delays #onUp + // callbacks until #onSessionReady is called, these will all happen during session + // initialization InOrder inOrder1 = inOrder(nodeListener1); inOrder1.verify(nodeListener1).onSessionReady(session); inOrder1.verify(nodeListener1).onUp(nodeCaptor1.capture()); @@ -104,20 +111,29 @@ public void should_inject_session_in_listeners() throws Exception { assertThat(nodeCaptor2.getValue().getEndPoint()) .isEqualTo(SIMULACRON_RULE.getContactPoints().iterator().next()); - verify(schemaListener1).onSessionReady(session); - verify(schemaListener2).onSessionReady(session); + // SchemaChangeListener#onSessionReady is called asynchronously from AdminExecutor so we may + // have to wait a little + verify(schemaListener1, timeout(500).times(1)).onSessionReady(session); + verify(schemaListener2, timeout(500).times(1)).onSessionReady(session); + // Request tracker #onSessionReady is called synchronously during session initialization verify(requestTracker1).onSessionReady(session); verify(requestTracker2).onSessionReady(session); assertThat(MyNodeStateListener.onSessionReadyCalled).isTrue(); assertThat(MyNodeStateListener.onUpCalled).isTrue(); - assertThat(MySchemaChangeListener.onSessionReadyCalled).isTrue(); + // SchemaChangeListener#onSessionReady is called asynchronously from AdminExecutor so we may + // have to wait a little + assertThat( + Uninterruptibles.awaitUninterruptibly( + MySchemaChangeListener.onSessionReadyLatch, 500, TimeUnit.MILLISECONDS)) + .isTrue(); assertThat(MyRequestTracker.onSessionReadyCalled).isTrue(); } + // CqlSession#close waits for all listener close methods to be called verify(nodeListener1).close(); verify(nodeListener2).close(); @@ -163,14 +179,14 @@ public void close() { public static class MySchemaChangeListener extends SchemaChangeListenerBase { - private static volatile boolean onSessionReadyCalled = false; + private static CountDownLatch onSessionReadyLatch = new CountDownLatch(1); private static volatile boolean closeCalled = false; public MySchemaChangeListener(@SuppressWarnings("unused") DriverContext ignored) {} @Override public void onSessionReady(@NonNull Session session) { - onSessionReadyCalled = true; + onSessionReadyLatch.countDown(); } @Override From ec93ef9cdbde1b5fc5a694ebf09b375f76bcb373 Mon Sep 17 00:00:00 2001 From: hhughes Date: Thu, 20 Jul 2023 13:46:13 -0700 Subject: [PATCH 267/395] JAVA-3084: Add integration test coverage for ExtraTypeCodecs (#1679) --- .../core/type/codec/ExtraTypeCodecsIT.java | 298 ++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/ExtraTypeCodecsIT.java diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/ExtraTypeCodecsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/ExtraTypeCodecsIT.java new file mode 100644 index 00000000000..853f6993aec --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/ExtraTypeCodecsIT.java @@ -0,0 +1,298 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.type.codec; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.type.codec.ExtraTypeCodecs; +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; +import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.categories.ParallelizableTests; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; + +@Category(ParallelizableTests.class) +public class ExtraTypeCodecsIT { + + private static final CcmRule CCM_RULE = CcmRule.getInstance(); + + private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); + + @ClassRule + public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); + + private enum TableField { + cql_text("text_value", "text"), + cql_int("integer_value", "int"), + cql_vector("vector_value", "vector"), + cql_list_of_text("list_of_text_value", "list"), + cql_timestamp("timestamp_value", "timestamp"), + cql_boolean("boolean_value", "boolean"), + ; + + final String name; + final String ty; + + TableField(String name, String ty) { + this.name = name; + this.ty = ty; + } + + private String definition() { + return String.format("%s %s", name, ty); + } + } + + @BeforeClass + public static void setupSchema() { + List fieldDefinitions = new ArrayList<>(); + fieldDefinitions.add("key uuid PRIMARY KEY"); + Stream.of(TableField.values()) + .forEach( + tf -> { + // TODO: Move this check to BackendRequirementRule once JAVA-3069 is resolved. + if (tf == TableField.cql_vector + && CCM_RULE.getCassandraVersion().compareTo(Version.parse("5.0")) < 0) { + // don't add vector type before cassandra version 5.0 + return; + } + fieldDefinitions.add(tf.definition()); + }); + SESSION_RULE + .session() + .execute( + SimpleStatement.builder( + String.format( + "CREATE TABLE IF NOT EXISTS extra_type_codecs_it (%s)", + String.join(", ", fieldDefinitions))) + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + } + + private void insertAndRead(TableField field, T value, TypeCodec codec) { + CqlSession session = SESSION_RULE.session(); + // write value under new key using provided codec + UUID key = UUID.randomUUID(); + + PreparedStatement preparedInsert = + session.prepare( + SimpleStatement.builder( + String.format( + "INSERT INTO extra_type_codecs_it (key, %s) VALUES (?, ?)", field.name)) + .build()); + BoundStatement boundInsert = + preparedInsert + .boundStatementBuilder() + .setUuid("key", key) + .set(field.name, value, codec) + .build(); + session.execute(boundInsert); + + // read value using provided codec and assert result + PreparedStatement preparedSelect = + session.prepare( + SimpleStatement.builder( + String.format("SELECT %s FROM extra_type_codecs_it WHERE key = ?", field.name)) + .build()); + BoundStatement boundSelect = preparedSelect.boundStatementBuilder().setUuid("key", key).build(); + assertThat(session.execute(boundSelect).one().get(field.name, codec)).isEqualTo(value); + } + + @Test + public void enum_names_of() { + insertAndRead( + TableField.cql_text, TestEnum.value1, ExtraTypeCodecs.enumNamesOf(TestEnum.class)); + } + + @Test + public void enum_ordinals_of() { + insertAndRead( + TableField.cql_int, TestEnum.value1, ExtraTypeCodecs.enumOrdinalsOf(TestEnum.class)); + } + + // Also requires -Dccm.branch=vsearch and the ability to build that branch locally + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "5.0.0") + @Test + public void float_to_vector_array() { + // @BackRequirement on test methods that use @ClassRule to configure CcmRule require @Rule + // BackendRequirementRule included with fix JAVA-3069. Until then we will ignore this test with + // an assume. + Assume.assumeTrue( + "Requires Cassandra 5.0 or greater", + CCM_RULE.getCassandraVersion().compareTo(Version.parse("5.0")) >= 0); + insertAndRead( + TableField.cql_vector, + new float[] {1.1f, 0f, Float.NaN}, + ExtraTypeCodecs.floatVectorToArray(3)); + } + + @Test + public void json_java_class() { + insertAndRead( + TableField.cql_text, + new TestJsonAnnotatedPojo("example", Arrays.asList(1, 2, 3)), + ExtraTypeCodecs.json(TestJsonAnnotatedPojo.class)); + } + + @Test + public void json_java_class_and_object_mapper() { + insertAndRead( + TableField.cql_text, + TestPojo.create(1, "abc", "def"), + ExtraTypeCodecs.json(TestPojo.class, new ObjectMapper())); + } + + @Test + public void list_to_array_of() { + insertAndRead( + TableField.cql_list_of_text, + new String[] {"hello", "kitty"}, + ExtraTypeCodecs.listToArrayOf(TypeCodecs.TEXT)); + } + + @Test + public void local_timestamp_at() { + ZoneId systemZoneId = ZoneId.systemDefault(); + insertAndRead( + TableField.cql_timestamp, + LocalDateTime.now(systemZoneId).truncatedTo(ChronoUnit.MILLIS), + ExtraTypeCodecs.localTimestampAt(systemZoneId)); + } + + @Test + public void optional_of() { + insertAndRead( + TableField.cql_boolean, Optional.empty(), ExtraTypeCodecs.optionalOf(TypeCodecs.BOOLEAN)); + insertAndRead( + TableField.cql_boolean, Optional.of(true), ExtraTypeCodecs.optionalOf(TypeCodecs.BOOLEAN)); + } + + @Test + public void timestamp_at() { + ZoneId systemZoneId = ZoneId.systemDefault(); + insertAndRead( + TableField.cql_timestamp, + Instant.now().truncatedTo(ChronoUnit.MILLIS), + ExtraTypeCodecs.timestampAt(systemZoneId)); + } + + @Test + public void timestamp_millis_at() { + ZoneId systemZoneId = ZoneId.systemDefault(); + insertAndRead( + TableField.cql_timestamp, + Instant.now().toEpochMilli(), + ExtraTypeCodecs.timestampMillisAt(systemZoneId)); + } + + @Test + public void zoned_timestamp_at() { + ZoneId systemZoneId = ZoneId.systemDefault(); + insertAndRead( + TableField.cql_timestamp, + ZonedDateTime.now(systemZoneId).truncatedTo(ChronoUnit.MILLIS), + ExtraTypeCodecs.zonedTimestampAt(systemZoneId)); + } + + private enum TestEnum { + value1, + value2, + value3, + } + + // Public for JSON serialization + public static final class TestJsonAnnotatedPojo { + public final String info; + public final List values; + + @JsonCreator + public TestJsonAnnotatedPojo( + @JsonProperty("info") String info, @JsonProperty("values") List values) { + this.info = info; + this.values = values; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TestJsonAnnotatedPojo testJsonAnnotatedPojo = (TestJsonAnnotatedPojo) o; + return Objects.equals(info, testJsonAnnotatedPojo.info) + && Objects.equals(values, testJsonAnnotatedPojo.values); + } + + @Override + public int hashCode() { + return Objects.hash(info, values); + } + } + + public static final class TestPojo { + public int id; + public String[] messages; + + public static TestPojo create(int id, String... messages) { + TestPojo obj = new TestPojo(); + obj.id = id; + obj.messages = messages; + return obj; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TestPojo testPojo = (TestPojo) o; + return id == testPojo.id && Arrays.equals(messages, testPojo.messages); + } + + @Override + public int hashCode() { + int result = Objects.hash(id); + result = 31 * result + Arrays.hashCode(messages); + return result; + } + } +} From 60c9cbc51f29c3ae262f9ce53dfd923600efaab6 Mon Sep 17 00:00:00 2001 From: hhughes Date: Thu, 10 Aug 2023 11:04:57 -0700 Subject: [PATCH 268/395] JAVA-3100: Update jackson-databind to 2.13.4.1 and (#1694) jackson-jaxrs-json-provider to 2.13.4 to address recent CVEs Additional: - Remove unused maven property legacy-jackson.version --- core/revapi.json | 6 ++++++ pom.xml | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/revapi.json b/core/revapi.json index 63e2cef5a1e..318e29709ec 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -6950,6 +6950,12 @@ "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", "justification": "Refactorings in PR 1666" + }, + { + "code": "java.method.returnTypeChangedCovariantly", + "old": "method java.lang.Throwable java.lang.Throwable::fillInStackTrace() @ com.fasterxml.jackson.databind.deser.UnresolvedForwardReference", + "new": "method com.fasterxml.jackson.databind.deser.UnresolvedForwardReference com.fasterxml.jackson.databind.deser.UnresolvedForwardReference::fillInStackTrace()", + "justification": "Upgrade jackson-databind to 2.13.4.1 to address CVEs, API change cause: https://github.com/FasterXML/jackson-databind/issues/3419" } ] } diff --git a/pom.xml b/pom.xml index 19adba12170..8fa1bc52a34 100644 --- a/pom.xml +++ b/pom.xml @@ -57,9 +57,8 @@ 1.7.26 1.0.3 20230227 - 2.13.2 - 2.13.2.2 - 1.9.12 + 2.13.4 + 2.13.4.1 1.1.10.1 1.7.1 From ae99f7d83d4696411b4a21567f6febb489e964fe Mon Sep 17 00:00:00 2001 From: hhughes Date: Fri, 18 Aug 2023 15:55:11 -0700 Subject: [PATCH 269/395] JAVA-3095: Fix CREATE keyword in vector search example in upgrade guide. (#1693) --- upgrade_guide/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index 6310f220c3d..4f8288b96a1 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -28,7 +28,7 @@ try (CqlSession session = new CqlSessionBuilder().withLocalDatacenter("datacente session.execute("DROP KEYSPACE IF EXISTS test"); session.execute("CREATE KEYSPACE test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}"); session.execute("CREATE TABLE test.foo(i int primary key, j vector)"); - session.execute("CREAT CUSTOM INDEX ann_index ON test.foo(j) USING 'StorageAttachedIndex'"); + session.execute("CREATE CUSTOM INDEX ann_index ON test.foo(j) USING 'StorageAttachedIndex'"); session.execute("INSERT INTO test.foo (i, j) VALUES (1, [8, 2.3, 58])"); session.execute("INSERT INTO test.foo (i, j) VALUES (2, [1.2, 3.4, 5.6])"); session.execute("INSERT INTO test.foo (i, j) VALUES (5, [23, 18, 3.9])"); From f5605eabe58a092bbc9a11219c5007349e46ce75 Mon Sep 17 00:00:00 2001 From: hhughes Date: Fri, 18 Aug 2023 17:24:59 -0700 Subject: [PATCH 270/395] Update 4.x changelog for 3.11.4 release (#1691) --- changelog/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 6c8c236a6a4..cb272907b66 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -632,6 +632,11 @@ changelog](https://docs.datastax.com/en/developer/java-driver-dse/latest/changel - [bug] JAVA-1499: Wait for load balancing policy at cluster initialization - [new feature] JAVA-1495: Add prepared statements +## 3.11.4 +- [improvement] JAVA-3079: Upgrade Netty to 4.1.94, 3.x edition +- [improvement] JAVA-3082: Fix maven build for Apple-silicon +- [improvement] PR 1671: Fix LatencyAwarePolicy scale docstring + ## 3.11.3 - [improvement] JAVA-3023: Upgrade Netty to 4.1.77, 3.x edition From 4d6e2e793797325f8d2c6edcfb2593615cd39f62 Mon Sep 17 00:00:00 2001 From: Benoit TELLIER Date: Mon, 21 Aug 2023 12:25:26 +0700 Subject: [PATCH 271/395] Improve ByteBufPrimitiveCodec readBytes (#1617) --- .../core/protocol/ByteBufPrimitiveCodec.java | 21 +------ .../protocol/ByteBufPrimitiveCodecTest.java | 59 +++++++++++++++++++ 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodec.java index b7fc6350636..44815e99229 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodec.java @@ -114,8 +114,9 @@ public int readUnsignedShort(ByteBuf source) { public ByteBuffer readBytes(ByteBuf source) { int length = readInt(source); if (length < 0) return null; - ByteBuf slice = source.readSlice(length); - return ByteBuffer.wrap(readRawBytes(slice)); + byte[] bytes = new byte[length]; + source.readBytes(bytes); + return ByteBuffer.wrap(bytes); } @Override @@ -220,22 +221,6 @@ public void writeShortBytes(byte[] bytes, ByteBuf dest) { dest.writeBytes(bytes); } - // Reads *all* readable bytes from a buffer and return them. - // If the buffer is backed by an array, this will return the underlying array directly, without - // copy. - private static byte[] readRawBytes(ByteBuf buffer) { - if (buffer.hasArray() && buffer.readableBytes() == buffer.array().length) { - // Move the readerIndex just so we consistently consume the input - buffer.readerIndex(buffer.writerIndex()); - return buffer.array(); - } - - // Otherwise, just read the bytes in a new array - byte[] bytes = new byte[buffer.readableBytes()]; - buffer.readBytes(bytes); - return bytes; - } - private static String readString(ByteBuf source, int length) { try { String str = source.toString(source.readerIndex(), length, CharsetUtil.UTF_8); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java index 18ebb79ea59..2690de71cb0 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java @@ -164,6 +164,65 @@ public void should_read_bytes() { assertThat(Bytes.toHexString(bytes)).isEqualTo("0xcafebabe"); } + @Test + public void should_read_bytes_when_extra_data() { + ByteBuf source = + ByteBufs.wrap( + // length (as an int) + 0x00, + 0x00, + 0x00, + 0x04, + // contents + 0xca, + 0xfe, + 0xba, + 0xbe, + 0xde, + 0xda, + 0xdd); + ByteBuffer bytes = codec.readBytes(source); + assertThat(Bytes.toHexString(bytes)).isEqualTo("0xcafebabe"); + } + + @Test + public void read_bytes_should_udpate_reader_index() { + ByteBuf source = + ByteBufs.wrap( + // length (as an int) + 0x00, + 0x00, + 0x00, + 0x04, + // contents + 0xca, + 0xfe, + 0xba, + 0xbe, + 0xde, + 0xda, + 0xdd); + codec.readBytes(source); + + assertThat(source.readerIndex()).isEqualTo(8); + } + + @Test + public void read_bytes_should_throw_when_not_enough_content() { + ByteBuf source = + ByteBufs.wrap( + // length (as an int) : 4 bytes + 0x00, + 0x00, + 0x00, + 0x04, + // contents : only 2 bytes + 0xca, + 0xfe); + assertThatThrownBy(() -> codec.readBytes(source)) + .isInstanceOf(IndexOutOfBoundsException.class); + } + @Test public void should_read_null_bytes() { ByteBuf source = ByteBufs.wrap(0xFF, 0xFF, 0xFF, 0xFF); // -1 (as an int) From 511ac4ecca3a575e73a51e32a3db47a509eb9859 Mon Sep 17 00:00:00 2001 From: Chris Lin <99268912+chrislin22@users.noreply.github.com> Date: Mon, 21 Aug 2023 11:52:36 -0400 Subject: [PATCH 272/395] removed auto trigger snyk and clean on PR --- .github/workflows/snyk-cli-scan.yml | 4 ---- .github/workflows/snyk-pr-cleanup.yml | 5 ----- 2 files changed, 9 deletions(-) diff --git a/.github/workflows/snyk-cli-scan.yml b/.github/workflows/snyk-cli-scan.yml index 50d303a128b..f78bc163934 100644 --- a/.github/workflows/snyk-cli-scan.yml +++ b/.github/workflows/snyk-cli-scan.yml @@ -1,10 +1,6 @@ name: 🔬 Snyk cli SCA on: - push: - branches: [ 4.x ] - pull_request: - branches: [ 4.x ] workflow_dispatch: env: diff --git a/.github/workflows/snyk-pr-cleanup.yml b/.github/workflows/snyk-pr-cleanup.yml index 9c3136bef82..27208c8c0a8 100644 --- a/.github/workflows/snyk-pr-cleanup.yml +++ b/.github/workflows/snyk-pr-cleanup.yml @@ -1,11 +1,6 @@ name: 🗑️ Snyk PR cleanup - merged/closed on: - pull_request: - types: - - closed - branches: - - 4.x workflow_dispatch: jobs: From 1b19116d0d70dc95a2783b8ef53a269770060698 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 21 Aug 2023 12:02:35 -0500 Subject: [PATCH 273/395] Fixing formatting error from recent commit --- .../internal/core/protocol/ByteBufPrimitiveCodecTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java index 2690de71cb0..e2bfb43e891 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/protocol/ByteBufPrimitiveCodecTest.java @@ -219,8 +219,7 @@ public void read_bytes_should_throw_when_not_enough_content() { // contents : only 2 bytes 0xca, 0xfe); - assertThatThrownBy(() -> codec.readBytes(source)) - .isInstanceOf(IndexOutOfBoundsException.class); + assertThatThrownBy(() -> codec.readBytes(source)).isInstanceOf(IndexOutOfBoundsException.class); } @Test From 9982bc6328b8d8a0599ca86b2386a49e95b1411b Mon Sep 17 00:00:00 2001 From: Chris Lin <99268912+chrislin22@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:13:25 -0400 Subject: [PATCH 274/395] removed all snyk related stuff --- .github/workflows/snyk-cli-scan.yml | 43 --------------------------- .github/workflows/snyk-pr-cleanup.yml | 11 ------- 2 files changed, 54 deletions(-) delete mode 100644 .github/workflows/snyk-cli-scan.yml delete mode 100644 .github/workflows/snyk-pr-cleanup.yml diff --git a/.github/workflows/snyk-cli-scan.yml b/.github/workflows/snyk-cli-scan.yml deleted file mode 100644 index f78bc163934..00000000000 --- a/.github/workflows/snyk-cli-scan.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: 🔬 Snyk cli SCA - -on: - workflow_dispatch: - -env: - SNYK_SEVERITY_THRESHOLD_LEVEL: high - -jobs: - snyk-cli-scan: - runs-on: ubuntu-latest - steps: - - name: Git checkout - uses: actions/checkout@v3 - - - name: prepare for snyk scan - uses: datastax/shared-github-actions/actions/snyk-prepare@main - - - name: Set up JDK 8 - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '8' - cache: maven - - - name: run maven install prepare for snyk - run: | - mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true - - - name: snyk scan java - uses: datastax/shared-github-actions/actions/snyk-scan-java@main - with: - directories: . - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - SNYK_ORG_ID: ${{ secrets.SNYK_ORG_ID }} - extra-snyk-options: "-DskipTests -Dmaven.javadoc.skip=true" - - - name: Snyk scan result - uses: datastax/shared-github-actions/actions/snyk-process-scan-results@main - with: - gh_repo_token: ${{ secrets.GITHUB_TOKEN }} - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - SNYK_ORG_ID: ${{ secrets.SNYK_ORG_ID }} diff --git a/.github/workflows/snyk-pr-cleanup.yml b/.github/workflows/snyk-pr-cleanup.yml deleted file mode 100644 index 27208c8c0a8..00000000000 --- a/.github/workflows/snyk-pr-cleanup.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: 🗑️ Snyk PR cleanup - merged/closed - -on: - workflow_dispatch: - -jobs: - snyk_project_cleanup_when_pr_closed: - uses: datastax/shared-github-actions/.github/workflows/snyk-pr-cleanup.yml@main - secrets: - snyk_token: ${{ secrets.SNYK_TOKEN }} - snyk_org_id: ${{ secrets.SNYK_ORG_ID }} From d94a8f06252d100ed1a405ca3809e059fbf8a4e0 Mon Sep 17 00:00:00 2001 From: hhughes Date: Mon, 21 Aug 2023 13:40:55 -0700 Subject: [PATCH 275/395] JAVA-3111: upgrade jackson-databind to 2.13.4.2 to address gradle dependency issue (#1708) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8fa1bc52a34..b74cfeee652 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 1.0.3 20230227 2.13.4 - 2.13.4.1 + 2.13.4.2 1.1.10.1 1.7.1 From fd446ce2870dafa3fe2654deb6e95506f62d2851 Mon Sep 17 00:00:00 2001 From: hhughes Date: Mon, 21 Aug 2023 13:47:23 -0700 Subject: [PATCH 276/395] JAVA-3069: Refactor duplicated tests with different requirements to use @BackendRequirement (#1667) Refactor @BackendRequirement test skipping logic into new rule, BackendRequirementRule. --- .../DseGssApiAuthProviderAlternateIT.java | 8 +- .../core/auth/DseGssApiAuthProviderIT.java | 8 +- .../core/auth/DsePlainTextAuthProviderIT.java | 8 +- .../core/auth/DseProxyAuthenticationIT.java | 8 +- .../driver/api/core/auth/EmbeddedAdsRule.java | 15 +- .../cql/continuous/ContinuousPagingIT.java | 8 +- .../reactive/ContinuousPagingReactiveIT.java | 8 +- .../api/core/data/geometry/LineStringIT.java | 5 +- .../api/core/data/geometry/PointIT.java | 5 +- .../api/core/data/geometry/PolygonIT.java | 5 +- .../api/core/data/time/DateRangeIT.java | 5 +- .../graph/ClassicGraphGeoSearchIndexIT.java | 8 +- .../graph/ClassicGraphTextSearchIndexIT.java | 8 +- .../core/graph/CoreGraphGeoSearchIndexIT.java | 8 +- .../graph/CoreGraphTextSearchIndexIT.java | 8 +- .../api/core/graph/CqlCollectionIT.java | 8 +- .../api/core/graph/GraphAuthenticationIT.java | 8 +- .../driver/api/core/graph/GraphPagingIT.java | 8 +- .../graph/GraphSpeculativeExecutionIT.java | 8 +- .../graph/GraphTextSearchIndexITBase.java | 9 +- .../api/core/graph/GraphTimeoutsIT.java | 8 +- .../DefaultReactiveGraphResultSetIT.java | 8 +- .../remote/ClassicGraphDataTypeRemoteIT.java | 8 +- .../remote/ClassicGraphTraversalRemoteIT.java | 8 +- .../remote/CoreGraphDataTypeRemoteIT.java | 8 +- .../remote/CoreGraphTraversalRemoteIT.java | 8 +- .../GraphTraversalMetaPropertiesRemoteIT.java | 8 +- ...GraphTraversalMultiPropertiesRemoteIT.java | 8 +- .../remote/GraphTraversalRemoteITBase.java | 5 +- .../ClassicGraphDataTypeFluentIT.java | 8 +- .../ClassicGraphDataTypeScriptIT.java | 8 +- .../ClassicGraphTraversalBatchIT.java | 8 +- .../statement/ClassicGraphTraversalIT.java | 8 +- .../statement/CoreGraphDataTypeFluentIT.java | 8 +- .../statement/CoreGraphDataTypeScriptIT.java | 8 +- .../statement/CoreGraphTraversalBatchIT.java | 8 +- .../graph/statement/CoreGraphTraversalIT.java | 8 +- .../GraphTraversalMetaPropertiesIT.java | 8 +- .../GraphTraversalMultiPropertiesIT.java | 8 +- .../api/core/insights/InsightsClientIT.java | 8 +- .../schema/DseAggregateMetadataIT.java | 8 +- .../schema/DseFunctionMetadataIT.java | 8 +- .../schema/KeyspaceGraphMetadataIT.java | 5 +- .../TableGraphMetadataCaseSensitiveIT.java | 5 +- .../metadata/schema/TableGraphMetadataIT.java | 5 +- .../ProtocolVersionInitialNegotiationIT.java | 240 +++++++----------- .../NettyResourceLeakDetectionIT.java | 21 +- .../oss/driver/core/cql/BatchStatementIT.java | 5 +- .../driver/core/cql/BoundStatementCcmIT.java | 5 +- .../core/cql/ExecutionInfoWarningsIT.java | 9 +- .../oss/driver/core/cql/NowInSecondsIT.java | 13 +- .../driver/core/cql/PerRequestKeyspaceIT.java | 19 +- .../driver/core/cql/PreparedStatementIT.java | 13 +- .../core/metadata/ByteOrderedTokenIT.java | 8 +- .../metadata/ByteOrderedTokenVnodesIT.java | 8 +- .../core/metadata/Murmur3TokenVnodesIT.java | 8 +- .../driver/core/metadata/NodeMetadataIT.java | 5 +- .../core/metadata/RandomTokenVnodesIT.java | 8 +- .../oss/driver/core/metadata/SchemaIT.java | 13 +- .../DriverBlockHoundIntegrationCcmIT.java | 8 +- .../mapper/DefaultNullSavingStrategyIT.java | 8 +- .../datastax/oss/driver/mapper/DeleteIT.java | 8 +- .../driver/mapper/IncrementWithNullsIT.java | 5 +- .../oss/driver/mapper/NestedUdtIT.java | 8 +- .../oss/driver/mapper/PrimitivesIT.java | 8 +- .../oss/driver/mapper/SchemaValidationIT.java | 8 +- .../mapper/SelectCustomWhereClauseIT.java | 8 +- .../driver/mapper/SelectOtherClausesIT.java | 8 +- .../driver/mapper/UpdateCustomIfClauseIT.java | 8 +- .../oss/driver/mapper/UpdateReactiveIT.java | 8 +- .../oss/driver/querybuilder/JsonInsertIT.java | 8 +- .../driver/internal/osgi/OsgiGeoTypesIT.java | 8 +- .../oss/driver/internal/osgi/OsgiGraphIT.java | 8 +- .../driver/internal/osgi/OsgiSnappyIT.java | 5 +- .../internal/osgi/support/CcmPaxExam.java | 18 +- .../api/testinfra/CassandraRequirement.java | 4 + .../driver/api/testinfra/DseRequirement.java | 4 + .../driver/api/testinfra/ccm/BaseCcmRule.java | 14 +- .../requirement/BackendRequirementRule.java | 59 +++++ .../requirement/VersionRequirement.java | 6 + 80 files changed, 577 insertions(+), 361 deletions(-) create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderAlternateIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderAlternateIT.java index 3b56e3edf65..44ba5b08eed 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderAlternateIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderAlternateIT.java @@ -22,7 +22,8 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.tngtech.java.junit.dataprovider.DataProvider; @@ -32,7 +33,10 @@ import org.junit.Test; import org.junit.runner.RunWith; -@DseRequirement(min = "5.0", description = "Required for DseAuthenticator") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "Required for DseAuthenticator") @RunWith(DataProviderRunner.class) public class DseGssApiAuthProviderAlternateIT { @ClassRule public static EmbeddedAdsRule ads = new EmbeddedAdsRule(true); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderIT.java index b8884e68b27..d357c2c678d 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseGssApiAuthProviderIT.java @@ -24,7 +24,8 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.auth.AuthenticationException; import com.datastax.oss.driver.api.core.cql.ResultSet; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.util.List; import java.util.Map; @@ -32,7 +33,10 @@ import org.junit.ClassRule; import org.junit.Test; -@DseRequirement(min = "5.0", description = "Required for DseAuthenticator") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "Required for DseAuthenticator") public class DseGssApiAuthProviderIT { @ClassRule public static EmbeddedAdsRule ads = new EmbeddedAdsRule(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DsePlainTextAuthProviderIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DsePlainTextAuthProviderIT.java index 08629a1f17e..c3c98c51d00 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DsePlainTextAuthProviderIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DsePlainTextAuthProviderIT.java @@ -24,8 +24,9 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.auth.AuthenticationException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.auth.PlainTextAuthProvider; import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; @@ -35,7 +36,10 @@ import org.junit.ClassRule; import org.junit.Test; -@DseRequirement(min = "5.0", description = "Required for DseAuthenticator") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "Required for DseAuthenticator") public class DsePlainTextAuthProviderIT { @ClassRule diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java index 7b4bf6be433..385b9206311 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java @@ -27,7 +27,8 @@ import com.datastax.oss.driver.api.core.cql.ResultSet; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.servererrors.UnauthorizedException; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.auth.PlainTextAuthProvider; import java.util.List; @@ -36,7 +37,10 @@ import org.junit.ClassRule; import org.junit.Test; -@DseRequirement(min = "5.1", description = "Required for DseAuthenticator with proxy") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1", + description = "Required for DseAuthenticator with proxy") public class DseProxyAuthenticationIT { private static String bobPrincipal; private static String charliePrincipal; diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java index 0903eb9b298..6590c056198 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java @@ -18,16 +18,12 @@ import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.dse.driver.internal.core.auth.DseGssApiAuthProvider; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; -import com.datastax.oss.driver.api.testinfra.requirement.BackendType; -import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirementRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.io.File; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.junit.AssumptionViolatedException; @@ -155,12 +151,7 @@ protected void before() { @Override public Statement apply(Statement base, Description description) { - BackendType backend = CcmBridge.DSE_ENABLEMENT ? BackendType.DSE : BackendType.CASSANDRA; - Version version = CcmBridge.VERSION; - - Collection requirements = VersionRequirement.fromAnnotations(description); - - if (VersionRequirement.meetsAny(requirements, backend, version)) { + if (BackendRequirementRule.meetsDescriptionRequirements(description)) { return super.apply(base, description); } else { // requirements not met, throw reasoning assumption to skip test @@ -168,7 +159,7 @@ public Statement apply(Statement base, Description description) { @Override public void evaluate() { throw new AssumptionViolatedException( - VersionRequirement.buildReasonString(requirements, backend, version)); + BackendRequirementRule.buildReasonString(description)); } }; } diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java index a0a3aaf3cf5..42600609d50 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java @@ -30,8 +30,9 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -58,8 +59,9 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement( - min = "5.1.0", +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1.0", description = "Continuous paging is only available from 5.1.0 onwards") @Category(ParallelizableTests.class) @RunWith(DataProviderRunner.class) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousPagingReactiveIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousPagingReactiveIT.java index 927a3dfc286..658dfeba2da 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousPagingReactiveIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/reactive/ContinuousPagingReactiveIT.java @@ -27,8 +27,9 @@ import com.datastax.oss.driver.api.core.cql.ExecutionInfo; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.metrics.DefaultNodeMetric; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -47,8 +48,9 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement( - min = "5.1.0", +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1.0", description = "Continuous paging is only available from 5.1.0 onwards") @Category(ParallelizableTests.class) @RunWith(DataProviderRunner.class) diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/LineStringIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/LineStringIT.java index 2261c3fae2d..6012ae4ba89 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/LineStringIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/LineStringIT.java @@ -22,8 +22,9 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.util.List; import java.util.UUID; @@ -34,7 +35,7 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0") +@BackendRequirement(type = BackendType.DSE, minInclusive = "5.0") public class LineStringIT extends GeometryIT { private static CcmRule ccm = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PointIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PointIT.java index fcb3a3b5ae4..b6bbe1e9492 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PointIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PointIT.java @@ -16,8 +16,9 @@ package com.datastax.dse.driver.api.core.data.geometry; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.assertj.core.util.Lists; import org.junit.BeforeClass; @@ -25,7 +26,7 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0") +@BackendRequirement(type = BackendType.DSE, minInclusive = "5.0") public class PointIT extends GeometryIT { private static CcmRule ccm = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PolygonIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PolygonIT.java index 9d7bfc3292f..2d5dccf8759 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PolygonIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/geometry/PolygonIT.java @@ -22,8 +22,9 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.util.UUID; import org.assertj.core.util.Lists; @@ -33,7 +34,7 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0") +@BackendRequirement(type = BackendType.DSE, minInclusive = "5.0") public class PolygonIT extends GeometryIT { private static CcmRule ccm = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/time/DateRangeIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/time/DateRangeIT.java index 958fac68ab9..5b2976c89d7 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/time/DateRangeIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/data/time/DateRangeIT.java @@ -25,8 +25,9 @@ import com.datastax.oss.driver.api.core.data.TupleValue; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -44,7 +45,7 @@ import org.junit.rules.TestRule; @Category({ParallelizableTests.class}) -@DseRequirement(min = "5.1") +@BackendRequirement(type = BackendType.DSE, minInclusive = "5.1") public class DateRangeIT { private static CcmRule ccmRule = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphGeoSearchIndexIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphGeoSearchIndexIT.java index df4c3385a79..eaf18f1a9ae 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphGeoSearchIndexIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphGeoSearchIndexIT.java @@ -16,8 +16,9 @@ package com.datastax.dse.driver.api.core.graph; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.shaded.guava.common.base.Joiner; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; @@ -30,7 +31,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.1", description = "DSE 5.1 required for graph geo indexing") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1", + description = "DSE 5.1 required for graph geo indexing") public class ClassicGraphGeoSearchIndexIT extends GraphGeoSearchIndexITBase { private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().withDseWorkloads("graph", "solr").build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphTextSearchIndexIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphTextSearchIndexIT.java index 315c092f682..bb85c1e1223 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphTextSearchIndexIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/ClassicGraphTextSearchIndexIT.java @@ -16,8 +16,9 @@ package com.datastax.dse.driver.api.core.graph; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.shaded.guava.common.base.Joiner; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; @@ -30,7 +31,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.1", description = "DSE 5.1 required for graph geo indexing") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1", + description = "DSE 5.1 required for graph geo indexing") public class ClassicGraphTextSearchIndexIT extends GraphTextSearchIndexITBase { private static final CustomCcmRule CCM_RULE = CustomCcmRule.builder().withDseWorkloads("graph", "solr").build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphGeoSearchIndexIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphGeoSearchIndexIT.java index 42b0e3378a5..279222c5bb1 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphGeoSearchIndexIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphGeoSearchIndexIT.java @@ -16,8 +16,9 @@ package com.datastax.dse.driver.api.core.graph; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; import java.util.Collection; @@ -28,7 +29,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") public class CoreGraphGeoSearchIndexIT extends GraphGeoSearchIndexITBase { private static final CustomCcmRule CCM_RULE = diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphTextSearchIndexIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphTextSearchIndexIT.java index 9617746e026..e1b784574e1 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphTextSearchIndexIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CoreGraphTextSearchIndexIT.java @@ -16,8 +16,9 @@ package com.datastax.dse.driver.api.core.graph; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; import java.util.Collection; @@ -28,7 +29,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") public class CoreGraphTextSearchIndexIT extends GraphTextSearchIndexITBase { private static final CustomCcmRule CCM_RULE = diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CqlCollectionIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CqlCollectionIT.java index ee8d4ac943d..74f441504f8 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CqlCollectionIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/CqlCollectionIT.java @@ -22,8 +22,9 @@ import com.datastax.dse.driver.api.core.graph.predicates.CqlCollection; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.CqlSessionRuleBuilder; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -41,7 +42,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.8", description = "DSE 6.8.0 required for collection predicates support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8", + description = "DSE 6.8.0 required for collection predicates support") public class CqlCollectionIT { private static final CustomCcmRule CCM_RULE = diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphAuthenticationIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphAuthenticationIT.java index aaaafc26248..6d70e994666 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphAuthenticationIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphAuthenticationIT.java @@ -22,8 +22,9 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.auth.PlainTextAuthProvider; import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; @@ -32,7 +33,10 @@ import org.junit.ClassRule; import org.junit.Test; -@DseRequirement(min = "5.0.0", description = "DSE 5 required for Graph") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.0", + description = "DSE 5 required for Graph") public class GraphAuthenticationIT { @ClassRule diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphPagingIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphPagingIT.java index 335aceb9b84..b2cefb1b4a3 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphPagingIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphPagingIT.java @@ -32,8 +32,9 @@ import com.datastax.oss.driver.api.core.cql.ExecutionInfo; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metrics.Metrics; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.util.CountingIterator; @@ -53,7 +54,10 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement(min = "6.8.0", description = "Graph paging requires DSE 6.8+") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "Graph paging requires DSE 6.8+") @RunWith(DataProviderRunner.class) public class GraphPagingIT { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphSpeculativeExecutionIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphSpeculativeExecutionIT.java index fcacddb787f..4d8aec69264 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphSpeculativeExecutionIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphSpeculativeExecutionIT.java @@ -20,8 +20,9 @@ import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.specex.ConstantSpeculativeExecutionPolicy; import com.datastax.oss.driver.internal.core.specex.NoSpeculativeExecutionPolicy; @@ -33,7 +34,10 @@ import org.junit.Test; import org.junit.runner.RunWith; -@DseRequirement(min = "6.8.0", description = "DSE 6.8 required for graph paging") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8 required for graph paging") @RunWith(DataProviderRunner.class) public class GraphSpeculativeExecutionIT { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTextSearchIndexITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTextSearchIndexITBase.java index 9a8b3d2eedc..1330a433ff8 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTextSearchIndexITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTextSearchIndexITBase.java @@ -18,7 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat; import com.datastax.dse.driver.api.core.graph.predicates.Search; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; @@ -102,7 +103,7 @@ public void search_by_regex(String indexType) { */ @UseDataProvider("indexTypes") @Test - @DseRequirement(min = "5.1.0") + @BackendRequirement(type = BackendType.DSE, minInclusive = "5.1.0") public void search_by_fuzzy(String indexType) { // Alias matches 'awrio' fuzzy GraphTraversal traversal = @@ -185,7 +186,7 @@ public void search_by_token_regex(String indexType) { */ @UseDataProvider("indexTypes") @Test - @DseRequirement(min = "5.1.0") + @BackendRequirement(type = BackendType.DSE, minInclusive = "5.1.0") public void search_by_token_fuzzy(String indexType) { // Description containing 'lives' fuzzy GraphTraversal traversal = @@ -210,7 +211,7 @@ public void search_by_token_fuzzy(String indexType) { */ @UseDataProvider("indexTypes") @Test - @DseRequirement(min = "5.1.0") + @BackendRequirement(type = BackendType.DSE, minInclusive = "5.1.0") public void search_by_phrase(String indexType) { // Full name contains phrase "Paul Joe" GraphTraversal traversal = diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTimeoutsIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTimeoutsIT.java index 4b8ec8d2d19..bc3fa00be9d 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTimeoutsIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/GraphTimeoutsIT.java @@ -24,8 +24,9 @@ import com.datastax.oss.driver.api.core.DriverTimeoutException; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.time.Duration; import org.junit.ClassRule; @@ -33,7 +34,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0.0", description = "DSE 5 required for Graph") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.0", + description = "DSE 5 required for Graph") public class GraphTimeoutsIT { public static CustomCcmRule ccmRule = CustomCcmRule.builder().withDseWorkloads("graph").build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/reactive/DefaultReactiveGraphResultSetIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/reactive/DefaultReactiveGraphResultSetIT.java index 9c46891b4ab..0e183efd4ea 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/reactive/DefaultReactiveGraphResultSetIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/reactive/DefaultReactiveGraphResultSetIT.java @@ -23,8 +23,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.ExecutionInfo; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; @@ -39,7 +40,10 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement(min = "6.8.0", description = "Graph paging requires DSE 6.8+") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "Graph paging requires DSE 6.8+") @RunWith(DataProviderRunner.class) public class DefaultReactiveGraphResultSetIT { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphDataTypeRemoteIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphDataTypeRemoteIT.java index 5eb70d01604..6d5c8187718 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphDataTypeRemoteIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphDataTypeRemoteIT.java @@ -21,8 +21,9 @@ import com.datastax.dse.driver.api.core.graph.SampleGraphScripts; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -32,7 +33,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0.3", description = "DSE 5.0.3 required for remote TinkerPop support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.3", + description = "DSE 5.0.3 required for remote TinkerPop support") public class ClassicGraphDataTypeRemoteIT extends ClassicGraphDataTypeITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphTraversalRemoteIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphTraversalRemoteIT.java index a855d38333a..c2c56468c5c 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphTraversalRemoteIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/ClassicGraphTraversalRemoteIT.java @@ -23,8 +23,9 @@ import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.dse.driver.api.core.graph.SocialTraversalSource; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.junit.BeforeClass; @@ -32,8 +33,9 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement( - min = "5.0.9", +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.9", description = "DSE 5.0.9 required for inserting edges and vertices script.") public class ClassicGraphTraversalRemoteIT extends GraphTraversalRemoteITBase { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphDataTypeRemoteIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphDataTypeRemoteIT.java index 40deb724757..21c8a48758f 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphDataTypeRemoteIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphDataTypeRemoteIT.java @@ -21,8 +21,9 @@ import com.datastax.dse.driver.api.core.graph.DseGraph; import com.datastax.dse.driver.api.core.graph.GraphTestSupport; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import java.util.Map; @@ -35,7 +36,10 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") @RunWith(DataProviderRunner.class) public class CoreGraphDataTypeRemoteIT extends CoreGraphDataTypeITBase { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphTraversalRemoteIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphTraversalRemoteIT.java index dfd45cdfb8e..e4afc6939eb 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphTraversalRemoteIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/CoreGraphTraversalRemoteIT.java @@ -23,8 +23,9 @@ import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.dse.driver.api.core.graph.SocialTraversalSource; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.junit.BeforeClass; @@ -32,7 +33,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.8", description = "DSE 6.8 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8", + description = "DSE 6.8 required for Core graph support") public class CoreGraphTraversalRemoteIT extends GraphTraversalRemoteITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMetaPropertiesRemoteIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMetaPropertiesRemoteIT.java index a40b7c6d397..b95d1c596e2 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMetaPropertiesRemoteIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMetaPropertiesRemoteIT.java @@ -23,8 +23,9 @@ import com.datastax.dse.driver.api.core.graph.GraphTestSupport; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -37,7 +38,10 @@ // INFO: meta props are going away in NGDG -@DseRequirement(min = "5.0.3", description = "DSE 5.0.3 required for remote TinkerPop support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.3", + description = "DSE 5.0.3 required for remote TinkerPop support") public class GraphTraversalMetaPropertiesRemoteIT { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMultiPropertiesRemoteIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMultiPropertiesRemoteIT.java index 6dcd6bda336..6267fc6719e 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMultiPropertiesRemoteIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalMultiPropertiesRemoteIT.java @@ -23,8 +23,9 @@ import com.datastax.dse.driver.api.core.graph.GraphTestSupport; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.util.Iterator; import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource; @@ -37,7 +38,10 @@ import org.junit.rules.TestRule; // INFO: multi props are not supported in Core -@DseRequirement(min = "5.0.3", description = "DSE 5.0.3 required for remote TinkerPop support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.3", + description = "DSE 5.0.3 required for remote TinkerPop support") public class GraphTraversalMultiPropertiesRemoteIT { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java index 4177f5a1477..9d8ecdf7382 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java @@ -28,8 +28,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -583,7 +584,7 @@ public void should_handle_asynchronous_execution_graph_binary() { * @test_category dse:graph */ @Test - @DseRequirement(min = "5.1.0") + @BackendRequirement(type = BackendType.DSE, minInclusive = "5.1.0") public void should_fail_future_returned_from_promise_on_query_error() throws Exception { CompletableFuture future = graphTraversalSource().V("invalidid").peerPressure().promise(Traversal::next); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeFluentIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeFluentIT.java index 35c05deb01f..5696d1e2e0c 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeFluentIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeFluentIT.java @@ -22,8 +22,9 @@ import com.datastax.dse.driver.api.core.graph.SampleGraphScripts; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.junit.BeforeClass; @@ -31,7 +32,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0.3", description = "DSE 5.0.3 required for fluent API support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.3", + description = "DSE 5.0.3 required for fluent API support") public class ClassicGraphDataTypeFluentIT extends ClassicGraphDataTypeITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.CCM_BUILDER_WITH_GRAPH.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeScriptIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeScriptIT.java index 9a12e5ca54a..b462ab4ecde 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeScriptIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphDataTypeScriptIT.java @@ -20,8 +20,9 @@ import com.datastax.dse.driver.api.core.graph.SampleGraphScripts; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.junit.BeforeClass; @@ -29,7 +30,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0.4", description = "DSE 5.0.4 required for script API with GraphSON 2") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.4", + description = "DSE 5.0.4 required for script API with GraphSON 2") public class ClassicGraphDataTypeScriptIT extends ClassicGraphDataTypeITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.CCM_BUILDER_WITH_GRAPH.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalBatchIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalBatchIT.java index 780d8af6ed4..8f6a92e27ba 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalBatchIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalBatchIT.java @@ -19,8 +19,9 @@ import com.datastax.dse.driver.api.core.graph.SampleGraphScripts; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; @@ -29,7 +30,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.0", description = "DSE 6.0 required for BatchGraphStatement.") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.0", + description = "DSE 6.0 required for BatchGraphStatement.") public class ClassicGraphTraversalBatchIT extends GraphTraversalBatchITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalIT.java index f1dd053692b..c1da29e3519 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/ClassicGraphTraversalIT.java @@ -20,8 +20,9 @@ import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.dse.driver.api.core.graph.SocialTraversalSource; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; @@ -30,8 +31,9 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement( - min = "5.0.9", +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.9", description = "DSE 5.0.9 required for inserting edges and vertices script.") public class ClassicGraphTraversalIT extends GraphTraversalITBase { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeFluentIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeFluentIT.java index 613aa006005..7b40239ada0 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeFluentIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeFluentIT.java @@ -22,8 +22,9 @@ import com.datastax.dse.driver.api.core.graph.FluentGraphStatement; import com.datastax.dse.driver.api.core.graph.GraphTestSupport; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import java.util.Map; @@ -34,7 +35,10 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") @RunWith(DataProviderRunner.class) public class CoreGraphDataTypeFluentIT extends CoreGraphDataTypeITBase { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeScriptIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeScriptIT.java index 3bb73739f3e..e53f28937b1 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeScriptIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphDataTypeScriptIT.java @@ -20,8 +20,9 @@ import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatementBuilder; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import java.util.Map; @@ -30,7 +31,10 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") @RunWith(DataProviderRunner.class) public class CoreGraphDataTypeScriptIT extends CoreGraphDataTypeITBase { diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalBatchIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalBatchIT.java index 51f50fb25a6..9ec2b892a50 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalBatchIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalBatchIT.java @@ -19,8 +19,9 @@ import com.datastax.dse.driver.api.core.graph.SampleGraphScripts; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; @@ -29,7 +30,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") public class CoreGraphTraversalBatchIT extends GraphTraversalBatchITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalIT.java index 8bafe312916..a8ff90dc0ed 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/CoreGraphTraversalIT.java @@ -20,8 +20,9 @@ import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.dse.driver.api.core.graph.SocialTraversalSource; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; @@ -30,7 +31,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.8.0", description = "DSE 6.8.0 required for Core graph support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8.0", + description = "DSE 6.8.0 required for Core graph support") public class CoreGraphTraversalIT extends GraphTraversalITBase { private static final CustomCcmRule CCM_RULE = GraphTestSupport.CCM_BUILDER_WITH_GRAPH.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMetaPropertiesIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMetaPropertiesIT.java index ea3ee972c24..0c406c4534f 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMetaPropertiesIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMetaPropertiesIT.java @@ -27,8 +27,9 @@ import com.datastax.dse.driver.api.core.graph.GraphTestSupport; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -39,7 +40,10 @@ // INFO: meta props are going away in NGDG -@DseRequirement(min = "5.0.3", description = "DSE 5.0.3 required for remote TinkerPop support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.3", + description = "DSE 5.0.3 required for remote TinkerPop support") public class GraphTraversalMetaPropertiesIT { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMultiPropertiesIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMultiPropertiesIT.java index 78bd336dc0a..8dc6532766c 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMultiPropertiesIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalMultiPropertiesIT.java @@ -25,8 +25,9 @@ import com.datastax.dse.driver.api.core.graph.GraphTestSupport; import com.datastax.dse.driver.api.core.graph.ScriptGraphStatement; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.util.Iterator; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -37,7 +38,10 @@ import org.junit.rules.TestRule; // INFO: multi props are not supported in Core -@DseRequirement(min = "5.0.3", description = "DSE 5.0.3 required for remote TinkerPop support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0.3", + description = "DSE 5.0.3 required for remote TinkerPop support") public class GraphTraversalMultiPropertiesIT { private static final CustomCcmRule CCM_RULE = GraphTestSupport.GRAPH_CCM_RULE_BUILDER.build(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/insights/InsightsClientIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/insights/InsightsClientIT.java index 00389706fcb..c8da3dcd2ca 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/insights/InsightsClientIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/insights/InsightsClientIT.java @@ -18,8 +18,9 @@ import com.datastax.dse.driver.internal.core.insights.InsightsClient; import com.datastax.dse.driver.internal.core.insights.configuration.InsightsConfiguration; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import io.netty.util.concurrent.DefaultEventExecutor; @@ -31,7 +32,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "6.7.0", description = "DSE 6.7.0 required for Insights support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.7.0", + description = "DSE 6.7.0 required for Insights support") public class InsightsClientIT { private static final StackTraceElement[] EMPTY_STACK_TRACE = {}; diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java index a7f1a4fd25a..ed96c74eac2 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java @@ -22,8 +22,9 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.metadata.schema.AggregateMetadata; import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.util.Objects; import java.util.Optional; @@ -32,7 +33,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0", description = "DSE 5.0+ required function/aggregate support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "DSE 5.0+ required function/aggregate support") public class DseAggregateMetadataIT extends AbstractMetadataIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java index 66ed45ce9e0..ecfadcfacfb 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java @@ -24,8 +24,9 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.metadata.schema.FunctionMetadata; import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import java.util.Objects; import java.util.Optional; @@ -34,7 +35,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@DseRequirement(min = "5.0", description = "DSE 5.0+ required function/aggregate support") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "DSE 5.0+ required function/aggregate support") public class DseFunctionMetadataIT extends AbstractMetadataIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/KeyspaceGraphMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/KeyspaceGraphMetadataIT.java index 6feae130b8c..9abb7918183 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/KeyspaceGraphMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/KeyspaceGraphMetadataIT.java @@ -20,8 +20,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.CqlSessionRuleBuilder; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -32,7 +33,7 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@DseRequirement(min = "6.8") +@BackendRequirement(type = BackendType.DSE, minInclusive = "6.8") public class KeyspaceGraphMetadataIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java index 77bfeb13896..442f33a216f 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataCaseSensitiveIT.java @@ -20,8 +20,9 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.CqlSessionRuleBuilder; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -38,7 +39,7 @@ * case-sensitive column names in its tables. See JAVA-2492 for more information. */ @Category(ParallelizableTests.class) -@DseRequirement(min = "6.8") +@BackendRequirement(type = BackendType.DSE, minInclusive = "6.8") public class TableGraphMetadataCaseSensitiveIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java index 933951dd7f8..7992e6ff6ba 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/TableGraphMetadataIT.java @@ -20,8 +20,9 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.CqlSessionRuleBuilder; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -33,7 +34,7 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@DseRequirement(min = "6.8") +@BackendRequirement(type = BackendType.DSE, minInclusive = "6.8") public class TableGraphMetadataIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java index 8ba8986b35b..e640f25e50e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ProtocolVersionInitialNegotiationIT.java @@ -26,12 +26,11 @@ import com.datastax.oss.driver.api.core.UnsupportedProtocolVersionException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; -import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -42,68 +41,57 @@ public class ProtocolVersionInitialNegotiationIT { @Rule public CcmRule ccm = CcmRule.getInstance(); - @CassandraRequirement( - min = "2.1", - max = "2.2", + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.1", + maxExclusive = "2.2", description = "Only C* in [2.1,2.2[ has V3 as its highest version") + @BackendRequirement( + type = BackendType.DSE, + maxExclusive = "5.0", + description = "Only DSE in [*,5.0[ has V3 as its highest version") @Test - public void should_downgrade_to_v3_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + public void should_downgrade_to_v3() { try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); session.execute("select * from system.local"); } } - @DseRequirement(max = "5.0", description = "Only DSE in [*,5.0[ has V3 as its highest version") - @Test - public void should_downgrade_to_v3_dse() { - try (CqlSession session = SessionUtils.newSession(ccm)) { - assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); - session.execute("select * from system.local"); - } - } - - @CassandraRequirement( - min = "2.2", - max = "4.0-rc1", + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.2", + maxExclusive = "4.0-rc1", description = "Only C* in [2.2,4.0-rc1[ has V4 as its highest version") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + maxExclusive = "5.1", + description = "Only DSE in [5.0,5.1[ has V4 as its highest version") @Test - public void should_downgrade_to_v4_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + public void should_downgrade_to_v4() { try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); session.execute("select * from system.local"); } } - @CassandraRequirement( - min = "4.0-rc1", + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "4.0-rc1", description = "Only C* in [4.0-rc1,*[ has V5 as its highest version") @Test public void should_downgrade_to_v5_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(5); session.execute("select * from system.local"); } } - @DseRequirement( - min = "5.0", - max = "5.1", - description = "Only DSE in [5.0,5.1[ has V4 as its highest version") - @Test - public void should_downgrade_to_v4_dse() { - try (CqlSession session = SessionUtils.newSession(ccm)) { - assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); - session.execute("select * from system.local"); - } - } - - @DseRequirement( - min = "5.1", - max = "6.0", + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1", + maxExclusive = "6.0", description = "Only DSE in [5.1,6.0[ has DSE_V1 as its highest version") @Test public void should_downgrade_to_dse_v1() { @@ -113,29 +101,16 @@ public void should_downgrade_to_dse_v1() { } } - @CassandraRequirement(max = "2.2", description = "Only C* in [*,2.2[ has V4 unsupported") - @Test - public void should_fail_if_provided_v4_is_not_supported_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") - .build(); - try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { - fail("Expected an AllNodesFailedException"); - } catch (AllNodesFailedException anfe) { - Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); - assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); - UnsupportedProtocolVersionException unsupportedException = - (UnsupportedProtocolVersionException) cause; - assertThat(unsupportedException.getAttemptedVersions()) - .containsOnly(DefaultProtocolVersion.V4); - } - } - - @DseRequirement(max = "5.0", description = "Only DSE in [*,5.0[ has V4 unsupported") + @BackendRequirement( + type = BackendType.CASSANDRA, + maxExclusive = "2.2", + description = "Only C* in [*,2.2[ has V4 unsupported") + @BackendRequirement( + type = BackendType.DSE, + maxExclusive = "5.0", + description = "Only DSE in [*,5.0[ has V4 unsupported") @Test - public void should_fail_if_provided_v4_is_not_supported_dse() { + public void should_fail_if_provided_v4_is_not_supported() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") @@ -152,34 +127,17 @@ public void should_fail_if_provided_v4_is_not_supported_dse() { } } - @CassandraRequirement( - min = "2.1", - max = "4.0-rc1", + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.1", + maxExclusive = "4.0-rc1", description = "Only C* in [2.1,4.0-rc1[ has V5 unsupported or supported as beta") - @Test - public void should_fail_if_provided_v5_is_not_supported_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") - .build(); - try (CqlSession ignored = SessionUtils.newSession(ccm, loader)) { - fail("Expected an AllNodesFailedException"); - } catch (AllNodesFailedException anfe) { - Throwable cause = anfe.getAllErrors().values().iterator().next().get(0); - assertThat(cause).isInstanceOf(UnsupportedProtocolVersionException.class); - UnsupportedProtocolVersionException unsupportedException = - (UnsupportedProtocolVersionException) cause; - assertThat(unsupportedException.getAttemptedVersions()) - .containsOnly(DefaultProtocolVersion.V5); - } - } - - @DseRequirement( - max = "7.0", + @BackendRequirement( + type = BackendType.DSE, + maxExclusive = "7.0", description = "Only DSE in [*,7.0[ has V5 unsupported or supported as beta") @Test - public void should_fail_if_provided_v5_is_not_supported_dse() { + public void should_fail_if_provided_v5_is_not_supported() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") @@ -196,7 +154,10 @@ public void should_fail_if_provided_v5_is_not_supported_dse() { } } - @DseRequirement(max = "5.1", description = "Only DSE in [*,5.1[ has DSE_V1 unsupported") + @BackendRequirement( + type = BackendType.DSE, + maxExclusive = "5.1", + description = "Only DSE in [*,5.1[ has DSE_V1 unsupported") @Test public void should_fail_if_provided_dse_v1_is_not_supported() { DriverConfigLoader loader = @@ -215,7 +176,10 @@ public void should_fail_if_provided_dse_v1_is_not_supported() { } } - @DseRequirement(max = "6.0", description = "Only DSE in [*,6.0[ has DSE_V2 unsupported") + @BackendRequirement( + type = BackendType.DSE, + maxExclusive = "6.0", + description = "Only DSE in [*,6.0[ has DSE_V2 unsupported") @Test public void should_fail_if_provided_dse_v2_is_not_supported() { DriverConfigLoader loader = @@ -235,10 +199,12 @@ public void should_fail_if_provided_dse_v2_is_not_supported() { } /** Note that this test will need to be updated as new protocol versions are introduced. */ - @CassandraRequirement(min = "4.0", description = "Only C* in [4.0,*[ has V5 supported") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "4.0", + description = "Only C* in [4.0,*[ has V5 supported") @Test - public void should_not_downgrade_if_server_supports_latest_version_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + public void should_not_downgrade_if_server_supports_latest_version() { try (CqlSession session = SessionUtils.newSession(ccm)) { assertThat(session.getContext().getProtocolVersion()).isEqualTo(ProtocolVersion.V5); session.execute("select * from system.local"); @@ -246,7 +212,10 @@ public void should_not_downgrade_if_server_supports_latest_version_oss() { } /** Note that this test will need to be updated as new protocol versions are introduced. */ - @DseRequirement(min = "6.0", description = "Only DSE in [6.0,*[ has DSE_V2 supported") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.0", + description = "Only DSE in [6.0,*[ has DSE_V2 supported") @Test public void should_not_downgrade_if_server_supports_latest_version_dse() { try (CqlSession session = SessionUtils.newSession(ccm)) { @@ -255,10 +224,16 @@ public void should_not_downgrade_if_server_supports_latest_version_dse() { } } - @CassandraRequirement(min = "2.1", description = "Only C* in [2.1,*[ has V3 supported") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.1", + description = "Only C* in [2.1,*[ has V3 supported") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "4.8", + description = "Only DSE in [4.8,*[ has V3 supported") @Test - public void should_use_explicitly_provided_v3_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + public void should_use_explicitly_provided_v3() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") @@ -269,23 +244,16 @@ public void should_use_explicitly_provided_v3_oss() { } } - @DseRequirement(min = "4.8", description = "Only DSE in [4.8,*[ has V3 supported") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.2", + description = "Only C* in [2.2,*[ has V4 supported") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "Only DSE in [5.0,*[ has V4 supported") @Test - public void should_use_explicitly_provided_v3_dse() { - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") - .build(); - try (CqlSession session = SessionUtils.newSession(ccm, loader)) { - assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(3); - session.execute("select * from system.local"); - } - } - - @CassandraRequirement(min = "2.2", description = "Only C* in [2.2,*[ has V4 supported") - @Test - public void should_use_explicitly_provided_v4_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); + public void should_use_explicitly_provided_v4() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") @@ -296,36 +264,16 @@ public void should_use_explicitly_provided_v4_oss() { } } - @DseRequirement(min = "5.0", description = "Only DSE in [5.0,*[ has V4 supported") - @Test - public void should_use_explicitly_provided_v4_dse() { - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4") - .build(); - try (CqlSession session = SessionUtils.newSession(ccm, loader)) { - assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(4); - session.execute("select * from system.local"); - } - } - - @CassandraRequirement(min = "4.0", description = "Only C* in [4.0,*[ has V5 supported") - @Test - public void should_use_explicitly_provided_v5_oss() { - Assume.assumeFalse("This test is only for OSS C*", ccm.getDseVersion().isPresent()); - DriverConfigLoader loader = - SessionUtils.configLoaderBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") - .build(); - try (CqlSession session = SessionUtils.newSession(ccm, loader)) { - assertThat(session.getContext().getProtocolVersion().getCode()).isEqualTo(5); - session.execute("select * from system.local"); - } - } - - @DseRequirement(min = "7.0", description = "Only DSE in [7.0,*[ has V5 supported") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "4.0", + description = "Only C* in [4.0,*[ has V5 supported") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "7.0", + description = "Only DSE in [7.0,*[ has V5 supported") @Test - public void should_use_explicitly_provided_v5_dse() { + public void should_use_explicitly_provided_v5() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_VERSION, "V5") @@ -336,7 +284,10 @@ public void should_use_explicitly_provided_v5_dse() { } } - @DseRequirement(min = "5.1", description = "Only DSE in [5.1,*[ has DSE_V1 supported") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1", + description = "Only DSE in [5.1,*[ has DSE_V1 supported") @Test public void should_use_explicitly_provided_dse_v1() { DriverConfigLoader loader = @@ -349,7 +300,10 @@ public void should_use_explicitly_provided_dse_v1() { } } - @DseRequirement(min = "6.0", description = "Only DSE in [6.0,*[ has DSE_V2 supported") + @BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.0", + description = "Only DSE in [6.0,*[ has DSE_V2 supported") @Test public void should_use_explicitly_provided_dse_v2() { DriverConfigLoader loader = diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java index ada5ae9a61b..c3334360a23 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/connection/NettyResourceLeakDetectionIT.java @@ -24,13 +24,15 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirementRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.IsolatedTests; @@ -42,10 +44,10 @@ import java.nio.ByteBuffer; import java.util.List; import org.junit.After; -import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; @@ -70,6 +72,10 @@ public class NettyResourceLeakDetectionIT { @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); + // Separately use BackendRequirementRule with @Rule so backend requirements are evaluated for each + // test method. + @Rule public final BackendRequirementRule backendRequirementRule = new BackendRequirementRule(); + private static final ByteBuffer LARGE_PAYLOAD = Bytes.fromHexString("0x" + Strings.repeat("ab", Segment.MAX_PAYLOAD_LENGTH + 100)); @@ -118,12 +124,15 @@ public void should_not_leak_compressed_lz4() { } } + @BackendRequirement( + type = BackendType.DSE, + description = "Snappy is not supported in OSS C* 4.0+ with protocol v5") + @BackendRequirement( + type = BackendType.CASSANDRA, + maxExclusive = "4.0.0", + description = "Snappy is not supported in OSS C* 4.0+ with protocol v5") @Test public void should_not_leak_compressed_snappy() { - Assume.assumeTrue( - "Snappy is not supported in OSS C* 4.0+ with protocol v5", - CCM_RULE.getDseVersion().isPresent() - || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0); DriverConfigLoader loader = SessionUtils.configLoaderBuilder() .withString(DefaultDriverOption.PROTOCOL_COMPRESSION, "snappy") diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java index cc960b6c27c..9a481aa1f85 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java @@ -31,8 +31,9 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -121,7 +122,7 @@ public void should_execute_batch_of_bound_statements_with_variables() { } @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_execute_batch_of_bound_statements_with_unset_values() { // Build a batch of batchCount statements with bound statements, each with their own positional // variables. diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java index 106b2823dc1..c8f3c2ea45e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java @@ -37,8 +37,9 @@ import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.metadata.token.Token; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -353,7 +354,7 @@ public void should_propagate_attributes_when_preparing_a_simple_statement() { // Test for JAVA-2066 @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_compute_routing_key_when_indices_randomly_distributed() { try (CqlSession session = SessionUtils.newSession(ccmRule, sessionRule.keyspace())) { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java index e3648c93424..702ff66db3e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java @@ -30,8 +30,9 @@ import com.datastax.oss.driver.api.core.cql.ResultSet; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.cql.CqlRequestHandler; @@ -116,7 +117,7 @@ public void cleanupLogger() { } @Test - @CassandraRequirement(min = "3.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "3.0") public void should_execute_query_and_log_server_side_warnings() { final String query = "SELECT count(*) FROM test;"; Statement st = SimpleStatement.builder(query).build(); @@ -140,7 +141,7 @@ public void should_execute_query_and_log_server_side_warnings() { } @Test - @CassandraRequirement(min = "3.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "3.0") public void should_execute_query_and_not_log_server_side_warnings() { final String query = "SELECT count(*) FROM test;"; Statement st = @@ -158,7 +159,7 @@ public void should_execute_query_and_not_log_server_side_warnings() { } @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_expose_warnings_on_execution_info() { // the default batch size warn threshold is 5 * 1024 bytes, but after CASSANDRA-10876 there must // be multiple mutations in a batch to trigger this warning so the batch includes 2 different diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java index 2b570329d51..16c3f43c990 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/NowInSecondsIT.java @@ -24,9 +24,9 @@ import com.datastax.oss.driver.api.core.cql.ResultSet; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -39,10 +39,11 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "4.0") -@DseRequirement( - // Use next version -- not sure if it will be in by then, but as a reminder to check - min = "7.0", +@BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") +// Use next version -- not sure if it will be in by then, but as a reminder to check +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "7.0", description = "Feature not available in DSE yet") public class NowInSecondsIT { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java index de6be0afe61..501ed5f5718 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java @@ -28,8 +28,9 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -74,14 +75,14 @@ public void setupSchema() { } @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_reject_simple_statement_with_keyspace_in_protocol_v4() { should_reject_statement_with_keyspace_in_protocol_v4( SimpleStatement.newInstance("SELECT * FROM foo").setKeyspace(sessionRule.keyspace())); } @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_reject_batch_statement_with_explicit_keyspace_in_protocol_v4() { SimpleStatement statementWithoutKeyspace = SimpleStatement.newInstance( @@ -94,7 +95,7 @@ public void should_reject_batch_statement_with_explicit_keyspace_in_protocol_v4( } @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_reject_batch_statement_with_inferred_keyspace_in_protocol_v4() { SimpleStatement statementWithKeyspace = SimpleStatement.newInstance( @@ -120,7 +121,7 @@ private void should_reject_statement_with_keyspace_in_protocol_v4(Statement stat } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_execute_simple_statement_with_keyspace() { CqlSession session = sessionRule.session(); session.execute( @@ -138,7 +139,7 @@ public void should_execute_simple_statement_with_keyspace() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_execute_batch_with_explicit_keyspace() { CqlSession session = sessionRule.session(); session.execute( @@ -162,7 +163,7 @@ public void should_execute_batch_with_explicit_keyspace() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_execute_batch_with_inferred_keyspace() { CqlSession session = sessionRule.session(); session.execute( @@ -194,7 +195,7 @@ public void should_execute_batch_with_inferred_keyspace() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_prepare_statement_with_keyspace() { CqlSession session = sessionRule.session(); PreparedStatement prepared = @@ -214,7 +215,7 @@ public void should_prepare_statement_with_keyspace() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_reprepare_statement_with_keyspace_on_the_fly() { // Create a separate session because we don't want it to have a default keyspace try (CqlSession session = SessionUtils.newSession(ccmRule)) { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index 490158980fb..964bc7fe34d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -34,7 +34,6 @@ import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; @@ -148,7 +147,7 @@ public void should_have_non_empty_variable_definitions_for_select_query_with_bou } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_update_metadata_when_schema_changed_across_executions() { // Given CqlSession session = sessionRule.session(); @@ -177,7 +176,7 @@ public void should_update_metadata_when_schema_changed_across_executions() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_update_metadata_when_schema_changed_across_pages() { // Given CqlSession session = sessionRule.session(); @@ -222,7 +221,7 @@ public void should_update_metadata_when_schema_changed_across_pages() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_update_metadata_when_schema_changed_across_sessions() { // Given CqlSession session1 = sessionRule.session(); @@ -269,7 +268,7 @@ public void should_update_metadata_when_schema_changed_across_sessions() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_fail_to_reprepare_if_query_becomes_invalid() { // Given CqlSession session = sessionRule.session(); @@ -288,13 +287,13 @@ public void should_fail_to_reprepare_if_query_becomes_invalid() { } @Test - @CassandraRequirement(min = "4.0") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_not_store_metadata_for_conditional_updates() { should_not_store_metadata_for_conditional_updates(sessionRule.session()); } @Test - @CassandraRequirement(min = "2.2") + @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public void should_not_store_metadata_for_conditional_updates_in_legacy_protocol() { DriverConfigLoader loader = SessionUtils.configLoaderBuilder() diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java index 28795b6c4c4..c3eeae19a35 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenIT.java @@ -17,8 +17,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.metadata.token.ByteOrderedToken; @@ -28,8 +29,9 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@CassandraRequirement( - max = "4.0-beta4", +@BackendRequirement( + type = BackendType.CASSANDRA, + maxExclusive = "4.0-beta4", description = "Token allocation is not compatible with this partitioner, " + "but is enabled by default in C* 4.0 (see CASSANDRA-7032 and CASSANDRA-13701)") diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java index 1009013c734..561a59a0847 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/ByteOrderedTokenVnodesIT.java @@ -17,8 +17,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.metadata.token.ByteOrderedToken; @@ -28,8 +29,9 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@CassandraRequirement( - max = "4.0-beta4", +@BackendRequirement( + type = BackendType.CASSANDRA, + maxExclusive = "4.0-beta4", description = "Token allocation is not compatible with this partitioner, " + "but is enabled by default in C* 4.0 (see CASSANDRA-7032 and CASSANDRA-13701)") diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java index 3dcf8f88b17..6f15a668e9e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/Murmur3TokenVnodesIT.java @@ -17,8 +17,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; @@ -28,8 +29,9 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@CassandraRequirement( - max = "4.0-beta4", +@BackendRequirement( + type = BackendType.CASSANDRA, + maxExclusive = "4.0-beta4", // TODO Re-enable when CASSANDRA-16364 is fixed description = "TODO Re-enable when CASSANDRA-16364 is fixed") public class Murmur3TokenVnodesIT extends TokenITBase { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java index 32e8c3929a5..ba35cf824b3 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java @@ -23,9 +23,10 @@ import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance; import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeState; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.context.EventBus; @@ -90,7 +91,7 @@ public void should_expose_node_metadata() { } @Test - @DseRequirement(min = "5.1") + @BackendRequirement(type = BackendType.DSE, minInclusive = "5.1") public void should_expose_dse_node_properties() { try (CqlSession session = SessionUtils.newSession(ccmRule)) { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java index 1545bd46104..2f56e118b73 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/RandomTokenVnodesIT.java @@ -17,8 +17,9 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; @@ -28,8 +29,9 @@ import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@CassandraRequirement( - max = "4.0-beta4", +@BackendRequirement( + type = BackendType.CASSANDRA, + maxExclusive = "4.0-beta4", // TODO Re-enable when CASSANDRA-16364 is fixed description = "TODO Re-enable when CASSANDRA-16364 is fixed") public class RandomTokenVnodesIT extends TokenITBase { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index 1e2803c7ef4..266c24f2c45 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -31,8 +31,9 @@ import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -185,7 +186,10 @@ public void should_refresh_schema_manually() { } } - @CassandraRequirement(min = "4.0", description = "virtual tables introduced in 4.0") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "4.0", + description = "virtual tables introduced in 4.0") @Test public void should_get_virtual_metadata() { skipIfDse60(); @@ -269,7 +273,10 @@ public void should_get_virtual_metadata() { } } - @CassandraRequirement(min = "4.0", description = "virtual tables introduced in 4.0") + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "4.0", + description = "virtual tables introduced in 4.0") @Test public void should_exclude_virtual_keyspaces_from_token_map() { skipIfDse60(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java index e771b28116a..949e62eae28 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/DriverBlockHoundIntegrationCcmIT.java @@ -26,8 +26,9 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; -import com.datastax.oss.driver.api.testinfra.DseRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.IsolatedTests; import java.time.Duration; @@ -51,8 +52,9 @@ * {@link DriverBlockHoundIntegration} are being applied, and especially when continuous paging is * used. */ -@DseRequirement( - min = "5.1.0", +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.1.0", description = "Continuous paging is only available from 5.1.0 onwards") @Category(IsolatedTests.class) public class DriverBlockHoundIntegrationCcmIT extends ContinuousPagingITBase { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultNullSavingStrategyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultNullSavingStrategyIT.java index cbcf0cc4f5e..be17e70963d 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultNullSavingStrategyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DefaultNullSavingStrategyIT.java @@ -35,8 +35,9 @@ import com.datastax.oss.driver.api.mapper.annotations.SetEntity; import com.datastax.oss.driver.api.mapper.annotations.Update; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import java.util.function.BiConsumer; @@ -53,7 +54,10 @@ * DefaultNullSavingStrategy} annotation. */ @Category(ParallelizableTests.class) -@CassandraRequirement(min = "2.2", description = "support for unset values") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.2", + description = "support for unset values") public class DefaultNullSavingStrategyIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java index 18ff14cee43..4ddccc48b52 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java @@ -36,8 +36,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; @@ -53,8 +54,9 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement( - min = "3.0", +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.0", description = ">= in WHERE clause not supported in legacy versions") public class DeleteIT extends InventoryITBase { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/IncrementWithNullsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/IncrementWithNullsIT.java index 642bb9c17b9..3d0cef6afce 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/IncrementWithNullsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/IncrementWithNullsIT.java @@ -28,8 +28,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.mapper.IncrementIT.ProductRating; @@ -42,7 +43,7 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "2.2") +@BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "2.2") public class IncrementWithNullsIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java index b7b8742e53c..73f89c19a07 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java @@ -38,8 +38,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.annotations.SetEntity; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -61,7 +62,10 @@ /** Tests that entities with UDTs nested at various levels are properly mapped. */ @Category(ParallelizableTests.class) -@CassandraRequirement(min = "2.2", description = "support for unset values") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.2", + description = "support for unset values") public class NestedUdtIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java index 9cc4004690d..c97e6c084c8 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/PrimitivesIT.java @@ -29,8 +29,9 @@ import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import java.util.Objects; @@ -42,7 +43,10 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "2.2", description = "smallint is a reserved keyword in 2.1") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.2", + description = "smallint is a reserved keyword in 2.1") public class PrimitivesIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java index 9abaa714996..6e9d75c4325 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SchemaValidationIT.java @@ -43,8 +43,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.annotations.Update; import com.datastax.oss.driver.api.mapper.entity.EntityHelper; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.LoggerTest; @@ -61,7 +62,10 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "3.4", description = "Creates a SASI index") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.4", + description = "Creates a SASI index") public class SchemaValidationIT extends InventoryITBase { private static CcmRule ccm = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java index 3afcc03e451..498c9894346 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java @@ -32,8 +32,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Insert; import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; @@ -47,7 +48,10 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "3.4", description = "Creates a SASI index") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.4", + description = "Creates a SASI index") public class SelectCustomWhereClauseIT extends InventoryITBase { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectOtherClausesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectOtherClausesIT.java index 5b479a13f55..96b64f69a80 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectOtherClausesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectOtherClausesIT.java @@ -33,8 +33,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; import com.datastax.oss.driver.api.mapper.annotations.Select; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -49,7 +50,10 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "3.6", description = "Uses PER PARTITION LIMIT") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.6", + description = "Uses PER PARTITION LIMIT") public class SelectOtherClausesIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateCustomIfClauseIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateCustomIfClauseIT.java index 53773a20ee1..d930e9135ce 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateCustomIfClauseIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateCustomIfClauseIT.java @@ -30,8 +30,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.annotations.Update; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; @@ -46,7 +47,10 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "3.11.0", description = "UDT fields in IF clause") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.11.0", + description = "UDT fields in IF clause") public class UpdateCustomIfClauseIT extends InventoryITBase { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateReactiveIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateReactiveIT.java index 6eb2f83793c..98102b30ebe 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateReactiveIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateReactiveIT.java @@ -31,8 +31,9 @@ import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.annotations.Update; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import io.reactivex.Flowable; @@ -47,8 +48,9 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement( - min = "3.6", +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.6", description = "Uses UDT fields in IF conditions (CASSANDRA-7423)") public class UpdateReactiveIT extends InventoryITBase { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/JsonInsertIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/JsonInsertIT.java index 9b6ed735d40..09937e61a64 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/JsonInsertIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/JsonInsertIT.java @@ -30,8 +30,9 @@ import com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException; import com.datastax.oss.driver.api.core.type.codec.ExtraTypeCodecs; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -49,7 +50,10 @@ import org.junit.rules.TestRule; @Category(ParallelizableTests.class) -@CassandraRequirement(min = "2.2", description = "JSON support in Cassandra was added in 2.2") +@BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "2.2", + description = "JSON support in Cassandra was added in 2.2") public class JsonInsertIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGeoTypesIT.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGeoTypesIT.java index ef18fade1fe..c80e8449a39 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGeoTypesIT.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGeoTypesIT.java @@ -19,7 +19,8 @@ import com.datastax.oss.driver.api.osgi.service.MailboxService; import com.datastax.oss.driver.api.osgi.service.geo.GeoMailboxService; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.internal.osgi.checks.DefaultServiceChecks; import com.datastax.oss.driver.internal.osgi.checks.GeoServiceChecks; import com.datastax.oss.driver.internal.osgi.support.BundleOptions; @@ -35,7 +36,10 @@ @RunWith(CcmPaxExam.class) @ExamReactorStrategy(CcmExamReactorFactory.class) -@DseRequirement(min = "5.0", description = "Requires geo types") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "5.0", + description = "Requires geo types") public class OsgiGeoTypesIT { @Inject MailboxService service; diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGraphIT.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGraphIT.java index a34c7946b8b..0b7cef9530f 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGraphIT.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiGraphIT.java @@ -19,7 +19,8 @@ import com.datastax.oss.driver.api.osgi.service.MailboxService; import com.datastax.oss.driver.api.osgi.service.graph.GraphMailboxService; -import com.datastax.oss.driver.api.testinfra.DseRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.internal.osgi.checks.DefaultServiceChecks; import com.datastax.oss.driver.internal.osgi.checks.GraphServiceChecks; import com.datastax.oss.driver.internal.osgi.support.BundleOptions; @@ -35,7 +36,10 @@ @RunWith(CcmPaxExam.class) @ExamReactorStrategy(CcmExamReactorFactory.class) -@DseRequirement(min = "6.8", description = "Requires Core Graph") +@BackendRequirement( + type = BackendType.DSE, + minInclusive = "6.8", + description = "Requires Core Graph") public class OsgiGraphIT { @Inject MailboxService service; diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java index 9794cf27435..e3722530b82 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/OsgiSnappyIT.java @@ -16,7 +16,8 @@ package com.datastax.oss.driver.internal.osgi; import com.datastax.oss.driver.api.osgi.service.MailboxService; -import com.datastax.oss.driver.api.testinfra.CassandraRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.internal.osgi.checks.DefaultServiceChecks; import com.datastax.oss.driver.internal.osgi.support.BundleOptions; import com.datastax.oss.driver.internal.osgi.support.CcmExamReactorFactory; @@ -31,7 +32,7 @@ @RunWith(CcmPaxExam.class) @ExamReactorStrategy(CcmExamReactorFactory.class) -@CassandraRequirement(max = "3.99") +@BackendRequirement(type = BackendType.CASSANDRA, maxExclusive = "4.0.0") public class OsgiSnappyIT { @Inject MailboxService service; diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java index 4a1700639b4..8e33b0c9b11 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java @@ -15,12 +15,7 @@ */ package com.datastax.oss.driver.internal.osgi.support; -import static com.datastax.oss.driver.internal.osgi.support.CcmStagedReactor.CCM_BRIDGE; - -import com.datastax.oss.driver.api.core.Version; -import com.datastax.oss.driver.api.testinfra.requirement.BackendType; -import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement; -import java.util.Collection; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirementRule; import org.junit.AssumptionViolatedException; import org.junit.runner.Description; import org.junit.runner.notification.Failure; @@ -37,19 +32,12 @@ public CcmPaxExam(Class klass) throws InitializationError { @Override public void run(RunNotifier notifier) { Description description = getDescription(); - BackendType backend = - CCM_BRIDGE.getDseVersion().isPresent() ? BackendType.DSE : BackendType.CASSANDRA; - Version version = CCM_BRIDGE.getDseVersion().orElseGet(CCM_BRIDGE::getCassandraVersion); - - Collection requirements = - VersionRequirement.fromAnnotations(getDescription()); - if (VersionRequirement.meetsAny(requirements, backend, version)) { + if (BackendRequirementRule.meetsDescriptionRequirements(description)) { super.run(notifier); } else { // requirements not met, throw reasoning assumption to skip test AssumptionViolatedException e = - new AssumptionViolatedException( - VersionRequirement.buildReasonString(requirements, backend, version)); + new AssumptionViolatedException(BackendRequirementRule.buildReasonString(description)); notifier.fireTestAssumptionFailed(new Failure(description, e)); } } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/CassandraRequirement.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/CassandraRequirement.java index e28757e420f..df50d42c825 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/CassandraRequirement.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/CassandraRequirement.java @@ -21,7 +21,11 @@ /** * Annotation for a Class or Method that defines a Cassandra Version requirement. If the cassandra * version in use does not meet the version requirement, the test is skipped. + * + * @deprecated Replaced by {@link + * com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement} */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) public @interface CassandraRequirement { diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/DseRequirement.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/DseRequirement.java index c80c6914282..f9c0ccd293a 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/DseRequirement.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/DseRequirement.java @@ -21,7 +21,11 @@ /** * Annotation for a Class or Method that defines a DSE Version requirement. If the DSE version in * use does not meet the version requirement or DSE isn't used at all, the test is skipped. + * + * @deprecated Replaced by {@link + * com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement} */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) public @interface DseRequirement { diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java index d4830dd249e..29c8da9c7c9 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java @@ -19,9 +19,7 @@ import com.datastax.oss.driver.api.core.ProtocolVersion; import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; -import com.datastax.oss.driver.api.testinfra.requirement.BackendType; -import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement; -import java.util.Collection; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirementRule; import java.util.Optional; import org.junit.AssumptionViolatedException; import org.junit.runner.Description; @@ -58,13 +56,7 @@ protected void after() { @Override public Statement apply(Statement base, Description description) { - BackendType backend = - ccmBridge.getDseVersion().isPresent() ? BackendType.DSE : BackendType.CASSANDRA; - Version version = ccmBridge.getDseVersion().orElseGet(ccmBridge::getCassandraVersion); - - Collection requirements = VersionRequirement.fromAnnotations(description); - - if (VersionRequirement.meetsAny(requirements, backend, version)) { + if (BackendRequirementRule.meetsDescriptionRequirements(description)) { return super.apply(base, description); } else { // requirements not met, throw reasoning assumption to skip test @@ -72,7 +64,7 @@ public Statement apply(Statement base, Description description) { @Override public void evaluate() { throw new AssumptionViolatedException( - VersionRequirement.buildReasonString(requirements, backend, version)); + BackendRequirementRule.buildReasonString(description)); } }; } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java new file mode 100644 index 00000000000..2f48331a0ff --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java @@ -0,0 +1,59 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.requirement; + +import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; +import org.junit.AssumptionViolatedException; +import org.junit.rules.ExternalResource; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class BackendRequirementRule extends ExternalResource { + @Override + public Statement apply(Statement base, Description description) { + if (meetsDescriptionRequirements(description)) { + return super.apply(base, description); + } else { + // requirements not met, throw reasoning assumption to skip test + return new Statement() { + @Override + public void evaluate() { + throw new AssumptionViolatedException(buildReasonString(description)); + } + }; + } + } + + protected static BackendType getBackendType() { + return CcmBridge.DSE_ENABLEMENT ? BackendType.DSE : BackendType.CASSANDRA; + } + + protected static Version getVersion() { + return CcmBridge.VERSION; + } + + public static boolean meetsDescriptionRequirements(Description description) { + return VersionRequirement.meetsAny( + VersionRequirement.fromAnnotations(description), getBackendType(), getVersion()); + } + + /* Note, duplicating annotation processing from #meetsDescriptionRequirements */ + public static String buildReasonString(Description description) { + return VersionRequirement.buildReasonString( + VersionRequirement.fromAnnotations(description), getBackendType(), getVersion()); + } +} diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java index 28a72bc92ad..c83792286b3 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/VersionRequirement.java @@ -100,6 +100,9 @@ public static Collection fromAnnotations(Description descrip CassandraRequirement cassandraRequirement = description.getAnnotation(CassandraRequirement.class); DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class); + // matches methods/classes with one @BackendRequirement annotation + BackendRequirement backendRequirement = description.getAnnotation(BackendRequirement.class); + // matches methods/classes with two or more @BackendRequirement annotations BackendRequirements backendRequirements = description.getAnnotation(BackendRequirements.class); // build list of required versions @@ -110,6 +113,9 @@ public static Collection fromAnnotations(Description descrip if (dseRequirement != null) { requirements.add(VersionRequirement.fromDseRequirement(dseRequirement)); } + if (backendRequirement != null) { + requirements.add(VersionRequirement.fromBackendRequirement(backendRequirement)); + } if (backendRequirements != null) { Arrays.stream(backendRequirements.value()) .forEach(r -> requirements.add(VersionRequirement.fromBackendRequirement(r))); From ff4e003601b2d92eee3f4a9ea881d1e38ebfc8e4 Mon Sep 17 00:00:00 2001 From: hhughes Date: Mon, 21 Aug 2023 13:55:22 -0700 Subject: [PATCH 277/395] JAVA-3076: NullSavingStrategyIT sometimes fails with ProtocolError: Must not send frame with WARNING flag for native protocol version < 4 (#1669) NullSavingStrategyIT.java: - Remove V3 protocol configuration from class SessionRule - Create new session configured with V3 protocol in @BeforeClass method to use in tests --- .../driver/mapper/NullSavingStrategyIT.java | 63 ++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NullSavingStrategyIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NullSavingStrategyIT.java index 32f71041b19..99d7abef4a2 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NullSavingStrategyIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NullSavingStrategyIT.java @@ -36,9 +36,11 @@ import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; import java.util.Objects; import java.util.UUID; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -51,13 +53,24 @@ public class NullSavingStrategyIT { private static final CcmRule CCM_RULE = CcmRule.getInstance(); - private static final SessionRule SESSION_RULE = - SessionRule.builder(CCM_RULE) - .withConfigLoader( - DriverConfigLoader.programmaticBuilder() - .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") - .build()) - .build(); + private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); + + // JAVA-3076: V3 protocol calls that could trigger cassandra to issue client warnings appear to be + // inherently unstable when used at the same time as V4+ protocol clients (common since this is + // part of the parallelizable test suite). + // + // For this test we'll use latest protocol version for SessionRule set-up, which creates the + // keyspace and could potentially result in warning about too many keyspaces, and then create a + // new client for the tests to use, which they access via the static InventoryMapper instance + // `mapper`. + // + // This additional client is created in the @BeforeClass method #setup() and guaranteed to be + // closed in @AfterClass method #teardown(). + // + // Note: The standard junit runner executes rules before class/test setup so the order of + // execution will be CcmRule#before > SessionRule#before > NullSavingStrategyIT#setup, meaning + // CCM_RULE/SESSION_RULE should be fully initialized by the time #setup() is invoked. + private static CqlSession v3Session; @ClassRule public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE); @@ -66,14 +79,34 @@ public class NullSavingStrategyIT { @BeforeClass public static void setup() { - CqlSession session = SESSION_RULE.session(); - session.execute( - SimpleStatement.builder( - "CREATE TABLE product_simple(id uuid PRIMARY KEY, description text)") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); - - mapper = new NullSavingStrategyIT_InventoryMapperBuilder(session).build(); + // setup table for use in tests, this can use the default session + SESSION_RULE + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE product_simple(id uuid PRIMARY KEY, description text)") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + + // Create V3 protocol session for use in tests, will be closed in #teardown() + v3Session = + SessionUtils.newSession( + CCM_RULE, + SESSION_RULE.keyspace(), + DriverConfigLoader.programmaticBuilder() + .withString(DefaultDriverOption.PROTOCOL_VERSION, "V3") + .build()); + + // Hand V3 session to InventoryMapper which the tests will use to perform db calls + mapper = new NullSavingStrategyIT_InventoryMapperBuilder(v3Session).build(); + } + + @AfterClass + public static void teardown() { + // Close V3 session (SESSION_RULE will be closed separately by @ClassRule handling) + if (v3Session != null) { + v3Session.close(); + } } @Test From d990f92ba01c3ecaaa3f31a0f1fb327f77a96617 Mon Sep 17 00:00:00 2001 From: hhughes Date: Tue, 22 Aug 2023 15:27:53 -0700 Subject: [PATCH 278/395] JAVA-3104: Do not eagerly pre-allocate array when deserializing CqlVector (#1714) --- .../oss/driver/api/core/data/CqlVector.java | 2 +- .../driver/api/core/data/CqlVectorTest.java | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java index 2889ea5eb24..4d388e3062c 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java @@ -218,7 +218,7 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo stream.defaultReadObject(); int size = stream.readInt(); - list = new ArrayList<>(size); + list = new ArrayList<>(); for (int i = 0; i < size; i++) { list.add((T) stream.readObject()); } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java index 75dfbc26e42..ff28edf85ba 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java @@ -17,16 +17,22 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.fail; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.internal.SerializationHelper; import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import java.io.ByteArrayInputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamException; import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; import org.assertj.core.util.Lists; import org.junit.Test; @@ -231,4 +237,20 @@ public int size() { CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); assertThat(deserialized).isEqualTo(initial); } + + @Test + public void should_not_use_preallocate_serialized_size() throws DecoderException { + // serialized CqlVector(1.0f, 2.5f, 3.0f) with size field adjusted to Integer.MAX_VALUE + byte[] suspiciousBytes = + Hex.decodeHex( + "aced000573720042636f6d2e64617461737461782e6f73732e6472697665722e6170692e636f72652e646174612e43716c566563746f722453657269616c697a6174696f6e50726f78790000000000000001030000787077047fffffff7372000f6a6176612e6c616e672e466c6f6174daedc9a2db3cf0ec02000146000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b02000078703f8000007371007e0002402000007371007e00024040000078" + .toCharArray()); + try { + new ObjectInputStream(new ByteArrayInputStream(suspiciousBytes)).readObject(); + fail("Should not be able to deserialize bytes with incorrect size field"); + } catch (Exception e) { + // check we fail to deserialize, rather than OOM + assertThat(e).isInstanceOf(ObjectStreamException.class); + } + } } From acd1cc31c6c64193e044c0f92f311cb1143035f4 Mon Sep 17 00:00:00 2001 From: Madhavan Date: Thu, 7 Sep 2023 12:19:59 -0400 Subject: [PATCH 279/395] Fix hyperlink on the https://docs.datastax.com/en/developer/java-driver/latest/manual/mapper/mapper/#mapper-builder website (#1723) --- manual/mapper/mapper/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 18be59df1c4..894143f0b9b 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -39,7 +39,7 @@ public interface InventoryMapper { ``` The builder allows you to create a mapper instance, by wrapping a core `CqlSession` (if you need -more details on how to create a session, refer to the [core driver documentation](../core/)). +more details on how to create a session, refer to the [core driver documentation](../../core/)). ```java CqlSession session = CqlSession.builder().build(); From 3c4aa0e9c162db590ba3cb21b93faa200f812e48 Mon Sep 17 00:00:00 2001 From: hhughes Date: Thu, 7 Sep 2023 13:52:46 -0700 Subject: [PATCH 280/395] JAVA-3116: update surefire/failsafe to 3.0.0 to fix issue running tests with specified jvm (#1719) Additionally: - Set --jvm_version=8 when running dse 6.8.19+ with graph workloads (DSP-23501) - Update commons-configuration2 to 2.9.0 + deps in BundleOptions to support java17 - Update felix framework version to 7.0.1 for java17 (FELIX-6287) - Pick up newer bndlib for ArrayIndexOutOfBounds error printed with OsgiGraphIT (bndtools/bnd issue#3405) - Update pax-url-wrap to 2.6.4 (and bring pax-url-reference up to the same version) - Force newer tinybundles version 3.0.0 (default 2.1.1 version required older bndlib) --- .../internal/osgi/support/BundleOptions.java | 5 +- pom.xml | 14 ++++-- .../driver/api/testinfra/ccm/CcmBridge.java | 49 ++++++++++++++++++- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java index 6e7d82787f4..aa62b623f4b 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java @@ -152,9 +152,10 @@ public static CompositeOption tinkerpopBundles() { .overwriteManifest(WrappedUrlProvisionOption.OverwriteMode.FULL), // Note: the versions below are hard-coded because they shouldn't change very often, // but if the tests fail because of them, we should consider parameterizing them - mavenBundle("com.sun.mail", "mailapi", "1.6.4"), + mavenBundle("com.sun.activation", "jakarta.activation", "2.0.1"), + mavenBundle("com.sun.mail", "mailapi", "2.0.1"), mavenBundle("org.apache.commons", "commons-text", "1.8"), - mavenBundle("org.apache.commons", "commons-configuration2", "2.7"), + mavenBundle("org.apache.commons", "commons-configuration2", "2.9.0"), CoreOptions.wrappedBundle(mavenBundle("commons-logging", "commons-logging", "1.1.1")) .exports("org.apache.commons.logging.*") .bundleVersion("1.1.1") diff --git a/pom.xml b/pom.xml index b74cfeee652..efde974bb28 100644 --- a/pom.xml +++ b/pom.xml @@ -68,8 +68,9 @@ 4.13.2 1.2.3 6.0.0 - 6.0.3 + 7.0.1 4.13.4 + 2.6.4 0.11.0 1.1.4 2.31 @@ -79,7 +80,7 @@ 2.2.2 4.0.3 2.0.0-M19 - 2.22.2 + 3.0.0 22.0.0.2 false ${skipTests} @@ -269,12 +270,17 @@ org.ops4j.pax.url pax-url-wrap - 2.6.3 + ${pax-url.version} org.ops4j.pax.url pax-url-reference - 2.6.2 + ${pax-url.version} + + + org.ops4j.pax.tinybundles + tinybundles + 3.0.0 org.glassfish diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java index cef9e13c4b6..6985516f84b 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java @@ -44,6 +44,7 @@ import org.apache.commons.exec.Executor; import org.apache.commons.exec.LogOutputStream; import org.apache.commons.exec.PumpStreamHandler; +import org.assertj.core.util.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -267,8 +268,11 @@ public void reloadCore(int node, String keyspace, String table, boolean reindex) public void start() { if (started.compareAndSet(false, true)) { + List cmdAndArgs = Lists.newArrayList("start", jvmArgs, "--wait-for-binary-proto"); + overrideJvmVersionForDseWorkloads() + .ifPresent(jvmVersion -> cmdAndArgs.add(String.format("--jvm_version=%d", jvmVersion))); try { - execute("start", jvmArgs, "--wait-for-binary-proto"); + execute(cmdAndArgs.toArray(new String[0])); } catch (RuntimeException re) { // if something went wrong starting CCM, see if we can also dump the error executeCheckLogError(); @@ -296,7 +300,10 @@ public void resume(int n) { } public void start(int n) { - execute("node" + n, "start"); + List cmdAndArgs = Lists.newArrayList("node" + n, "start"); + overrideJvmVersionForDseWorkloads() + .ifPresent(jvmVersion -> cmdAndArgs.add(String.format("--jvm_version=%d", jvmVersion))); + execute(cmdAndArgs.toArray(new String[0])); } public void stop(int n) { @@ -416,6 +423,44 @@ private static File createTempStore(String storePath) { return f; } + /** + * Get the current JVM major version (1.8.0_372 -> 8, 11.0.19 -> 11) + * + * @return major version of current JVM + */ + private static int getCurrentJvmMajorVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if (dot != -1) { + version = version.substring(0, dot); + } + } + return Integer.parseInt(version); + } + + private Optional overrideJvmVersionForDseWorkloads() { + if (getCurrentJvmMajorVersion() <= 8) { + return Optional.empty(); + } + + if (!DSE_ENABLEMENT || !getDseVersion().isPresent()) { + return Optional.empty(); + } + + if (getDseVersion().get().compareTo(Version.parse("6.8.19")) < 0) { + return Optional.empty(); + } + + if (dseWorkloads.contains("graph")) { + return Optional.of(8); + } + + return Optional.empty(); + } + public static Builder builder() { return new Builder(); } From 18498127e0dc060d569f3e66731b21263022ffe2 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Mon, 11 Sep 2023 08:11:36 -0700 Subject: [PATCH 281/395] Update 4.x changelog for 3.11.5 release (#1731) --- changelog/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index cb272907b66..54d0d7a6c37 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -632,6 +632,10 @@ changelog](https://docs.datastax.com/en/developer/java-driver-dse/latest/changel - [bug] JAVA-1499: Wait for load balancing policy at cluster initialization - [new feature] JAVA-1495: Add prepared statements +## 3.11.5 +- [improvement] JAVA-3114: Shade io.dropwizard.metrics:metrics-core in shaded driver +- [improvement] JAVA-3115: SchemaChangeListener#onKeyspaceChanged can fire when keyspace has not changed if using SimpleStrategy replication + ## 3.11.4 - [improvement] JAVA-3079: Upgrade Netty to 4.1.94, 3.x edition - [improvement] JAVA-3082: Fix maven build for Apple-silicon From 06947df149626dff539c24dc95257759b2a42709 Mon Sep 17 00:00:00 2001 From: nparaddi-walmart <121308948+nparaddi-walmart@users.noreply.github.com> Date: Mon, 11 Sep 2023 10:16:47 -0700 Subject: [PATCH 282/395] =?UTF-8?q?add=20support=20for=20publishing=20perc?= =?UTF-8?q?entile=20time=20series=20for=20the=20histogram=20m=E2=80=A6=20(?= =?UTF-8?q?#1689)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add support for publishing percentile time series for the histogram metrics cql-requests, cql-messages and throttling delay. Motivation: Histogram metrics is generating too many metrics overloading the promethous servers. if application has 500 Vms and 1000 cassandra nodes, The histogram metrics generates 100*500*1000 = 50,000,000 time series every 30 seconds. This is just too much metrics. Let us say we can generate percentile 95 timeseries for for every cassandra nodes, then we only have 1*500 = 500 metrics and in applciation side, we can ignore the _bucket time series. This way there will be very less metrics. Modifications: add configurable pre-defined percentiles to Micrometer Timer.Builder.publishPercentiles. This change is being added to cql-requests, cql-messages and throttling delay. Result: Based on the configuration, we will see additonal quantile time series for cql-requests, cql-messages and throttling delay histogram metrics. * add support for publishing percentile time series for the histogram metrics cql-requests, cql-messages and throttling delay. Motivation: Histogram metrics is generating too many metrics overloading the promethous servers. if application has 500 Vms and 1000 cassandra nodes, The histogram metrics generates 100*500*1000 = 50,000,000 time series every 30 seconds. This is just too much metrics. Let us say we can generate percentile 95 timeseries for for every cassandra nodes, then we only have 1*500 = 500 metrics and in applciation side, we can ignore the _bucket time series. This way there will be very less metrics. Modifications: add configurable pre-defined percentiles to Micrometer Timer.Builder.publishPercentiles. This change is being added to cql-requests, cql-messages and throttling delay. Result: Based on the configuration, we will see additonal quantile time series for cql-requests, cql-messages and throttling delay histogram metrics. * using helper method as suggested in review * fixes as per review comments * add configuration option which switches aggregable histogram generation on/off for all metric flavors [default=on] * updating java doc * rename method to publishPercentilesIfDefined * renmae method --------- Co-authored-by: Nagappa Paraddi --- .../api/core/config/DseDriverOption.java | 28 ++++++++ .../api/core/config/DefaultDriverOption.java | 35 ++++++++++ .../driver/api/core/config/OptionsMap.java | 1 + .../api/core/config/TypedDriverOption.java | 45 +++++++++++++ core/src/main/resources/reference.conf | 25 +++++++- .../micrometer/MicrometerMetricUpdater.java | 26 +++++++- .../MicrometerNodeMetricUpdater.java | 15 +++-- .../MicrometerSessionMetricUpdater.java | 29 ++++++--- .../MicrometerNodeMetricUpdaterTest.java | 64 ++++++++++++++++++- .../MicrometerSessionMetricUpdaterTest.java | 64 ++++++++++++++++++- 10 files changed, 311 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java b/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java index 74907c177b6..3ad6ed683bf 100644 --- a/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java +++ b/core/src/main/java/com/datastax/dse/driver/api/core/config/DseDriverOption.java @@ -288,6 +288,34 @@ public enum DseDriverOption implements DriverOption { *

    Value-type: {@link java.time.Duration Duration} */ METRICS_NODE_GRAPH_MESSAGES_SLO("advanced.metrics.node.graph-messages.slo"), + /** + * Optional list of percentiles to publish for graph-requests metric. Produces an additional time + * series for each requested percentile. This percentile is computed locally, and so can't be + * aggregated with percentiles computed across other dimensions (e.g. in a different instance). + * + *

    Value type: {@link java.util.List List}<{@link Double}> + */ + METRICS_SESSION_GRAPH_REQUESTS_PUBLISH_PERCENTILES( + "advanced.metrics.session.graph-requests.publish-percentiles"), + /** + * Optional list of percentiles to publish for node graph-messages metric. Produces an additional + * time series for each requested percentile. This percentile is computed locally, and so can't be + * aggregated with percentiles computed across other dimensions (e.g. in a different instance). + * + *

    Value type: {@link java.util.List List}<{@link Double}> + */ + METRICS_NODE_GRAPH_MESSAGES_PUBLISH_PERCENTILES( + "advanced.metrics.node.graph-messages.publish-percentiles"), + /** + * Optional list of percentiles to publish for continuous paging requests metric. Produces an + * additional time series for each requested percentile. This percentile is computed locally, and + * so can't be aggregated with percentiles computed across other dimensions (e.g. in a different + * instance). + * + *

    Value type: {@link java.util.List List}<{@link Double}> + */ + CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES( + "advanced.metrics.session.continuous-cql-requests.publish-percentiles"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index e7e75d952fa..71d07236f1e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -939,6 +939,41 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: List of {@link String} */ METADATA_SCHEMA_CHANGE_LISTENER_CLASSES("advanced.schema-change-listener.classes"), + /** + * Optional list of percentiles to publish for cql-requests metric. Produces an additional time + * series for each requested percentile. This percentile is computed locally, and so can't be + * aggregated with percentiles computed across other dimensions (e.g. in a different instance). + * + *

    Value type: {@link java.util.List List}<{@link Double}> + */ + METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES( + "advanced.metrics.session.cql-requests.publish-percentiles"), + /** + * Optional list of percentiles to publish for node cql-messages metric. Produces an additional + * time series for each requested percentile. This percentile is computed locally, and so can't be + * aggregated with percentiles computed across other dimensions (e.g. in a different instance). + * + *

    Value type: {@link java.util.List List}<{@link Double}> + */ + METRICS_NODE_CQL_MESSAGES_PUBLISH_PERCENTILES( + "advanced.metrics.node.cql-messages.publish-percentiles"), + /** + * Optional list of percentiles to publish for throttling delay metric.Produces an additional time + * series for each requested percentile. This percentile is computed locally, and so can't be + * aggregated with percentiles computed across other dimensions (e.g. in a different instance). + * + *

    Value type: {@link java.util.List List}<{@link Double}> + */ + METRICS_SESSION_THROTTLING_PUBLISH_PERCENTILES( + "advanced.metrics.session.throttling.delay.publish-percentiles"), + /** + * Adds histogram buckets used to generate aggregable percentile approximations in monitoring + * systems that have query facilities to do so (e.g. Prometheus histogram_quantile, Atlas + * percentiles). + * + *

    Value-type: boolean + */ + METRICS_GENERATE_AGGREGABLE_HISTOGRAMS("advanced.metrics.histograms.generate-aggregable"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 8f5aa01592e..2c7a1169984 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -378,6 +378,7 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.COALESCER_INTERVAL, Duration.of(10, ChronoUnit.MICROS)); map.put(TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC, 0); map.put(TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, false); + map.put(TypedDriverOption.METRICS_GENERATE_AGGREGABLE_HISTOGRAMS, true); } @Immutable diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index 2428be064ce..3f790e9c0dd 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -388,6 +388,10 @@ public String toString() { /** The consistency level to use for trace queries. */ public static final TypedDriverOption REQUEST_TRACE_CONSISTENCY = new TypedDriverOption<>(DefaultDriverOption.REQUEST_TRACE_CONSISTENCY, GenericType.STRING); + /** Whether or not to publish aggregable histogram for metrics */ + public static final TypedDriverOption METRICS_GENERATE_AGGREGABLE_HISTOGRAMS = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_GENERATE_AGGREGABLE_HISTOGRAMS, GenericType.BOOLEAN); /** List of enabled session-level metrics. */ public static final TypedDriverOption> METRICS_SESSION_ENABLED = new TypedDriverOption<>( @@ -409,6 +413,12 @@ public String toString() { new TypedDriverOption<>( DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_SLO, GenericType.listOf(GenericType.DURATION)); + /** Optional pre-defined percentile of cql requests to publish, as a list of percentiles . */ + public static final TypedDriverOption> + METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES, + GenericType.listOf(GenericType.DOUBLE)); /** * The number of significant decimal digits to which internal structures will maintain for * requests. @@ -433,6 +443,12 @@ public String toString() { new TypedDriverOption<>( DefaultDriverOption.METRICS_SESSION_THROTTLING_SLO, GenericType.listOf(GenericType.DURATION)); + /** Optional pre-defined percentile of throttling delay to publish, as a list of percentiles . */ + public static final TypedDriverOption> + METRICS_SESSION_THROTTLING_PUBLISH_PERCENTILES = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_SESSION_THROTTLING_PUBLISH_PERCENTILES, + GenericType.listOf(GenericType.DOUBLE)); /** * The number of significant decimal digits to which internal structures will maintain for * throttling. @@ -457,6 +473,12 @@ public String toString() { new TypedDriverOption<>( DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_SLO, GenericType.listOf(GenericType.DURATION)); + /** Optional pre-defined percentile of node cql messages to publish, as a list of percentiles . */ + public static final TypedDriverOption> + METRICS_NODE_CQL_MESSAGES_PUBLISH_PERCENTILES = + new TypedDriverOption<>( + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_PUBLISH_PERCENTILES, + GenericType.listOf(GenericType.DOUBLE)); /** * The number of significant decimal digits to which internal structures will maintain for * requests. @@ -700,6 +722,15 @@ public String toString() { new TypedDriverOption<>( DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO, GenericType.listOf(GenericType.DURATION)); + /** + * Optional pre-defined percentile of continuous paging cql requests to publish, as a list of + * percentiles . + */ + public static final TypedDriverOption> + CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES = + new TypedDriverOption<>( + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES, + GenericType.listOf(GenericType.DOUBLE)); /** * The number of significant decimal digits to which internal structures will maintain for * continuous requests. @@ -774,6 +805,12 @@ public String toString() { new TypedDriverOption<>( DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_SLO, GenericType.listOf(GenericType.DURATION)); + /** Optional pre-defined percentile of graph requests to publish, as a list of percentiles . */ + public static final TypedDriverOption> + METRICS_SESSION_GRAPH_REQUESTS_PUBLISH_PERCENTILES = + new TypedDriverOption<>( + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_PUBLISH_PERCENTILES, + GenericType.listOf(GenericType.DOUBLE)); /** * The number of significant decimal digits to which internal structures will maintain for graph * requests. @@ -798,6 +835,14 @@ public String toString() { new TypedDriverOption<>( DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_SLO, GenericType.listOf(GenericType.DURATION)); + /** + * Optional pre-defined percentile of node graph requests to publish, as a list of percentiles . + */ + public static final TypedDriverOption> + METRICS_NODE_GRAPH_MESSAGES_PUBLISH_PERCENTILES = + new TypedDriverOption<>( + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_PUBLISH_PERCENTILES, + GenericType.listOf(GenericType.DOUBLE)); /** * The number of significant decimal digits to which internal structures will maintain for graph * requests. diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index ee83280032e..4c58a1698e1 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1434,6 +1434,16 @@ datastax-java-driver { // prefix = "cassandra" } + histograms { + # Adds histogram buckets used to generate aggregable percentile approximations in monitoring + # systems that have query facilities to do so (e.g. Prometheus histogram_quantile, Atlas percentiles). + # + # Required: no + # Modifiable at runtime: no + # Overridable in a profile: no + generate-aggregable = true + } + # The session-level metrics (all disabled by default). # # Required: yes @@ -1526,7 +1536,7 @@ datastax-java-driver { # Modifiable at runtime: no # Overridable in a profile: no cql-requests { - + # The largest latency that we expect to record. # # This should be slightly higher than request.timeout (in theory, readings can't be higher @@ -1569,7 +1579,7 @@ datastax-java-driver { # time). # Valid for: Dropwizard. refresh-interval = 5 minutes - + # An optional list of latencies to track as part of the application's service-level # objectives (SLOs). # @@ -1577,7 +1587,11 @@ datastax-java-driver { # buckets used to generate aggregable percentile approximations. # Valid for: Micrometer. // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] - + + # An optional list of percentiles to be published by Micrometer. Produces an additional time series for each requested percentile. + # This percentile is computed locally, and so can't be aggregated with percentiles computed across other dimensions (e.g. in a different instance) + # Valid for: Micrometer. + // publish-percentiles = [ 0.75, 0.95, 0.99 ] } # Required: if the 'throttling.delay' metric is enabled, and Dropwizard or Micrometer is used. @@ -1589,6 +1603,7 @@ datastax-java-driver { significant-digits = 3 refresh-interval = 5 minutes // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] + // publish-percentiles = [ 0.75, 0.95, 0.99 ] } # Required: if the 'continuous-cql-requests' metric is enabled, and Dropwizard or Micrometer @@ -1601,6 +1616,7 @@ datastax-java-driver { significant-digits = 3 refresh-interval = 5 minutes // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] + // publish-percentiles = [ 0.75, 0.95, 0.99 ] } # Required: if the 'graph-requests' metric is enabled, and Dropwizard or Micrometer is used. @@ -1612,6 +1628,7 @@ datastax-java-driver { significant-digits = 3 refresh-interval = 5 minutes // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] + // publish-percentiles = [ 0.75, 0.95, 0.99 ] } } # The node-level metrics (all disabled by default). @@ -1776,6 +1793,7 @@ datastax-java-driver { significant-digits = 3 refresh-interval = 5 minutes // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] + // publish-percentiles = [ 0.75, 0.95, 0.99 ] } # See graph-requests in the `session` section @@ -1789,6 +1807,7 @@ datastax-java-driver { significant-digits = 3 refresh-interval = 5 minutes // slo = [ 100 milliseconds, 500 milliseconds, 1 second ] + // publish-percentiles = [ 0.75, 0.95, 0.99 ] } # The time after which the node level metrics will be evicted. diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java index c30dcc121ab..4785da14543 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java @@ -15,7 +15,9 @@ */ package com.datastax.oss.driver.internal.metrics.micrometer; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.config.DriverOption; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metrics.AbstractMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.MetricId; @@ -27,6 +29,7 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Timer; +import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -151,12 +154,31 @@ protected Timer getOrCreateTimerFor(MetricT metric) { } protected Timer.Builder configureTimer(Timer.Builder builder, MetricT metric, MetricId id) { - return builder.publishPercentileHistogram(); + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + if (profile.getBoolean(DefaultDriverOption.METRICS_GENERATE_AGGREGABLE_HISTOGRAMS)) { + builder.publishPercentileHistogram(); + } + return builder; } @SuppressWarnings("unused") protected DistributionSummary.Builder configureDistributionSummary( DistributionSummary.Builder builder, MetricT metric, MetricId id) { - return builder.publishPercentileHistogram(); + DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + if (profile.getBoolean(DefaultDriverOption.METRICS_GENERATE_AGGREGABLE_HISTOGRAMS)) { + builder.publishPercentileHistogram(); + } + return builder; + } + + static double[] toDoubleArray(List doubleList) { + return doubleList.stream().mapToDouble(Double::doubleValue).toArray(); + } + + static void configurePercentilesPublishIfDefined( + Timer.Builder builder, DriverExecutionProfile profile, DriverOption driverOption) { + if (profile.isDefined(driverOption)) { + builder.publishPercentiles(toDoubleArray(profile.getDoubleList(driverOption))); + } } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java index 0f5dada2bf3..d6359bca327 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdater.java @@ -96,9 +96,9 @@ protected void cancelMetricsExpirationTimeout() { @Override protected Timer.Builder configureTimer(Timer.Builder builder, NodeMetric metric, MetricId id) { DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + super.configureTimer(builder, metric, id); if (metric == DefaultNodeMetric.CQL_MESSAGES) { - return builder - .publishPercentileHistogram() + builder .minimumExpectedValue( profile.getDuration(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_LOWEST)) .maximumExpectedValue( @@ -111,9 +111,11 @@ protected Timer.Builder configureTimer(Timer.Builder builder, NodeMetric metric, : null) .percentilePrecision( profile.getInt(DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS)); + + configurePercentilesPublishIfDefined( + builder, profile, DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_PUBLISH_PERCENTILES); } else if (metric == DseNodeMetric.GRAPH_MESSAGES) { - return builder - .publishPercentileHistogram() + builder .minimumExpectedValue( profile.getDuration(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_LOWEST)) .maximumExpectedValue( @@ -125,7 +127,10 @@ protected Timer.Builder configureTimer(Timer.Builder builder, NodeMetric metric, .toArray(new Duration[0]) : null) .percentilePrecision(profile.getInt(DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_DIGITS)); + + configurePercentilesPublishIfDefined( + builder, profile, DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_PUBLISH_PERCENTILES); } - return super.configureTimer(builder, metric, id); + return builder; } } diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java index bb361b85f22..f9387f1685a 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdater.java @@ -63,9 +63,9 @@ protected MetricId getMetricId(SessionMetric metric) { @Override protected Timer.Builder configureTimer(Timer.Builder builder, SessionMetric metric, MetricId id) { DriverExecutionProfile profile = context.getConfig().getDefaultProfile(); + super.configureTimer(builder, metric, id); if (metric == DefaultSessionMetric.CQL_REQUESTS) { - return builder - .publishPercentileHistogram() + builder .minimumExpectedValue( profile.getDuration(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_LOWEST)) .maximumExpectedValue( @@ -80,9 +80,11 @@ protected Timer.Builder configureTimer(Timer.Builder builder, SessionMetric metr profile.isDefined(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS) ? profile.getInt(DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS) : null); + + configurePercentilesPublishIfDefined( + builder, profile, DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES); } else if (metric == DefaultSessionMetric.THROTTLING_DELAY) { - return builder - .publishPercentileHistogram() + builder .minimumExpectedValue( profile.getDuration(DefaultDriverOption.METRICS_SESSION_THROTTLING_LOWEST)) .maximumExpectedValue( @@ -97,9 +99,11 @@ protected Timer.Builder configureTimer(Timer.Builder builder, SessionMetric metr profile.isDefined(DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS) ? profile.getInt(DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS) : null); + + configurePercentilesPublishIfDefined( + builder, profile, DefaultDriverOption.METRICS_SESSION_THROTTLING_PUBLISH_PERCENTILES); } else if (metric == DseSessionMetric.CONTINUOUS_CQL_REQUESTS) { - return builder - .publishPercentileHistogram() + builder .minimumExpectedValue( profile.getDuration( DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_LOWEST)) @@ -119,9 +123,13 @@ protected Timer.Builder configureTimer(Timer.Builder builder, SessionMetric metr ? profile.getInt( DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS) : null); + + configurePercentilesPublishIfDefined( + builder, + profile, + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES); } else if (metric == DseSessionMetric.GRAPH_REQUESTS) { - return builder - .publishPercentileHistogram() + builder .minimumExpectedValue( profile.getDuration(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_LOWEST)) .maximumExpectedValue( @@ -136,7 +144,10 @@ protected Timer.Builder configureTimer(Timer.Builder builder, SessionMetric metr profile.isDefined(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS) ? profile.getInt(DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS) : null); + + configurePercentilesPublishIfDefined( + builder, profile, DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_PUBLISH_PERCENTILES); } - return super.configureTimer(builder, metric, id); + return builder; } } diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java index fbdfb7b2355..e5482aad910 100644 --- a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerNodeMetricUpdaterTest.java @@ -152,7 +152,8 @@ public void should_create_timer( DriverOption lowest, DriverOption highest, DriverOption digits, - DriverOption sla) { + DriverOption sla, + DriverOption percentiles) { // given Node node = mock(Node.class); InternalDriverContext context = mock(InternalDriverContext.class); @@ -174,6 +175,8 @@ public void should_create_timer( when(profile.isDefined(sla)).thenReturn(true); when(profile.getDurationList(sla)) .thenReturn(Arrays.asList(Duration.ofMillis(100), Duration.ofMillis(500))); + when(profile.isDefined(percentiles)).thenReturn(true); + when(profile.getDoubleList(percentiles)).thenReturn(Arrays.asList(0.75, 0.95, 0.99)); when(generator.nodeMetricId(node, metric)).thenReturn(METRIC_ID); SimpleMeterRegistry registry = spy(new SimpleMeterRegistry()); @@ -190,6 +193,63 @@ public void should_create_timer( assertThat(timer.count()).isEqualTo(10); HistogramSnapshot snapshot = timer.takeSnapshot(); assertThat(snapshot.histogramCounts()).hasSize(2); + assertThat(snapshot.percentileValues()).hasSize(3); + assertThat(snapshot.percentileValues()) + .satisfiesExactlyInAnyOrder( + valuePercentile -> assertThat(valuePercentile.percentile()).isEqualTo(0.75), + valuePercentile -> assertThat(valuePercentile.percentile()).isEqualTo(0.95), + valuePercentile -> assertThat(valuePercentile.percentile()).isEqualTo(0.99)); + } + + @Test + @UseDataProvider(value = "timerMetrics") + public void should_not_create_sla_percentiles( + NodeMetric metric, + DriverOption lowest, + DriverOption highest, + DriverOption digits, + DriverOption sla, + DriverOption percentiles) { + // given + Node node = mock(Node.class); + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + MetricIdGenerator generator = mock(MetricIdGenerator.class); + Set enabledMetrics = Collections.singleton(metric); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(context.getMetricIdGenerator()).thenReturn(generator); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(Duration.ofHours(1)); + when(profile.getDuration(lowest)).thenReturn(Duration.ofMillis(10)); + when(profile.getDuration(highest)).thenReturn(Duration.ofSeconds(1)); + when(profile.getInt(digits)).thenReturn(5); + when(profile.isDefined(sla)).thenReturn(false); + when(profile.getDurationList(sla)) + .thenReturn(Arrays.asList(Duration.ofMillis(100), Duration.ofMillis(500))); + when(profile.isDefined(percentiles)).thenReturn(false); + when(profile.getDoubleList(percentiles)).thenReturn(Arrays.asList(0.75, 0.95, 0.99)); + when(generator.nodeMetricId(node, metric)).thenReturn(METRIC_ID); + + SimpleMeterRegistry registry = spy(new SimpleMeterRegistry()); + MicrometerNodeMetricUpdater updater = + new MicrometerNodeMetricUpdater(node, context, enabledMetrics, registry); + + for (int i = 0; i < 10; i++) { + updater.updateTimer(metric, null, 100, TimeUnit.MILLISECONDS); + } + + // then + Timer timer = registry.find(METRIC_ID.getName()).timer(); + assertThat(timer).isNotNull(); + assertThat(timer.count()).isEqualTo(10); + HistogramSnapshot snapshot = timer.takeSnapshot(); + assertThat(snapshot.histogramCounts()).hasSize(0); + assertThat(snapshot.percentileValues()).hasSize(0); } @DataProvider @@ -201,6 +261,7 @@ public static Object[][] timerMetrics() { DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_HIGHEST, DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_DIGITS, DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_SLO, + DefaultDriverOption.METRICS_NODE_CQL_MESSAGES_PUBLISH_PERCENTILES, }, { DseNodeMetric.GRAPH_MESSAGES, @@ -208,6 +269,7 @@ public static Object[][] timerMetrics() { DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_HIGHEST, DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_DIGITS, DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_SLO, + DseDriverOption.METRICS_NODE_GRAPH_MESSAGES_PUBLISH_PERCENTILES, }, }; } diff --git a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java index 09b3e44bac4..1e2d210335f 100644 --- a/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java +++ b/metrics/micrometer/src/test/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerSessionMetricUpdaterTest.java @@ -59,7 +59,8 @@ public void should_create_timer( DriverOption lowest, DriverOption highest, DriverOption digits, - DriverOption sla) { + DriverOption sla, + DriverOption percentiles) { // given InternalDriverContext context = mock(InternalDriverContext.class); DriverExecutionProfile profile = mock(DriverExecutionProfile.class); @@ -80,6 +81,8 @@ public void should_create_timer( when(profile.isDefined(sla)).thenReturn(true); when(profile.getDurationList(sla)) .thenReturn(Arrays.asList(Duration.ofMillis(100), Duration.ofMillis(500))); + when(profile.isDefined(percentiles)).thenReturn(true); + when(profile.getDoubleList(percentiles)).thenReturn(Arrays.asList(0.75, 0.95, 0.99)); when(generator.sessionMetricId(metric)).thenReturn(METRIC_ID); SimpleMeterRegistry registry = spy(new SimpleMeterRegistry()); @@ -96,6 +99,61 @@ public void should_create_timer( assertThat(timer.count()).isEqualTo(10); HistogramSnapshot snapshot = timer.takeSnapshot(); assertThat(snapshot.histogramCounts()).hasSize(2); + assertThat(snapshot.percentileValues()).hasSize(3); + assertThat(snapshot.percentileValues()) + .satisfiesExactlyInAnyOrder( + valuePercentile -> assertThat(valuePercentile.percentile()).isEqualTo(0.75), + valuePercentile -> assertThat(valuePercentile.percentile()).isEqualTo(0.95), + valuePercentile -> assertThat(valuePercentile.percentile()).isEqualTo(0.99)); + } + + @Test + @UseDataProvider(value = "timerMetrics") + public void should_not_create_sla_percentiles( + SessionMetric metric, + DriverOption lowest, + DriverOption highest, + DriverOption digits, + DriverOption sla, + DriverOption percentiles) { + // given + InternalDriverContext context = mock(InternalDriverContext.class); + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + DriverConfig config = mock(DriverConfig.class); + MetricIdGenerator generator = mock(MetricIdGenerator.class); + Set enabledMetrics = Collections.singleton(metric); + + // when + when(context.getSessionName()).thenReturn("prefix"); + when(context.getConfig()).thenReturn(config); + when(config.getDefaultProfile()).thenReturn(profile); + when(context.getMetricIdGenerator()).thenReturn(generator); + when(profile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(Duration.ofHours(1)); + when(profile.isDefined(sla)).thenReturn(false); + when(profile.getDurationList(sla)) + .thenReturn(Arrays.asList(Duration.ofMillis(100), Duration.ofMillis(500))); + when(profile.getBoolean(DefaultDriverOption.METRICS_GENERATE_AGGREGABLE_HISTOGRAMS)) + .thenReturn(true); + when(profile.isDefined(percentiles)).thenReturn(false); + when(profile.getDoubleList(percentiles)).thenReturn(Arrays.asList(0.75, 0.95, 0.99)); + when(generator.sessionMetricId(metric)).thenReturn(METRIC_ID); + + SimpleMeterRegistry registry = new SimpleMeterRegistry(); + MicrometerSessionMetricUpdater updater = + new MicrometerSessionMetricUpdater(context, enabledMetrics, registry); + + for (int i = 0; i < 10; i++) { + updater.updateTimer(metric, null, 100, TimeUnit.MILLISECONDS); + } + + // then + Timer timer = registry.find(METRIC_ID.getName()).timer(); + assertThat(timer).isNotNull(); + assertThat(timer.count()).isEqualTo(10); + HistogramSnapshot snapshot = timer.takeSnapshot(); + assertThat(snapshot.histogramCounts()).hasSize(0); + assertThat(snapshot.percentileValues()).hasSize(0); } @DataProvider @@ -107,6 +165,7 @@ public static Object[][] timerMetrics() { DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_HIGHEST, DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_DIGITS, DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_SLO, + DefaultDriverOption.METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES, }, { DseSessionMetric.GRAPH_REQUESTS, @@ -114,6 +173,7 @@ public static Object[][] timerMetrics() { DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_HIGHEST, DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_DIGITS, DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_SLO, + DseDriverOption.METRICS_SESSION_GRAPH_REQUESTS_PUBLISH_PERCENTILES, }, { DseSessionMetric.CONTINUOUS_CQL_REQUESTS, @@ -121,6 +181,7 @@ public static Object[][] timerMetrics() { DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_HIGHEST, DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_DIGITS, DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_SLO, + DseDriverOption.CONTINUOUS_PAGING_METRICS_SESSION_CQL_REQUESTS_PUBLISH_PERCENTILES }, { DefaultSessionMetric.THROTTLING_DELAY, @@ -128,6 +189,7 @@ public static Object[][] timerMetrics() { DefaultDriverOption.METRICS_SESSION_THROTTLING_HIGHEST, DefaultDriverOption.METRICS_SESSION_THROTTLING_DIGITS, DefaultDriverOption.METRICS_SESSION_THROTTLING_SLO, + DefaultDriverOption.METRICS_SESSION_THROTTLING_PUBLISH_PERCENTILES }, }; } From 16260261d3df50fcf24fac1fc2d37896c4a111bf Mon Sep 17 00:00:00 2001 From: mck Date: Thu, 13 Jul 2023 15:45:41 +0200 Subject: [PATCH 283/395] Copyright to ASF (see https://incubator.apache.org/ip-clearance/cassandra-java-driver.html ) patch by Mick Semb Wever; reviewed by Henry Hughes for CASSANDRA-18611 --- NOTICE.txt | 20 ++++++++++++ README.md | 8 ++--- bom/pom.xml | 16 +++++----- core-shaded/pom.xml | 16 +++++----- core-shaded/src/assembly/shaded-jar.xml | 14 +++++---- core/pom.xml | 16 +++++----- .../driver/api/core/DseProtocolVersion.java | 14 +++++---- .../dse/driver/api/core/DseSession.java | 14 +++++---- .../driver/api/core/DseSessionBuilder.java | 14 +++++---- .../api/core/auth/BaseDseAuthenticator.java | 14 +++++---- .../core/auth/DseGssApiAuthProviderBase.java | 14 +++++---- .../auth/DsePlainTextAuthProviderBase.java | 14 +++++---- .../ProgrammaticDseGssApiAuthProvider.java | 16 +++++----- .../api/core/auth/ProxyAuthentication.java | 14 +++++---- .../core/config/DseDriverConfigLoader.java | 14 +++++---- .../api/core/config/DseDriverOption.java | 14 +++++---- .../continuous/ContinuousAsyncResultSet.java | 14 +++++---- .../cql/continuous/ContinuousResultSet.java | 14 +++++---- .../cql/continuous/ContinuousSession.java | 18 ++++++----- .../reactive/ContinuousReactiveResultSet.java | 14 +++++---- .../reactive/ContinuousReactiveSession.java | 14 +++++---- .../cql/reactive/ReactiveQueryMetadata.java | 14 +++++---- .../core/cql/reactive/ReactiveResultSet.java | 14 +++++---- .../api/core/cql/reactive/ReactiveRow.java | 14 +++++---- .../core/cql/reactive/ReactiveSession.java | 14 +++++---- .../api/core/cql/reactive/package-info.java | 14 +++++---- .../api/core/data/geometry/Geometry.java | 14 +++++---- .../api/core/data/geometry/LineString.java | 14 +++++---- .../driver/api/core/data/geometry/Point.java | 14 +++++---- .../api/core/data/geometry/Polygon.java | 14 +++++---- .../driver/api/core/data/time/DateRange.java | 14 +++++---- .../api/core/data/time/DateRangeBound.java | 14 +++++---- .../core/data/time/DateRangePrecision.java | 14 +++++---- .../api/core/graph/AsyncGraphResultSet.java | 14 +++++---- .../api/core/graph/BatchGraphStatement.java | 14 +++++---- .../graph/BatchGraphStatementBuilder.java | 14 +++++---- .../dse/driver/api/core/graph/DseGraph.java | 14 +++++---- .../DseGraphRemoteConnectionBuilder.java | 14 +++++---- .../api/core/graph/FluentGraphStatement.java | 14 +++++---- .../graph/FluentGraphStatementBuilder.java | 14 +++++---- .../api/core/graph/GraphExecutionInfo.java | 14 +++++---- .../dse/driver/api/core/graph/GraphNode.java | 14 +++++---- .../driver/api/core/graph/GraphResultSet.java | 14 +++++---- .../driver/api/core/graph/GraphSession.java | 14 +++++---- .../driver/api/core/graph/GraphStatement.java | 14 +++++---- .../core/graph/GraphStatementBuilderBase.java | 14 +++++---- .../api/core/graph/PagingEnabledOptions.java | 14 +++++---- .../api/core/graph/ScriptGraphStatement.java | 14 +++++---- .../graph/ScriptGraphStatementBuilder.java | 14 +++++---- .../core/graph/predicates/CqlCollection.java | 14 +++++---- .../driver/api/core/graph/predicates/Geo.java | 14 +++++---- .../api/core/graph/predicates/Search.java | 14 +++++---- .../graph/reactive/ReactiveGraphNode.java | 14 +++++---- .../reactive/ReactiveGraphResultSet.java | 14 +++++---- .../graph/reactive/ReactiveGraphSession.java | 14 +++++---- .../api/core/metadata/DseNodeProperties.java | 14 +++++---- .../metadata/schema/DseAggregateMetadata.java | 14 +++++---- .../metadata/schema/DseColumnMetadata.java | 14 +++++---- .../core/metadata/schema/DseEdgeMetadata.java | 14 +++++---- .../metadata/schema/DseFunctionMetadata.java | 14 +++++---- .../schema/DseGraphKeyspaceMetadata.java | 14 +++++---- .../schema/DseGraphTableMetadata.java | 14 +++++---- .../metadata/schema/DseIndexMetadata.java | 14 +++++---- .../metadata/schema/DseKeyspaceMetadata.java | 14 +++++---- .../metadata/schema/DseRelationMetadata.java | 14 +++++---- .../metadata/schema/DseTableMetadata.java | 14 +++++---- .../metadata/schema/DseVertexMetadata.java | 14 +++++---- .../core/metadata/schema/DseViewMetadata.java | 14 +++++---- .../api/core/metrics/DseNodeMetric.java | 14 +++++---- .../api/core/metrics/DseSessionMetric.java | 14 +++++---- .../servererrors/UnfitClientException.java | 14 +++++---- .../driver/api/core/type/DseDataTypes.java | 14 +++++---- .../api/core/type/codec/DseTypeCodecs.java | 14 +++++---- .../internal/core/DseProtocolFeature.java | 14 +++++---- .../core/InsightsClientLifecycleListener.java | 14 +++++---- .../driver/internal/core/auth/AuthUtils.java | 14 +++++---- .../core/auth/DseGssApiAuthProvider.java | 16 +++++----- .../core/auth/DsePlainTextAuthProvider.java | 14 +++++---- .../internal/core/cql/DseConversions.java | 14 +++++---- .../ContinuousCqlRequestAsyncProcessor.java | 14 +++++---- .../ContinuousCqlRequestHandler.java | 14 +++++---- .../ContinuousCqlRequestSyncProcessor.java | 14 +++++---- .../ContinuousRequestHandlerBase.java | 14 +++++---- .../DefaultContinuousAsyncResultSet.java | 14 +++++---- .../DefaultContinuousResultSet.java | 14 +++++---- ...ContinuousCqlRequestReactiveProcessor.java | 14 +++++---- .../DefaultContinuousReactiveResultSet.java | 14 +++++---- .../reactive/CqlRequestReactiveProcessor.java | 14 +++++---- .../reactive/DefaultReactiveResultSet.java | 14 +++++---- .../core/cql/reactive/DefaultReactiveRow.java | 14 +++++---- .../core/cql/reactive/EmptySubscription.java | 14 +++++---- .../core/cql/reactive/FailedPublisher.java | 14 +++++---- .../cql/reactive/FailedReactiveResultSet.java | 14 +++++---- .../core/cql/reactive/ReactiveOperators.java | 14 +++++---- .../cql/reactive/ReactiveResultSetBase.java | 14 +++++---- .../ReactiveResultSetSubscription.java | 14 +++++---- .../cql/reactive/SimpleUnicastProcessor.java | 14 +++++---- .../core/data/geometry/DefaultGeometry.java | 14 +++++---- .../core/data/geometry/DefaultLineString.java | 14 +++++---- .../core/data/geometry/DefaultPoint.java | 14 +++++---- .../core/data/geometry/DefaultPolygon.java | 14 +++++---- .../internal/core/data/geometry/Distance.java | 14 +++++---- .../geometry/DistanceSerializationProxy.java | 14 +++++---- .../data/geometry/WkbSerializationProxy.java | 14 +++++---- .../internal/core/data/geometry/WkbUtil.java | 14 +++++---- .../internal/core/graph/ByteBufUtil.java | 14 +++++---- .../core/graph/BytecodeGraphStatement.java | 14 +++++---- .../graph/ContinuousAsyncGraphResultSet.java | 14 +++++---- .../graph/ContinuousGraphRequestHandler.java | 14 +++++---- .../core/graph/CqlCollectionPredicate.java | 14 +++++---- .../graph/DefaultAsyncGraphResultSet.java | 14 +++++---- .../graph/DefaultBatchGraphStatement.java | 14 +++++---- .../DefaultDseRemoteConnectionBuilder.java | 14 +++++---- .../graph/DefaultFluentGraphStatement.java | 14 +++++---- .../graph/DefaultScriptGraphStatement.java | 14 +++++---- .../core/graph/DseGraphRemoteConnection.java | 14 +++++---- .../core/graph/DseGraphTraversal.java | 14 +++++---- .../internal/core/graph/DsePredicate.java | 14 +++++---- .../internal/core/graph/EditDistance.java | 14 +++++---- .../internal/core/graph/GeoPredicate.java | 14 +++++---- .../driver/internal/core/graph/GeoUtils.java | 14 +++++---- .../internal/core/graph/GraphConversions.java | 14 +++++---- .../graph/GraphExecutionInfoConverter.java | 14 +++++---- .../internal/core/graph/GraphProtocol.java | 14 +++++---- .../graph/GraphRequestAsyncProcessor.java | 14 +++++---- .../core/graph/GraphRequestHandler.java | 14 +++++---- .../core/graph/GraphRequestSyncProcessor.java | 14 +++++---- .../core/graph/GraphResultIterator.java | 14 +++++---- .../internal/core/graph/GraphResultSets.java | 14 +++++---- .../internal/core/graph/GraphSON1SerdeTP.java | 14 +++++---- .../internal/core/graph/GraphSON2SerdeTP.java | 14 +++++---- .../internal/core/graph/GraphSONUtils.java | 14 +++++---- .../core/graph/GraphStatementBase.java | 14 +++++---- .../core/graph/GraphSupportChecker.java | 14 +++++---- .../internal/core/graph/LegacyGraphNode.java | 14 +++++---- .../core/graph/MultiPageGraphResultSet.java | 14 +++++---- .../internal/core/graph/ObjectGraphNode.java | 14 +++++---- .../internal/core/graph/SearchPredicate.java | 14 +++++---- .../internal/core/graph/SearchUtils.java | 14 +++++---- .../core/graph/SinglePageGraphResultSet.java | 14 +++++---- .../core/graph/TinkerpopBufferUtil.java | 14 +++++---- ...actDynamicGraphBinaryCustomSerializer.java | 14 +++++---- ...ractSimpleGraphBinaryCustomSerializer.java | 14 +++++---- .../binary/ComplexTypeSerializerUtil.java | 14 +++++---- .../graph/binary/CqlDurationSerializer.java | 14 +++++---- .../core/graph/binary/DistanceSerializer.java | 14 +++++---- .../graph/binary/EditDistanceSerializer.java | 14 +++++---- .../core/graph/binary/GeometrySerializer.java | 14 +++++---- .../core/graph/binary/GraphBinaryModule.java | 14 +++++---- .../core/graph/binary/GraphBinaryUtils.java | 14 +++++---- .../graph/binary/LineStringSerializer.java | 14 +++++---- .../core/graph/binary/PairSerializer.java | 14 +++++---- .../core/graph/binary/PointSerializer.java | 14 +++++---- .../core/graph/binary/PolygonSerializer.java | 14 +++++---- .../graph/binary/TupleValueSerializer.java | 14 +++++---- .../core/graph/binary/UdtValueSerializer.java | 14 +++++---- .../graph/binary/buffer/DseNettyBuffer.java | 14 +++++---- .../binary/buffer/DseNettyBufferFactory.java | 14 +++++---- .../reactive/DefaultReactiveGraphNode.java | 14 +++++---- .../DefaultReactiveGraphResultSet.java | 14 +++++---- .../FailedReactiveGraphResultSet.java | 14 +++++---- .../ReactiveGraphRequestProcessor.java | 14 +++++---- .../ReactiveGraphResultSetSubscription.java | 14 +++++---- .../core/insights/AddressFormatter.java | 14 +++++---- .../insights/ConfigAntiPatternsFinder.java | 14 +++++---- .../core/insights/DataCentersFinder.java | 14 +++++---- .../insights/ExecutionProfilesInfoFinder.java | 14 +++++---- .../core/insights/InsightsClient.java | 14 +++++---- .../insights/InsightsSupportVerifier.java | 14 +++++---- .../internal/core/insights/PackageUtil.java | 14 +++++---- .../core/insights/PlatformInfoFinder.java | 14 +++++---- .../ReconnectionPolicyInfoFinder.java | 14 +++++---- .../configuration/InsightsConfiguration.java | 14 +++++---- .../InsightEventFormatException.java | 14 +++++---- .../insights/schema/AuthProviderType.java | 14 +++++---- .../core/insights/schema/Insight.java | 14 +++++---- .../core/insights/schema/InsightMetadata.java | 14 +++++---- .../core/insights/schema/InsightType.java | 14 +++++---- .../insights/schema/InsightsPlatformInfo.java | 14 +++++---- .../insights/schema/InsightsStartupData.java | 14 +++++---- .../insights/schema/InsightsStatusData.java | 14 +++++---- .../insights/schema/LoadBalancingInfo.java | 14 +++++---- .../schema/PoolSizeByHostDistance.java | 14 +++++---- .../schema/ReconnectionPolicyInfo.java | 14 +++++---- .../internal/core/insights/schema/SSL.java | 14 +++++---- .../insights/schema/SessionStateForNode.java | 14 +++++---- .../schema/SpecificExecutionProfile.java | 14 +++++---- .../schema/SpeculativeExecutionInfo.java | 14 +++++---- .../DseDcInferringLoadBalancingPolicy.java | 14 +++++---- .../loadbalancing/DseLoadBalancingPolicy.java | 14 +++++---- .../schema/DefaultDseAggregateMetadata.java | 14 +++++---- .../schema/DefaultDseColumnMetadata.java | 14 +++++---- .../schema/DefaultDseEdgeMetadata.java | 14 +++++---- .../schema/DefaultDseFunctionMetadata.java | 14 +++++---- .../schema/DefaultDseIndexMetadata.java | 14 +++++---- .../schema/DefaultDseKeyspaceMetadata.java | 14 +++++---- .../schema/DefaultDseTableMetadata.java | 14 +++++---- .../schema/DefaultDseVertexMetadata.java | 14 +++++---- .../schema/DefaultDseViewMetadata.java | 14 +++++---- .../core/metadata/schema/ScriptHelper.java | 14 +++++---- .../schema/parsing/DseAggregateParser.java | 14 +++++---- .../schema/parsing/DseFunctionParser.java | 14 +++++---- .../schema/parsing/DseSchemaParser.java | 14 +++++---- .../schema/parsing/DseTableParser.java | 14 +++++---- .../schema/parsing/DseViewParser.java | 14 +++++---- .../TinkerpopBufferPrimitiveCodec.java | 14 +++++---- .../internal/core/search/DateRangeUtil.java | 14 +++++---- .../core/session/DefaultDseSession.java | 14 +++++---- .../type/codec/DseTypeCodecsRegistrar.java | 14 +++++---- .../DseTypeCodecsRegistrarSubstitutions.java | 14 +++++---- .../type/codec/geometry/GeometryCodec.java | 14 +++++---- .../type/codec/geometry/LineStringCodec.java | 14 +++++---- .../core/type/codec/geometry/PointCodec.java | 14 +++++---- .../type/codec/geometry/PolygonCodec.java | 14 +++++---- .../core/type/codec/time/DateRangeCodec.java | 14 +++++---- .../concurrent/BoundedConcurrentQueue.java | 14 +++++---- .../api/core/AllNodesFailedException.java | 14 +++++---- .../driver/api/core/AsyncAutoCloseable.java | 14 +++++---- .../driver/api/core/AsyncPagingIterable.java | 14 +++++---- .../oss/driver/api/core/ConsistencyLevel.java | 14 +++++---- .../oss/driver/api/core/CqlIdentifier.java | 14 +++++---- .../oss/driver/api/core/CqlSession.java | 14 +++++---- .../driver/api/core/CqlSessionBuilder.java | 14 +++++---- .../api/core/DefaultConsistencyLevel.java | 14 +++++---- .../api/core/DefaultProtocolVersion.java | 14 +++++---- .../oss/driver/api/core/DriverException.java | 14 +++++---- .../api/core/DriverExecutionException.java | 14 +++++---- .../api/core/DriverTimeoutException.java | 14 +++++---- .../api/core/InvalidKeyspaceException.java | 14 +++++---- .../api/core/MappedAsyncPagingIterable.java | 14 +++++---- .../oss/driver/api/core/MavenCoordinates.java | 14 +++++---- .../api/core/NoNodeAvailableException.java | 14 +++++---- .../api/core/NodeUnavailableException.java | 14 +++++---- .../oss/driver/api/core/PagingIterable.java | 14 +++++---- .../oss/driver/api/core/ProtocolVersion.java | 14 +++++---- .../api/core/RequestThrottlingException.java | 14 +++++---- .../UnsupportedProtocolVersionException.java | 14 +++++---- .../datastax/oss/driver/api/core/Version.java | 14 +++++---- .../addresstranslation/AddressTranslator.java | 14 +++++---- .../driver/api/core/auth/AuthProvider.java | 14 +++++---- .../core/auth/AuthenticationException.java | 14 +++++---- .../driver/api/core/auth/Authenticator.java | 14 +++++---- .../core/auth/PlainTextAuthProviderBase.java | 14 +++++---- .../ProgrammaticPlainTextAuthProvider.java | 14 +++++---- .../api/core/auth/SyncAuthenticator.java | 14 +++++---- .../driver/api/core/auth/package-info.java | 14 +++++---- .../api/core/config/DefaultDriverOption.java | 14 +++++---- .../driver/api/core/config/DriverConfig.java | 14 +++++---- .../api/core/config/DriverConfigLoader.java | 14 +++++---- .../core/config/DriverExecutionProfile.java | 14 +++++---- .../driver/api/core/config/DriverOption.java | 14 +++++---- .../api/core/config/OngoingConfigOptions.java | 14 +++++---- .../driver/api/core/config/OptionsMap.java | 14 +++++---- ...ProgrammaticDriverConfigLoaderBuilder.java | 14 +++++---- .../api/core/config/TypedDriverOption.java | 14 +++++---- .../driver/api/core/config/package-info.java | 14 +++++---- .../connection/BusyConnectionException.java | 14 +++++---- .../connection/ClosedConnectionException.java | 14 +++++---- .../connection/ConnectionInitException.java | 14 +++++---- .../core/connection/CrcMismatchException.java | 14 +++++---- .../connection/FrameTooLongException.java | 14 +++++---- .../core/connection/HeartbeatException.java | 14 +++++---- .../core/connection/ReconnectionPolicy.java | 14 +++++---- .../api/core/connection/package-info.java | 14 +++++---- .../api/core/context/DriverContext.java | 14 +++++---- .../driver/api/core/cql/AsyncCqlSession.java | 14 +++++---- .../driver/api/core/cql/AsyncResultSet.java | 14 +++++---- .../driver/api/core/cql/BatchStatement.java | 14 +++++---- .../api/core/cql/BatchStatementBuilder.java | 14 +++++---- .../oss/driver/api/core/cql/BatchType.java | 14 +++++---- .../api/core/cql/BatchableStatement.java | 14 +++++---- .../oss/driver/api/core/cql/Bindable.java | 14 +++++---- .../driver/api/core/cql/BoundStatement.java | 14 +++++---- .../api/core/cql/BoundStatementBuilder.java | 14 +++++---- .../driver/api/core/cql/ColumnDefinition.java | 14 +++++---- .../api/core/cql/ColumnDefinitions.java | 14 +++++---- .../driver/api/core/cql/DefaultBatchType.java | 14 +++++---- .../driver/api/core/cql/ExecutionInfo.java | 14 +++++---- .../oss/driver/api/core/cql/PagingState.java | 14 +++++---- .../driver/api/core/cql/PrepareRequest.java | 14 +++++---- .../api/core/cql/PreparedStatement.java | 14 +++++---- .../oss/driver/api/core/cql/QueryTrace.java | 14 +++++---- .../oss/driver/api/core/cql/ResultSet.java | 14 +++++---- .../datastax/oss/driver/api/core/cql/Row.java | 14 +++++---- .../driver/api/core/cql/SimpleStatement.java | 14 +++++---- .../api/core/cql/SimpleStatementBuilder.java | 14 +++++---- .../oss/driver/api/core/cql/Statement.java | 14 +++++---- .../driver/api/core/cql/StatementBuilder.java | 14 +++++---- .../driver/api/core/cql/SyncCqlSession.java | 14 +++++---- .../oss/driver/api/core/cql/TraceEvent.java | 14 +++++---- .../driver/api/core/data/AccessibleById.java | 14 +++++---- .../api/core/data/AccessibleByIndex.java | 14 +++++---- .../api/core/data/AccessibleByName.java | 14 +++++---- .../oss/driver/api/core/data/ByteUtils.java | 14 +++++---- .../oss/driver/api/core/data/CqlDuration.java | 14 +++++---- .../oss/driver/api/core/data/CqlVector.java | 14 +++++---- .../oss/driver/api/core/data/Data.java | 14 +++++---- .../driver/api/core/data/GettableById.java | 14 +++++---- .../driver/api/core/data/GettableByIndex.java | 14 +++++---- .../driver/api/core/data/GettableByName.java | 14 +++++---- .../driver/api/core/data/SettableById.java | 14 +++++---- .../driver/api/core/data/SettableByIndex.java | 14 +++++---- .../driver/api/core/data/SettableByName.java | 14 +++++---- .../oss/driver/api/core/data/TupleValue.java | 14 +++++---- .../oss/driver/api/core/data/UdtValue.java | 14 +++++---- .../api/core/detach/AttachmentPoint.java | 14 +++++---- .../driver/api/core/detach/Detachable.java | 16 +++++----- .../loadbalancing/LoadBalancingPolicy.java | 14 +++++---- .../api/core/loadbalancing/NodeDistance.java | 14 +++++---- .../loadbalancing/NodeDistanceEvaluator.java | 14 +++++---- .../driver/api/core/metadata/EndPoint.java | 14 +++++---- .../driver/api/core/metadata/Metadata.java | 14 +++++---- .../oss/driver/api/core/metadata/Node.java | 14 +++++---- .../driver/api/core/metadata/NodeState.java | 14 +++++---- .../api/core/metadata/NodeStateListener.java | 14 +++++---- .../core/metadata/NodeStateListenerBase.java | 14 +++++---- .../metadata/SafeInitNodeStateListener.java | 14 +++++---- .../driver/api/core/metadata/TokenMap.java | 14 +++++---- .../metadata/schema/AggregateMetadata.java | 14 +++++---- .../core/metadata/schema/ClusteringOrder.java | 14 +++++---- .../core/metadata/schema/ColumnMetadata.java | 14 +++++---- .../api/core/metadata/schema/Describable.java | 14 +++++---- .../metadata/schema/FunctionMetadata.java | 14 +++++---- .../metadata/schema/FunctionSignature.java | 14 +++++---- .../api/core/metadata/schema/IndexKind.java | 14 +++++---- .../core/metadata/schema/IndexMetadata.java | 14 +++++---- .../metadata/schema/KeyspaceMetadata.java | 14 +++++---- .../metadata/schema/RelationMetadata.java | 14 +++++---- .../metadata/schema/SchemaChangeListener.java | 14 +++++---- .../schema/SchemaChangeListenerBase.java | 14 +++++---- .../core/metadata/schema/TableMetadata.java | 14 +++++---- .../core/metadata/schema/ViewMetadata.java | 14 +++++---- .../driver/api/core/metadata/token/Token.java | 14 +++++---- .../api/core/metadata/token/TokenRange.java | 14 +++++---- .../api/core/metrics/DefaultNodeMetric.java | 14 +++++---- .../core/metrics/DefaultSessionMetric.java | 14 +++++---- .../oss/driver/api/core/metrics/Metrics.java | 14 +++++---- .../driver/api/core/metrics/NodeMetric.java | 14 +++++---- .../api/core/metrics/SessionMetric.java | 14 +++++---- .../oss/driver/api/core/package-info.java | 14 +++++---- .../driver/api/core/paging/OffsetPager.java | 14 +++++---- .../driver/api/core/retry/RetryDecision.java | 14 +++++---- .../driver/api/core/retry/RetryPolicy.java | 14 +++++---- .../driver/api/core/retry/RetryVerdict.java | 14 +++++---- .../servererrors/AlreadyExistsException.java | 14 +++++---- .../servererrors/BootstrappingException.java | 14 +++++---- .../CASWriteUnknownException.java | 14 +++++---- .../CDCWriteFailureException.java | 14 +++++---- .../servererrors/CoordinatorException.java | 14 +++++---- .../core/servererrors/DefaultWriteType.java | 14 +++++---- .../FunctionFailureException.java | 14 +++++---- .../InvalidConfigurationInQueryException.java | 14 +++++---- .../servererrors/InvalidQueryException.java | 14 +++++---- .../servererrors/OverloadedException.java | 14 +++++---- .../api/core/servererrors/ProtocolError.java | 14 +++++---- .../QueryConsistencyException.java | 14 +++++---- .../servererrors/QueryExecutionException.java | 14 +++++---- .../QueryValidationException.java | 14 +++++---- .../servererrors/ReadFailureException.java | 14 +++++---- .../servererrors/ReadTimeoutException.java | 14 +++++---- .../api/core/servererrors/ServerError.java | 14 +++++---- .../api/core/servererrors/SyntaxError.java | 14 +++++---- .../core/servererrors/TruncateException.java | 14 +++++---- .../servererrors/UnauthorizedException.java | 14 +++++---- .../servererrors/UnavailableException.java | 14 +++++---- .../servererrors/WriteFailureException.java | 14 +++++---- .../servererrors/WriteTimeoutException.java | 14 +++++---- .../api/core/servererrors/WriteType.java | 14 +++++---- .../core/session/ProgrammaticArguments.java | 14 +++++---- .../oss/driver/api/core/session/Request.java | 14 +++++---- .../oss/driver/api/core/session/Session.java | 14 +++++---- .../api/core/session/SessionBuilder.java | 14 +++++---- .../session/throttling/RequestThrottler.java | 14 +++++---- .../core/session/throttling/Throttled.java | 14 +++++---- .../specex/SpeculativeExecutionPolicy.java | 14 +++++---- .../ssl/ProgrammaticSslEngineFactory.java | 14 +++++---- .../driver/api/core/ssl/SslEngineFactory.java | 14 +++++---- .../oss/driver/api/core/ssl/package-info.java | 14 +++++---- .../api/core/time/TimestampGenerator.java | 14 +++++---- .../api/core/tracker/RequestTracker.java | 14 +++++---- .../driver/api/core/type/ContainerType.java | 14 +++++---- .../oss/driver/api/core/type/CustomType.java | 14 +++++---- .../oss/driver/api/core/type/DataType.java | 14 +++++---- .../oss/driver/api/core/type/DataTypes.java | 14 +++++---- .../oss/driver/api/core/type/ListType.java | 14 +++++---- .../oss/driver/api/core/type/MapType.java | 14 +++++---- .../oss/driver/api/core/type/SetType.java | 14 +++++---- .../oss/driver/api/core/type/TupleType.java | 14 +++++---- .../driver/api/core/type/UserDefinedType.java | 14 +++++---- .../oss/driver/api/core/type/VectorType.java | 14 +++++---- .../type/codec/CodecNotFoundException.java | 14 +++++---- .../api/core/type/codec/ExtraTypeCodecs.java | 14 +++++---- .../api/core/type/codec/MappingCodec.java | 14 +++++---- .../type/codec/PrimitiveBooleanCodec.java | 14 +++++---- .../core/type/codec/PrimitiveByteCodec.java | 14 +++++---- .../core/type/codec/PrimitiveDoubleCodec.java | 14 +++++---- .../core/type/codec/PrimitiveFloatCodec.java | 14 +++++---- .../core/type/codec/PrimitiveIntCodec.java | 14 +++++---- .../core/type/codec/PrimitiveLongCodec.java | 14 +++++---- .../core/type/codec/PrimitiveShortCodec.java | 14 +++++---- .../driver/api/core/type/codec/TypeCodec.java | 14 +++++---- .../api/core/type/codec/TypeCodecs.java | 14 +++++---- .../type/codec/registry/CodecRegistry.java | 14 +++++---- .../codec/registry/MutableCodecRegistry.java | 14 +++++---- .../api/core/type/reflect/GenericType.java | 14 +++++---- .../type/reflect/GenericTypeParameter.java | 14 +++++---- .../oss/driver/api/core/uuid/Uuids.java | 14 +++++---- .../datastax/oss/driver/api/package-info.java | 14 +++++---- .../core/AsyncPagingIterableWrapper.java | 14 +++++---- .../core/ConsistencyLevelRegistry.java | 14 +++++---- .../driver/internal/core/ContactPoints.java | 14 +++++---- .../driver/internal/core/CqlIdentifiers.java | 14 +++++---- .../core/DefaultConsistencyLevelRegistry.java | 14 +++++---- .../core/DefaultMavenCoordinates.java | 14 +++++---- .../internal/core/DefaultProtocolFeature.java | 14 +++++---- .../core/DefaultProtocolVersionRegistry.java | 14 +++++---- .../internal/core/PagingIterableWrapper.java | 14 +++++---- .../driver/internal/core/ProtocolFeature.java | 14 +++++---- .../core/ProtocolVersionRegistry.java | 14 +++++---- .../Ec2MultiRegionAddressTranslator.java | 14 +++++---- .../FixedHostNameAddressTranslator.java | 14 +++++---- .../PassThroughAddressTranslator.java | 14 +++++---- .../adminrequest/AdminRequestHandler.java | 14 +++++---- .../core/adminrequest/AdminResult.java | 14 +++++---- .../internal/core/adminrequest/AdminRow.java | 14 +++++---- .../ThrottledAdminRequestHandler.java | 14 +++++---- .../UnexpectedResponseException.java | 14 +++++---- .../core/adminrequest/package-info.java | 14 +++++---- .../core/auth/PlainTextAuthProvider.java | 14 +++++---- .../internal/core/channel/ChannelEvent.java | 14 +++++---- .../internal/core/channel/ChannelFactory.java | 14 +++++---- .../core/channel/ChannelHandlerRequest.java | 14 +++++---- .../channel/ClusterNameMismatchException.java | 14 +++++---- .../core/channel/ConnectInitHandler.java | 14 +++++---- .../core/channel/DefaultWriteCoalescer.java | 14 +++++---- .../internal/core/channel/DriverChannel.java | 14 +++++---- .../core/channel/DriverChannelOptions.java | 14 +++++---- .../internal/core/channel/EventCallback.java | 14 +++++---- .../core/channel/HeartbeatHandler.java | 14 +++++---- .../core/channel/InFlightHandler.java | 14 +++++---- .../core/channel/InboundTrafficMeter.java | 14 +++++---- .../core/channel/OutboundTrafficMeter.java | 14 +++++---- .../channel/PassThroughWriteCoalescer.java | 14 +++++---- .../core/channel/ProtocolInitHandler.java | 14 +++++---- .../core/channel/ResponseCallback.java | 14 +++++---- .../core/channel/StreamIdGenerator.java | 14 +++++---- .../internal/core/channel/WriteCoalescer.java | 14 +++++---- .../internal/core/channel/package-info.java | 14 +++++---- .../core/config/ConfigChangeEvent.java | 14 +++++---- .../core/config/DerivedExecutionProfile.java | 14 +++++---- .../config/DriverOptionConfigBuilder.java | 14 +++++---- .../core/config/cloud/CloudConfig.java | 14 +++++---- .../core/config/cloud/CloudConfigFactory.java | 14 +++++---- .../composite/CompositeDriverConfig.java | 14 +++++---- .../CompositeDriverConfigLoader.java | 14 +++++---- .../CompositeDriverExecutionProfile.java | 14 +++++---- .../core/config/map/MapBasedDriverConfig.java | 14 +++++---- .../map/MapBasedDriverConfigLoader.java | 14 +++++---- .../map/MapBasedDriverExecutionProfile.java | 14 +++++---- .../typesafe/DefaultDriverConfigLoader.java | 14 +++++---- .../DefaultDriverConfigLoaderBuilder.java | 14 +++++---- ...ProgrammaticDriverConfigLoaderBuilder.java | 14 +++++---- .../config/typesafe/TypesafeDriverConfig.java | 14 +++++---- .../TypesafeDriverExecutionProfile.java | 14 +++++---- .../core/config/typesafe/package-info.java | 14 +++++---- .../ConstantReconnectionPolicy.java | 14 +++++---- .../ExponentialReconnectionPolicy.java | 14 +++++---- .../core/context/DefaultDriverContext.java | 14 +++++---- .../core/context/DefaultNettyOptions.java | 14 +++++---- .../internal/core/context/EventBus.java | 14 +++++---- .../core/context/InternalDriverContext.java | 14 +++++---- .../core/context/LifecycleListener.java | 14 +++++---- .../internal/core/context/NettyOptions.java | 14 +++++---- .../core/context/StartupOptionsBuilder.java | 14 +++++---- .../core/control/ControlConnection.java | 14 +++++---- .../driver/internal/core/cql/Conversions.java | 14 +++++---- .../core/cql/CqlPrepareAsyncProcessor.java | 14 +++++---- .../internal/core/cql/CqlPrepareHandler.java | 14 +++++---- .../core/cql/CqlPrepareSyncProcessor.java | 14 +++++---- .../core/cql/CqlRequestAsyncProcessor.java | 14 +++++---- .../internal/core/cql/CqlRequestHandler.java | 14 +++++---- .../core/cql/CqlRequestSyncProcessor.java | 14 +++++---- .../core/cql/DefaultAsyncResultSet.java | 14 +++++---- .../core/cql/DefaultBatchStatement.java | 14 +++++---- .../core/cql/DefaultBoundStatement.java | 14 +++++---- .../core/cql/DefaultColumnDefinition.java | 14 +++++---- .../core/cql/DefaultColumnDefinitions.java | 14 +++++---- .../core/cql/DefaultExecutionInfo.java | 14 +++++---- .../internal/core/cql/DefaultPagingState.java | 14 +++++---- .../core/cql/DefaultPrepareRequest.java | 14 +++++---- .../core/cql/DefaultPreparedStatement.java | 14 +++++---- .../internal/core/cql/DefaultQueryTrace.java | 14 +++++---- .../driver/internal/core/cql/DefaultRow.java | 14 +++++---- .../core/cql/DefaultSimpleStatement.java | 14 +++++---- .../internal/core/cql/DefaultTraceEvent.java | 14 +++++---- .../core/cql/EmptyColumnDefinitions.java | 14 +++++---- .../internal/core/cql/MultiPageResultSet.java | 14 +++++---- .../core/cql/PagingIterableSpliterator.java | 14 +++++---- .../internal/core/cql/QueryTraceFetcher.java | 14 +++++---- .../driver/internal/core/cql/ResultSets.java | 14 +++++---- .../core/cql/SinglePageResultSet.java | 14 +++++---- .../internal/core/data/DefaultTupleValue.java | 14 +++++---- .../internal/core/data/DefaultUdtValue.java | 14 +++++---- .../internal/core/data/IdentifierIndex.java | 14 +++++---- .../internal/core/data/ValuesHelper.java | 14 +++++---- .../BasicLoadBalancingPolicy.java | 14 +++++---- .../DcInferringLoadBalancingPolicy.java | 14 +++++---- .../DefaultLoadBalancingPolicy.java | 14 +++++---- .../DefaultNodeDistanceEvaluatorHelper.java | 14 +++++---- .../helper/InferringLocalDcHelper.java | 14 +++++---- .../loadbalancing/helper/LocalDcHelper.java | 14 +++++---- .../helper/MandatoryLocalDcHelper.java | 14 +++++---- .../helper/NodeDistanceEvaluatorHelper.java | 14 +++++---- .../NodeFilterToDistanceEvaluatorAdapter.java | 14 +++++---- .../helper/OptionalLocalDcHelper.java | 14 +++++---- .../nodeset/DcAgnosticNodeSet.java | 14 +++++---- .../loadbalancing/nodeset/MultiDcNodeSet.java | 14 +++++---- .../core/loadbalancing/nodeset/NodeSet.java | 14 +++++---- .../nodeset/SingleDcNodeSet.java | 14 +++++---- .../core/metadata/AddNodeRefresh.java | 14 +++++---- .../core/metadata/CloudTopologyMonitor.java | 14 +++++---- .../core/metadata/DefaultEndPoint.java | 14 +++++---- .../core/metadata/DefaultMetadata.java | 14 +++++---- .../internal/core/metadata/DefaultNode.java | 14 +++++---- .../core/metadata/DefaultNodeInfo.java | 14 +++++---- .../core/metadata/DefaultTopologyMonitor.java | 14 +++++---- .../internal/core/metadata/DistanceEvent.java | 14 +++++---- .../core/metadata/FullNodeListRefresh.java | 14 +++++---- .../core/metadata/InitialNodeListRefresh.java | 14 +++++---- .../metadata/LoadBalancingPolicyWrapper.java | 14 +++++---- .../core/metadata/MetadataManager.java | 14 +++++---- .../core/metadata/MetadataRefresh.java | 14 +++++---- .../MultiplexingNodeStateListener.java | 14 +++++---- .../internal/core/metadata/NodeInfo.java | 14 +++++---- .../core/metadata/NodeStateEvent.java | 14 +++++---- .../core/metadata/NodeStateManager.java | 14 +++++---- .../internal/core/metadata/NodesRefresh.java | 14 +++++---- .../core/metadata/NoopNodeStateListener.java | 14 +++++---- .../core/metadata/PeerRowValidator.java | 14 +++++---- .../core/metadata/RemoveNodeRefresh.java | 14 +++++---- .../core/metadata/SchemaAgreementChecker.java | 14 +++++---- .../internal/core/metadata/SniEndPoint.java | 14 +++++---- .../core/metadata/TokensChangedRefresh.java | 14 +++++---- .../internal/core/metadata/TopologyEvent.java | 14 +++++---- .../core/metadata/TopologyMonitor.java | 14 +++++---- .../schema/DefaultAggregateMetadata.java | 14 +++++---- .../schema/DefaultColumnMetadata.java | 14 +++++---- .../schema/DefaultFunctionMetadata.java | 14 +++++---- .../metadata/schema/DefaultIndexMetadata.java | 14 +++++---- .../schema/DefaultKeyspaceMetadata.java | 14 +++++---- .../metadata/schema/DefaultTableMetadata.java | 14 +++++---- .../metadata/schema/DefaultViewMetadata.java | 14 +++++---- .../MultiplexingSchemaChangeListener.java | 14 +++++---- .../schema/NoopSchemaChangeListener.java | 14 +++++---- .../metadata/schema/SchemaChangeType.java | 14 +++++---- .../core/metadata/schema/ScriptBuilder.java | 14 +++++---- .../schema/ShallowUserDefinedType.java | 14 +++++---- .../schema/events/AggregateChangeEvent.java | 14 +++++---- .../schema/events/FunctionChangeEvent.java | 14 +++++---- .../schema/events/KeyspaceChangeEvent.java | 14 +++++---- .../schema/events/TableChangeEvent.java | 14 +++++---- .../schema/events/TypeChangeEvent.java | 14 +++++---- .../schema/events/ViewChangeEvent.java | 14 +++++---- .../schema/parsing/AggregateParser.java | 14 +++++---- .../schema/parsing/CassandraSchemaParser.java | 14 +++++---- .../DataTypeClassNameCompositeParser.java | 14 +++++---- .../parsing/DataTypeClassNameParser.java | 14 +++++---- .../schema/parsing/DataTypeCqlNameParser.java | 14 +++++---- .../schema/parsing/DataTypeParser.java | 14 +++++---- .../parsing/DefaultSchemaParserFactory.java | 14 +++++---- .../schema/parsing/FunctionParser.java | 14 +++++---- .../metadata/schema/parsing/RawColumn.java | 14 +++++---- .../schema/parsing/RelationParser.java | 14 +++++---- .../metadata/schema/parsing/SchemaParser.java | 14 +++++---- .../schema/parsing/SchemaParserFactory.java | 14 +++++---- .../schema/parsing/SimpleJsonParser.java | 14 +++++---- .../metadata/schema/parsing/TableParser.java | 14 +++++---- .../schema/parsing/UserDefinedTypeParser.java | 14 +++++---- .../metadata/schema/parsing/ViewParser.java | 14 +++++---- .../queries/Cassandra21SchemaQueries.java | 14 +++++---- .../queries/Cassandra22SchemaQueries.java | 14 +++++---- .../queries/Cassandra3SchemaQueries.java | 14 +++++---- .../queries/Cassandra4SchemaQueries.java | 14 +++++---- .../queries/CassandraSchemaQueries.java | 14 +++++---- .../schema/queries/CassandraSchemaRows.java | 14 +++++---- .../queries/DefaultSchemaQueriesFactory.java | 14 +++++---- .../schema/queries/Dse68SchemaQueries.java | 14 +++++---- .../schema/queries/KeyspaceFilter.java | 14 +++++---- .../queries/RuleBasedKeyspaceFilter.java | 14 +++++---- .../schema/queries/SchemaQueries.java | 14 +++++---- .../schema/queries/SchemaQueriesFactory.java | 14 +++++---- .../metadata/schema/queries/SchemaRows.java | 14 +++++---- .../schema/refresh/SchemaRefresh.java | 14 +++++---- .../core/metadata/token/ByteOrderedToken.java | 14 +++++---- .../token/ByteOrderedTokenFactory.java | 14 +++++---- .../metadata/token/ByteOrderedTokenRange.java | 14 +++++---- .../token/CanonicalNodeSetBuilder.java | 14 +++++---- .../DefaultReplicationStrategyFactory.java | 14 +++++---- .../token/DefaultTokenFactoryRegistry.java | 14 +++++---- .../core/metadata/token/DefaultTokenMap.java | 14 +++++---- .../token/EverywhereReplicationStrategy.java | 14 +++++---- .../core/metadata/token/KeyspaceTokenMap.java | 14 +++++---- .../token/LocalReplicationStrategy.java | 14 +++++---- .../core/metadata/token/Murmur3Token.java | 14 +++++---- .../metadata/token/Murmur3TokenFactory.java | 14 +++++---- .../metadata/token/Murmur3TokenRange.java | 14 +++++---- .../NetworkTopologyReplicationStrategy.java | 14 +++++---- .../core/metadata/token/RandomToken.java | 14 +++++---- .../metadata/token/RandomTokenFactory.java | 14 +++++---- .../core/metadata/token/RandomTokenRange.java | 14 +++++---- .../metadata/token/ReplicationFactor.java | 14 +++++---- .../metadata/token/ReplicationStrategy.java | 14 +++++---- .../token/ReplicationStrategyFactory.java | 14 +++++---- .../token/SimpleReplicationStrategy.java | 14 +++++---- .../core/metadata/token/TokenFactory.java | 14 +++++---- .../metadata/token/TokenFactoryRegistry.java | 14 +++++---- .../core/metadata/token/TokenRangeBase.java | 14 +++++---- .../core/metrics/AbstractMetricUpdater.java | 14 +++++---- .../core/metrics/DefaultMetricId.java | 14 +++++---- .../metrics/DefaultMetricIdGenerator.java | 14 +++++---- .../internal/core/metrics/DefaultMetrics.java | 14 +++++---- .../core/metrics/DefaultMetricsFactory.java | 14 +++++---- .../DefaultMetricsFactorySubstitutions.java | 14 +++++---- .../core/metrics/DropwizardMetricUpdater.java | 14 +++++---- .../metrics/DropwizardMetricsFactory.java | 14 +++++---- .../metrics/DropwizardNodeMetricUpdater.java | 14 +++++---- .../DropwizardSessionMetricUpdater.java | 14 +++++---- .../internal/core/metrics/HdrReservoir.java | 14 +++++---- .../internal/core/metrics/MetricId.java | 14 +++++---- .../core/metrics/MetricIdGenerator.java | 14 +++++---- .../internal/core/metrics/MetricPaths.java | 14 +++++---- .../internal/core/metrics/MetricUpdater.java | 14 +++++---- .../internal/core/metrics/MetricsFactory.java | 14 +++++---- .../core/metrics/NodeMetricUpdater.java | 14 +++++---- .../core/metrics/NoopMetricsFactory.java | 14 +++++---- .../core/metrics/NoopNodeMetricUpdater.java | 14 +++++---- .../metrics/NoopSessionMetricUpdater.java | 14 +++++---- .../core/metrics/SessionMetricUpdater.java | 14 +++++---- .../metrics/TaggingMetricIdGenerator.java | 14 +++++---- .../oss/driver/internal/core/os/CpuInfo.java | 14 +++++---- .../driver/internal/core/os/EmptyLibc.java | 14 +++++---- .../driver/internal/core/os/GraalGetpid.java | 14 +++++---- .../driver/internal/core/os/GraalLibc.java | 14 +++++---- .../oss/driver/internal/core/os/JnrLibc.java | 14 +++++---- .../internal/core/os/JnrLibcSubstitution.java | 14 +++++---- .../oss/driver/internal/core/os/Libc.java | 14 +++++---- .../oss/driver/internal/core/os/Native.java | 14 +++++---- .../internal/core/pool/ChannelPool.java | 14 +++++---- .../core/pool/ChannelPoolFactory.java | 14 +++++---- .../driver/internal/core/pool/ChannelSet.java | 14 +++++---- .../core/protocol/BuiltInCompressors.java | 14 +++++---- .../core/protocol/ByteBufCompressor.java | 14 +++++---- .../core/protocol/ByteBufPrimitiveCodec.java | 14 +++++---- .../core/protocol/ByteBufSegmentBuilder.java | 14 +++++---- .../core/protocol/BytesToSegmentDecoder.java | 14 +++++---- .../protocol/CompressorSubstitutions.java | 14 +++++---- .../internal/core/protocol/FrameDecoder.java | 14 +++++---- .../core/protocol/FrameDecodingException.java | 14 +++++---- .../internal/core/protocol/FrameEncoder.java | 14 +++++---- .../core/protocol/FrameToSegmentEncoder.java | 14 +++++---- .../internal/core/protocol/Lz4Compressor.java | 14 +++++---- .../core/protocol/SegmentToBytesEncoder.java | 14 +++++---- .../core/protocol/SegmentToFrameDecoder.java | 14 +++++---- .../core/protocol/SnappyCompressor.java | 14 +++++---- .../internal/core/protocol/package-info.java | 14 +++++---- .../ConsistencyDowngradingRetryPolicy.java | 14 +++++---- .../ConsistencyDowngradingRetryVerdict.java | 14 +++++---- .../core/retry/DefaultRetryPolicy.java | 14 +++++---- .../core/retry/DefaultRetryVerdict.java | 14 +++++---- .../DefaultWriteTypeRegistry.java | 14 +++++---- .../core/servererrors/WriteTypeRegistry.java | 14 +++++---- .../session/BuiltInRequestProcessors.java | 14 +++++---- ...BuiltInRequestProcessorsSubstitutions.java | 14 +++++---- .../internal/core/session/DefaultSession.java | 14 +++++---- .../internal/core/session/PoolManager.java | 14 +++++---- .../internal/core/session/ReprepareOnUp.java | 14 +++++---- .../core/session/RepreparePayload.java | 14 +++++---- .../core/session/RequestProcessor.java | 14 +++++---- .../session/RequestProcessorRegistry.java | 14 +++++---- .../core/session/SchemaListenerNotifier.java | 14 +++++---- .../internal/core/session/SessionWrapper.java | 14 +++++---- .../ConcurrencyLimitingRequestThrottler.java | 14 +++++---- .../core/session/throttling/NanoClock.java | 14 +++++---- .../PassThroughRequestThrottler.java | 14 +++++---- .../RateLimitingRequestThrottler.java | 14 +++++---- .../ConstantSpeculativeExecutionPolicy.java | 14 +++++---- .../specex/NoSpeculativeExecutionPolicy.java | 14 +++++---- .../core/ssl/DefaultSslEngineFactory.java | 14 +++++---- .../core/ssl/JdkSslHandlerFactory.java | 14 +++++---- .../core/ssl/SniSslEngineFactory.java | 14 +++++---- .../internal/core/ssl/SslHandlerFactory.java | 14 +++++---- .../core/time/AtomicTimestampGenerator.java | 14 +++++---- .../oss/driver/internal/core/time/Clock.java | 14 +++++---- .../driver/internal/core/time/JavaClock.java | 14 +++++---- .../time/MonotonicTimestampGenerator.java | 14 +++++---- .../internal/core/time/NativeClock.java | 14 +++++---- .../time/ServerSideTimestampGenerator.java | 14 +++++---- .../time/ThreadLocalTimestampGenerator.java | 14 +++++---- .../tracker/MultiplexingRequestTracker.java | 14 +++++---- .../core/tracker/NoopRequestTracker.java | 14 +++++---- .../core/tracker/RequestLogFormatter.java | 14 +++++---- .../internal/core/tracker/RequestLogger.java | 14 +++++---- .../internal/core/type/DataTypeHelper.java | 14 +++++---- .../internal/core/type/DefaultCustomType.java | 14 +++++---- .../internal/core/type/DefaultListType.java | 14 +++++---- .../internal/core/type/DefaultMapType.java | 14 +++++---- .../internal/core/type/DefaultSetType.java | 14 +++++---- .../internal/core/type/DefaultTupleType.java | 14 +++++---- .../core/type/DefaultUserDefinedType.java | 14 +++++---- .../internal/core/type/DefaultVectorType.java | 14 +++++---- .../internal/core/type/PrimitiveType.java | 14 +++++---- .../core/type/UserDefinedTypeBuilder.java | 14 +++++---- .../internal/core/type/codec/BigIntCodec.java | 14 +++++---- .../internal/core/type/codec/BlobCodec.java | 14 +++++---- .../core/type/codec/BooleanCodec.java | 14 +++++---- .../core/type/codec/CounterCodec.java | 14 +++++---- .../core/type/codec/CqlDurationCodec.java | 14 +++++---- .../internal/core/type/codec/CustomCodec.java | 14 +++++---- .../internal/core/type/codec/DateCodec.java | 14 +++++---- .../core/type/codec/DecimalCodec.java | 14 +++++---- .../internal/core/type/codec/DoubleCodec.java | 14 +++++---- .../internal/core/type/codec/FloatCodec.java | 14 +++++---- .../internal/core/type/codec/InetCodec.java | 14 +++++---- .../internal/core/type/codec/IntCodec.java | 14 +++++---- .../internal/core/type/codec/ListCodec.java | 14 +++++---- .../internal/core/type/codec/MapCodec.java | 14 +++++---- .../internal/core/type/codec/ParseUtils.java | 14 +++++---- .../internal/core/type/codec/SetCodec.java | 14 +++++---- .../core/type/codec/SimpleBlobCodec.java | 14 +++++---- .../core/type/codec/SmallIntCodec.java | 14 +++++---- .../internal/core/type/codec/StringCodec.java | 14 +++++---- .../internal/core/type/codec/TimeCodec.java | 14 +++++---- .../core/type/codec/TimeUuidCodec.java | 14 +++++---- .../core/type/codec/TimestampCodec.java | 14 +++++---- .../core/type/codec/TinyIntCodec.java | 14 +++++---- .../internal/core/type/codec/TupleCodec.java | 14 +++++---- .../internal/core/type/codec/UdtCodec.java | 14 +++++---- .../internal/core/type/codec/UuidCodec.java | 14 +++++---- .../internal/core/type/codec/VarIntCodec.java | 14 +++++---- .../internal/core/type/codec/VectorCodec.java | 14 +++++---- .../core/type/codec/extras/OptionalCodec.java | 14 +++++---- .../array/AbstractListToArrayCodec.java | 14 +++++---- .../AbstractPrimitiveListToArrayCodec.java | 14 +++++---- .../extras/array/BooleanListToArrayCodec.java | 14 +++++---- .../extras/array/ByteListToArrayCodec.java | 14 +++++---- .../extras/array/DoubleListToArrayCodec.java | 14 +++++---- .../extras/array/FloatListToArrayCodec.java | 14 +++++---- .../extras/array/IntListToArrayCodec.java | 14 +++++---- .../extras/array/LongListToArrayCodec.java | 14 +++++---- .../extras/array/ObjectListToArrayCodec.java | 14 +++++---- .../extras/array/ShortListToArrayCodec.java | 14 +++++---- .../codec/extras/enums/EnumNameCodec.java | 14 +++++---- .../codec/extras/enums/EnumOrdinalCodec.java | 14 +++++---- .../type/codec/extras/json/JsonCodec.java | 14 +++++---- .../extras/time/LocalTimestampCodec.java | 14 +++++---- .../time/PersistentZonedTimestampCodec.java | 14 +++++---- .../extras/time/TimestampMillisCodec.java | 14 +++++---- .../extras/time/ZonedTimestampCodec.java | 14 +++++---- .../vector/AbstractVectorToArrayCodec.java | 14 +++++---- .../vector/FloatVectorToArrayCodec.java | 14 +++++---- .../codec/registry/CachingCodecRegistry.java | 14 +++++---- .../registry/CodecRegistryConstants.java | 14 +++++---- .../codec/registry/DefaultCodecRegistry.java | 14 +++++---- .../internal/core/type/util/VIntCoding.java | 14 +++++---- .../driver/internal/core/util/ArrayUtils.java | 14 +++++---- .../internal/core/util/CollectionsUtils.java | 14 +++++---- .../internal/core/util/CountingIterator.java | 14 +++++---- .../core/util/DefaultDependencyChecker.java | 14 +++++---- .../driver/internal/core/util/Dependency.java | 14 +++++---- .../internal/core/util/DirectedGraph.java | 14 +++++---- .../core/util/GraalDependencyChecker.java | 14 +++++---- .../driver/internal/core/util/Loggers.java | 14 +++++---- .../driver/internal/core/util/NanoTime.java | 14 +++++---- .../internal/core/util/ProtocolUtils.java | 14 +++++---- .../driver/internal/core/util/Reflection.java | 14 +++++---- .../driver/internal/core/util/RoutingKey.java | 14 +++++---- .../oss/driver/internal/core/util/Sizes.java | 14 +++++---- .../driver/internal/core/util/Strings.java | 14 +++++---- .../util/collection/CompositeQueryPlan.java | 14 +++++---- .../core/util/collection/EmptyQueryPlan.java | 14 +++++---- .../core/util/collection/LazyQueryPlan.java | 14 +++++---- .../core/util/collection/QueryPlan.java | 14 +++++---- .../core/util/collection/QueryPlanBase.java | 14 +++++---- .../core/util/collection/SimpleQueryPlan.java | 14 +++++---- .../util/concurrent/BlockingOperation.java | 14 +++++---- .../util/concurrent/CompletableFutures.java | 14 +++++---- .../core/util/concurrent/CycleDetector.java | 14 +++++---- .../core/util/concurrent/Debouncer.java | 14 +++++---- .../DriverBlockHoundIntegration.java | 14 +++++---- .../core/util/concurrent/LazyReference.java | 14 +++++---- .../core/util/concurrent/PromiseCombiner.java | 14 +++++---- .../core/util/concurrent/Reconnection.java | 14 +++++---- .../util/concurrent/ReplayingEventFilter.java | 14 +++++---- .../core/util/concurrent/RunOrSchedule.java | 14 +++++---- .../util/concurrent/UncaughtExceptions.java | 14 +++++---- .../internal/core/util/package-info.java | 14 +++++---- .../oss/driver/internal/package-info.java | 14 +++++---- .../com/datastax/oss/driver/Driver.properties | 16 +++++----- core/src/main/resources/reference.conf | 2 +- .../com/datastax/dse/driver/Assertions.java | 14 +++++---- .../dse/driver/DriverRunListener.java | 14 +++++---- .../dse/driver/DseTestDataProviders.java | 14 +++++---- .../datastax/dse/driver/DseTestFixtures.java | 14 +++++---- .../dse/driver/TinkerpopBufferAssert.java | 14 +++++---- .../data/time/DateRangePrecisionTest.java | 14 +++++---- .../api/core/data/time/DateRangeTest.java | 14 +++++---- .../graph/predicates/CqlCollectionTest.java | 14 +++++---- .../api/core/graph/predicates/GeoTest.java | 14 +++++---- .../api/core/graph/predicates/SearchTest.java | 14 +++++---- .../driver/internal/DependencyCheckTest.java | 14 +++++---- .../internal/DependencyCheckTestBase.java | 14 +++++---- .../context/DseStartupOptionsBuilderTest.java | 14 +++++---- ...ousCqlRequestHandlerNodeTargetingTest.java | 14 +++++---- ...tinuousCqlRequestHandlerReprepareTest.java | 14 +++++---- .../ContinuousCqlRequestHandlerRetryTest.java | 14 +++++---- .../ContinuousCqlRequestHandlerTest.java | 14 +++++---- .../ContinuousCqlRequestHandlerTestBase.java | 14 +++++---- .../DefaultContinuousAsyncResultSetTest.java | 14 +++++---- .../DefaultContinuousResultSetTest.java | 14 +++++---- ...inuousCqlRequestReactiveProcessorTest.java | 14 +++++---- .../CqlRequestReactiveProcessorTest.java | 14 +++++---- .../DefaultReactiveResultSetTckTest.java | 14 +++++---- .../core/cql/reactive/MockAsyncResultSet.java | 14 +++++---- .../internal/core/cql/reactive/MockRow.java | 14 +++++---- .../ReactiveResultSetSubscriptionTest.java | 14 +++++---- .../SimpleUnicastProcessorTckTest.java | 14 +++++---- .../reactive/SimpleUnicastProcessorTest.java | 14 +++++---- .../core/cql/reactive/TestSubscriber.java | 14 +++++---- .../data/geometry/DefaultLineStringTest.java | 14 +++++---- .../core/data/geometry/DefaultPointTest.java | 14 +++++---- .../data/geometry/DefaultPolygonTest.java | 14 +++++---- .../core/data/geometry/DistanceTest.java | 14 +++++---- .../data/geometry/SerializationUtils.java | 14 +++++---- ...equestHandlerSpeculativeExecutionTest.java | 14 +++++---- .../ContinuousGraphRequestHandlerTest.java | 14 +++++---- .../GraphExecutionInfoConverterTest.java | 14 +++++---- .../internal/core/graph/GraphNodeTest.java | 14 +++++---- .../core/graph/GraphRequestHandlerTest.java | 14 +++++---- .../graph/GraphRequestHandlerTestHarness.java | 14 +++++---- .../core/graph/GraphResultSetTestBase.java | 14 +++++---- .../core/graph/GraphResultSetsTest.java | 14 +++++---- .../graph/GraphStatementBuilderBaseTest.java | 14 +++++---- .../core/graph/GraphSupportCheckerTest.java | 14 +++++---- .../internal/core/graph/GraphTestUtils.java | 14 +++++---- .../core/graph/binary/GraphDataTypesTest.java | 14 +++++---- .../ReactiveGraphRequestProcessorTest.java | 14 +++++---- .../refresh/GraphSchemaRefreshTest.java | 14 +++++---- .../core/insights/AddressFormatterTest.java | 14 +++++---- .../ConfigAntiPatternsFinderTest.java | 14 +++++---- .../core/insights/DataCentersFinderTest.java | 14 +++++---- .../insights/ExecutionProfileMockUtil.java | 14 +++++---- .../ExecutionProfilesInfoFinderTest.java | 14 +++++---- .../core/insights/InsightsClientTest.java | 14 +++++---- .../insights/InsightsSupportVerifierTest.java | 14 +++++---- .../core/insights/PackageUtilTest.java | 14 +++++---- .../core/insights/PlatformInfoFinderTest.java | 14 +++++---- .../ReconnectionPolicyInfoFinderTest.java | 14 +++++---- .../TinkerpopBufferPrimitiveCodecTest.java | 14 +++++---- .../codec/geometry/GeometryCodecTest.java | 14 +++++---- .../codec/geometry/LineStringCodecTest.java | 14 +++++---- .../type/codec/geometry/PointCodecTest.java | 14 +++++---- .../type/codec/geometry/PolygonCodecTest.java | 14 +++++---- .../type/codec/time/DateRangeCodecTest.java | 14 +++++---- .../BoundedConcurrentQueueTest.java | 14 +++++---- .../com/datastax/oss/driver/Assertions.java | 14 +++++---- .../datastax/oss/driver/ByteBufAssert.java | 14 +++++---- .../oss/driver/DriverRunListener.java | 14 +++++---- .../oss/driver/TestDataProviders.java | 14 +++++---- .../api/core/AllNodesFailedExceptionTest.java | 14 +++++---- .../driver/api/core/CqlIdentifierTest.java | 14 +++++---- .../oss/driver/api/core/VersionAssert.java | 14 +++++---- .../oss/driver/api/core/VersionTest.java | 14 +++++---- ...ProgrammaticPlainTextAuthProviderTest.java | 14 +++++---- .../api/core/config/OptionsMapTest.java | 14 +++++---- .../core/config/TypedDriverOptionTest.java | 14 +++++---- .../api/core/cql/StatementBuilderTest.java | 14 +++++---- .../api/core/cql/StatementProfileTest.java | 14 +++++---- .../driver/api/core/data/CqlDurationTest.java | 14 +++++---- .../driver/api/core/data/CqlVectorTest.java | 14 +++++---- .../SafeInitNodeStateListenerTest.java | 14 +++++---- .../api/core/paging/OffsetPagerAsyncTest.java | 14 +++++---- .../api/core/paging/OffsetPagerSyncTest.java | 14 +++++---- .../api/core/paging/OffsetPagerTestBase.java | 14 +++++---- .../core/paging/OffsetPagerTestFixture.java | 14 +++++---- ...ConsistencyDowngradingRetryPolicyTest.java | 14 +++++---- .../core/retry/DefaultRetryPolicyTest.java | 14 +++++---- .../api/core/retry/RetryPolicyTestBase.java | 14 +++++---- ...onstantSpeculativeExecutionPolicyTest.java | 14 +++++---- .../api/core/type/UserDefinedTypeTest.java | 14 +++++---- .../core/type/reflect/GenericTypeTest.java | 14 +++++---- .../oss/driver/api/core/uuid/UuidsTest.java | 14 +++++---- .../driver/internal/SerializationHelper.java | 14 +++++---- .../core/AsyncPagingIterableWrapperTest.java | 14 +++++---- .../internal/core/CompletionStageAssert.java | 14 +++++---- .../internal/core/ContactPointsTest.java | 14 +++++---- .../DefaultProtocolVersionRegistryTest.java | 14 +++++---- .../internal/core/DriverConfigAssert.java | 14 +++++---- .../core/MockAsyncPagingIterable.java | 14 +++++---- .../internal/core/MockPagingIterable.java | 14 +++++---- .../internal/core/NettyFutureAssert.java | 14 +++++---- .../core/PagingIterableWrapperTest.java | 14 +++++---- .../driver/internal/core/TestResponses.java | 14 +++++---- .../Ec2MultiRegionAddressTranslatorTest.java | 14 +++++---- .../FixedHostNameAddressTranslatorTest.java | 14 +++++---- .../ChannelFactoryAvailableIdsTest.java | 14 +++++---- .../ChannelFactoryClusterNameTest.java | 14 +++++---- ...ChannelFactoryProtocolNegotiationTest.java | 14 +++++---- .../ChannelFactorySupportedOptionsTest.java | 14 +++++---- .../core/channel/ChannelFactoryTestBase.java | 14 +++++---- .../core/channel/ChannelHandlerTestBase.java | 14 +++++---- .../core/channel/ConnectInitHandlerTest.java | 14 +++++---- .../core/channel/DriverChannelTest.java | 14 +++++---- .../core/channel/EmbeddedEndPoint.java | 14 +++++---- .../core/channel/InFlightHandlerTest.java | 14 +++++---- .../internal/core/channel/LocalEndPoint.java | 14 +++++---- .../core/channel/MockAuthenticator.java | 14 +++++---- .../channel/MockChannelFactoryHelper.java | 14 +++++---- .../core/channel/MockResponseCallback.java | 14 +++++---- .../core/channel/ProtocolInitHandlerTest.java | 14 +++++---- .../core/channel/StreamIdGeneratorTest.java | 14 +++++---- .../internal/core/config/MockOptions.java | 14 +++++---- .../core/config/MockTypedOptions.java | 14 +++++---- .../config/cloud/CloudConfigFactoryTest.java | 14 +++++---- .../CompositeDriverConfigReloadTest.java | 14 +++++---- .../composite/CompositeDriverConfigTest.java | 14 +++++---- .../map/MapBasedDriverConfigLoaderTest.java | 14 +++++---- .../config/map/MapBasedDriverConfigTest.java | 14 +++++---- .../DefaultDriverConfigLoaderTest.java | 14 +++++---- ...rammaticDriverConfigLoaderBuilderTest.java | 14 +++++---- ...eSafeDriverConfigOverrideDefaultsTest.java | 14 +++++---- .../typesafe/TypesafeDriverConfigTest.java | 14 +++++---- .../ExponentialReconnectionPolicyTest.java | 14 +++++---- .../context/DefaultDriverContextTest.java | 14 +++++---- .../context/MockedDriverContextFactory.java | 14 +++++---- .../context/StartupOptionsBuilderTest.java | 14 +++++---- .../core/context/bus/EventBusTest.java | 14 +++++---- .../control/ControlConnectionEventsTest.java | 14 +++++---- .../core/control/ControlConnectionTest.java | 14 +++++---- .../control/ControlConnectionTestBase.java | 14 +++++---- .../internal/core/cql/ConversionsTest.java | 14 +++++---- .../core/cql/CqlPrepareHandlerTest.java | 14 +++++---- .../core/cql/CqlRequestHandlerRetryTest.java | 14 +++++---- ...equestHandlerSpeculativeExecutionTest.java | 14 +++++---- .../core/cql/CqlRequestHandlerTest.java | 14 +++++---- .../core/cql/CqlRequestHandlerTestBase.java | 14 +++++---- .../cql/CqlRequestHandlerTrackerTest.java | 14 +++++---- .../core/cql/DefaultAsyncResultSetTest.java | 14 +++++---- .../cql/PagingIterableSpliteratorTest.java | 14 +++++---- .../internal/core/cql/PoolBehavior.java | 14 +++++---- .../core/cql/QueryTraceFetcherTest.java | 14 +++++---- .../core/cql/RequestHandlerTestHarness.java | 14 +++++---- .../internal/core/cql/ResultSetTestBase.java | 14 +++++---- .../internal/core/cql/ResultSetsTest.java | 14 +++++---- .../internal/core/cql/StatementSizeTest.java | 14 +++++---- .../core/data/AccessibleByIdTestBase.java | 14 +++++---- .../core/data/AccessibleByIndexTestBase.java | 14 +++++---- .../core/data/DefaultTupleValueTest.java | 14 +++++---- .../core/data/DefaultUdtValueTest.java | 14 +++++---- .../core/data/IdentifierIndexTest.java | 14 +++++---- ...asicLoadBalancingPolicyDcAgnosticTest.java | 14 +++++---- ...asicLoadBalancingPolicyDcFailoverTest.java | 14 +++++---- .../BasicLoadBalancingPolicyDistanceTest.java | 14 +++++---- .../BasicLoadBalancingPolicyEventsTest.java | 14 +++++---- .../BasicLoadBalancingPolicyInitTest.java | 14 +++++---- ...BasicLoadBalancingPolicyQueryPlanTest.java | 14 +++++---- ...ringLoadBalancingPolicyDcFailoverTest.java | 14 +++++---- ...erringLoadBalancingPolicyDistanceTest.java | 14 +++++---- ...nferringLoadBalancingPolicyEventsTest.java | 14 +++++---- ...cInferringLoadBalancingPolicyInitTest.java | 14 +++++---- ...rringLoadBalancingPolicyQueryPlanTest.java | 14 +++++---- ...aultLoadBalancingPolicyDcFailoverTest.java | 14 +++++---- ...efaultLoadBalancingPolicyDistanceTest.java | 14 +++++---- .../DefaultLoadBalancingPolicyEventsTest.java | 14 +++++---- .../DefaultLoadBalancingPolicyInitTest.java | 14 +++++---- ...faultLoadBalancingPolicyQueryPlanTest.java | 14 +++++---- ...LoadBalancingPolicyRequestTrackerTest.java | 14 +++++---- .../LoadBalancingPolicyTestBase.java | 14 +++++---- .../nodeset/DcAgnosticNodeSetTest.java | 14 +++++---- .../nodeset/MultiDcNodeSetTest.java | 14 +++++---- .../nodeset/SingleDcNodeSetTest.java | 14 +++++---- .../core/metadata/AddNodeRefreshTest.java | 14 +++++---- .../core/metadata/DefaultEndPointTest.java | 14 +++++---- .../metadata/DefaultMetadataTokenMapTest.java | 14 +++++---- .../core/metadata/DefaultNodeTest.java | 14 +++++---- .../metadata/DefaultTopologyMonitorTest.java | 14 +++++---- .../metadata/FullNodeListRefreshTest.java | 14 +++++---- .../metadata/InitialNodeListRefreshTest.java | 14 +++++---- .../LoadBalancingPolicyWrapperTest.java | 14 +++++---- .../core/metadata/MetadataManagerTest.java | 14 +++++---- .../MultiplexingNodeStateListenerTest.java | 14 +++++---- .../core/metadata/NodeStateManagerTest.java | 14 +++++---- .../core/metadata/PeerRowValidatorTest.java | 14 +++++---- .../core/metadata/RemoveNodeRefreshTest.java | 14 +++++---- .../metadata/SchemaAgreementCheckerTest.java | 14 +++++---- .../core/metadata/TestNodeFactory.java | 14 +++++---- .../metadata/schema/IndexMetadataTest.java | 14 +++++---- .../MultiplexingSchemaChangeListenerTest.java | 14 +++++---- .../schema/parsing/AggregateParserTest.java | 14 +++++---- .../parsing/DataTypeClassNameParserTest.java | 14 +++++---- .../parsing/DataTypeCqlNameParserTest.java | 14 +++++---- .../schema/parsing/FunctionParserTest.java | 14 +++++---- .../schema/parsing/SchemaParserTest.java | 14 +++++---- .../schema/parsing/SchemaParserTestBase.java | 14 +++++---- .../schema/parsing/TableParserTest.java | 14 +++++---- .../UserDefinedTypeListParserTest.java | 14 +++++---- .../schema/parsing/ViewParserTest.java | 14 +++++---- .../queries/Cassandra21SchemaQueriesTest.java | 14 +++++---- .../queries/Cassandra22SchemaQueriesTest.java | 14 +++++---- .../queries/Cassandra3SchemaQueriesTest.java | 14 +++++---- .../DefaultSchemaQueriesFactoryTest.java | 14 +++++---- .../schema/queries/KeyspaceFilterTest.java | 14 +++++---- .../schema/queries/SchemaQueriesTest.java | 14 +++++---- .../schema/refresh/SchemaRefreshTest.java | 14 +++++---- .../token/ByteOrderedTokenRangeTest.java | 14 +++++---- .../metadata/token/DefaultTokenMapTest.java | 14 +++++---- .../metadata/token/Murmur3TokenRangeTest.java | 14 +++++---- ...etworkTopologyReplicationStrategyTest.java | 14 +++++---- .../metadata/token/RandomTokenRangeTest.java | 14 +++++---- .../metadata/token/ReplicationFactorTest.java | 14 +++++---- .../token/SimpleReplicationStrategyTest.java | 14 +++++---- .../core/metadata/token/TokenRangeAssert.java | 14 +++++---- .../core/metadata/token/TokenRangeTest.java | 14 +++++---- .../metrics/DefaultMetricIdGeneratorTest.java | 14 +++++---- .../core/metrics/DefaultMetricIdTest.java | 14 +++++---- .../metrics/DropwizardMetricsFactoryTest.java | 14 +++++---- .../DropwizardNodeMetricUpdaterTest.java | 14 +++++---- .../core/metrics/NoopMetricsFactoryTest.java | 14 +++++---- .../metrics/TaggingMetricIdGeneratorTest.java | 14 +++++---- .../driver/internal/core/os/JnrLibcTest.java | 14 +++++---- .../driver/internal/core/os/NativeTest.java | 14 +++++---- .../core/pool/ChannelPoolInitTest.java | 14 +++++---- .../core/pool/ChannelPoolKeyspaceTest.java | 14 +++++---- .../core/pool/ChannelPoolReconnectTest.java | 14 +++++---- .../core/pool/ChannelPoolResizeTest.java | 14 +++++---- .../core/pool/ChannelPoolShutdownTest.java | 14 +++++---- .../core/pool/ChannelPoolTestBase.java | 14 +++++---- .../internal/core/pool/ChannelSetTest.java | 14 +++++---- .../core/protocol/BuiltInCompressorsTest.java | 14 +++++---- .../protocol/ByteBufPrimitiveCodecTest.java | 14 +++++---- .../protocol/BytesToSegmentDecoderTest.java | 14 +++++---- .../core/protocol/FrameDecoderTest.java | 14 +++++---- .../protocol/SegmentToFrameDecoderTest.java | 14 +++++---- .../core/protocol/SliceWriteListenerTest.java | 14 +++++---- .../core/session/DefaultSessionPoolsTest.java | 14 +++++---- .../session/MockChannelPoolFactoryHelper.java | 14 +++++---- .../core/session/PoolManagerTest.java | 14 +++++---- .../core/session/ReprepareOnUpTest.java | 14 +++++---- ...ncurrencyLimitingRequestThrottlerTest.java | 14 +++++---- .../session/throttling/MockThrottled.java | 14 +++++---- .../RateLimitingRequestThrottlerTest.java | 14 +++++---- .../session/throttling/SettableNanoClock.java | 14 +++++---- .../time/AtomicTimestampGeneratorTest.java | 14 +++++---- .../MonotonicTimestampGeneratorTestBase.java | 14 +++++---- .../ThreadLocalTimestampGeneratorTest.java | 14 +++++---- .../MultiplexingRequestTrackerTest.java | 14 +++++---- .../core/tracker/RequestLogFormatterTest.java | 14 +++++---- .../core/type/DataTypeDetachableTest.java | 14 +++++---- .../core/type/DataTypeSerializationTest.java | 14 +++++---- .../internal/core/type/PrimitiveTypeTest.java | 14 +++++---- .../core/type/codec/AsciiCodecTest.java | 14 +++++---- .../core/type/codec/BigIntCodecTest.java | 14 +++++---- .../core/type/codec/BlobCodecTest.java | 14 +++++---- .../core/type/codec/BooleanCodecTest.java | 14 +++++---- .../core/type/codec/CodecTestBase.java | 14 +++++---- .../core/type/codec/CounterCodecTest.java | 14 +++++---- .../core/type/codec/CqlDurationCodecTest.java | 14 +++++---- .../core/type/codec/CqlIntToStringCodec.java | 14 +++++---- .../core/type/codec/CustomCodecTest.java | 14 +++++---- .../core/type/codec/DateCodecTest.java | 14 +++++---- .../core/type/codec/DecimalCodecTest.java | 14 +++++---- .../core/type/codec/DoubleCodecTest.java | 14 +++++---- .../core/type/codec/FloatCodecTest.java | 14 +++++---- .../core/type/codec/InetCodecTest.java | 14 +++++---- .../core/type/codec/IntCodecTest.java | 14 +++++---- .../core/type/codec/ListCodecTest.java | 14 +++++---- .../core/type/codec/MapCodecTest.java | 14 +++++---- .../core/type/codec/MappingCodecTest.java | 14 +++++---- .../core/type/codec/SetCodecTest.java | 14 +++++---- .../core/type/codec/SimpleBlobCodecTest.java | 14 +++++---- .../core/type/codec/SmallIntCodecTest.java | 14 +++++---- .../core/type/codec/TextCodecTest.java | 14 +++++---- .../core/type/codec/TimeCodecTest.java | 14 +++++---- .../core/type/codec/TimeUuidCodecTest.java | 14 +++++---- .../core/type/codec/TimestampCodecTest.java | 14 +++++---- .../core/type/codec/TinyIntCodecTest.java | 14 +++++---- .../core/type/codec/TupleCodecTest.java | 14 +++++---- .../core/type/codec/UdtCodecTest.java | 14 +++++---- .../core/type/codec/UuidCodecTest.java | 14 +++++---- .../core/type/codec/VarintCodecTest.java | 14 +++++---- .../core/type/codec/VectorCodecTest.java | 14 +++++---- .../type/codec/extras/OptionalCodecTest.java | 14 +++++---- .../extras/array/BooleanArrayCodecTest.java | 14 +++++---- .../extras/array/ByteArrayCodecTest.java | 14 +++++---- .../extras/array/DoubleArrayCodecTest.java | 14 +++++---- .../extras/array/FloatArrayCodecTest.java | 14 +++++---- .../codec/extras/array/IntArrayCodecTest.java | 14 +++++---- .../extras/array/LongArrayCodecTest.java | 14 +++++---- .../extras/array/ObjectArrayCodecTest.java | 14 +++++---- .../extras/array/ShortArrayCodecTest.java | 14 +++++---- .../codec/extras/enums/EnumNameCodecTest.java | 14 +++++---- .../extras/enums/EnumOrdinalCodecTest.java | 14 +++++---- .../type/codec/extras/json/JsonCodecTest.java | 14 +++++---- .../extras/time/LocalTimestampCodecTest.java | 14 +++++---- .../PersistentZonedTimestampCodecTest.java | 14 +++++---- .../extras/time/TimestampMillisCodecTest.java | 14 +++++---- .../extras/time/ZonedTimestampCodecTest.java | 14 +++++---- .../registry/CachingCodecRegistryTest.java | 14 +++++---- ...CachingCodecRegistryTestDataProviders.java | 14 +++++---- .../internal/core/util/ArrayUtilsTest.java | 14 +++++---- .../driver/internal/core/util/ByteBufs.java | 14 +++++---- .../core/util/CollectionsUtilsTest.java | 14 +++++---- .../internal/core/util/DirectedGraphTest.java | 14 +++++---- .../driver/internal/core/util/LoggerTest.java | 14 +++++---- .../internal/core/util/ReflectionTest.java | 14 +++++---- .../internal/core/util/StringsTest.java | 14 +++++---- .../collection/CompositeQueryPlanTest.java | 14 +++++---- .../util/collection/LazyQueryPlanTest.java | 14 +++++---- .../util/collection/QueryPlanTestBase.java | 14 +++++---- .../util/collection/SimpleQueryPlanTest.java | 14 +++++---- .../core/util/concurrent/CapturingTimer.java | 14 +++++---- .../util/concurrent/CycleDetectorTest.java | 14 +++++---- .../core/util/concurrent/DebouncerTest.java | 14 +++++---- .../util/concurrent/PromiseCombinerTest.java | 14 +++++---- .../util/concurrent/ReconnectionTest.java | 14 +++++---- .../concurrent/ReplayingEventFilterTest.java | 14 +++++---- .../ScheduledTaskCapturingEventLoop.java | 14 +++++---- .../ScheduledTaskCapturingEventLoopTest.java | 14 +++++---- .../config/customApplication.properties | 14 +++++---- .../insights/malformed-pom.properties | 14 +++++---- .../test/resources/insights/pom.properties | 14 +++++---- core/src/test/resources/logback-test.xml | 14 +++++---- core/src/test/resources/project.properties | 14 +++++---- distribution/pom.xml | 20 ++++++------ distribution/src/assembly/binary-tarball.xml | 14 +++++---- docs.yaml | 4 +-- examples/README.md | 4 +-- examples/pom.xml | 18 ++++++----- .../astra/AstraReadCassandraVersion.java | 16 +++++----- .../basic/CreateAndPopulateKeyspace.java | 16 +++++----- .../examples/basic/ReadCassandraVersion.java | 16 +++++----- .../basic/ReadTopologyAndSchemaMetadata.java | 16 +++++----- .../concurrent/LimitConcurrencyCustom.java | 16 +++++----- .../LimitConcurrencyCustomAsync.java | 16 +++++----- .../LimitConcurrencyRequestThrottler.java | 14 +++++---- .../oss/driver/examples/datatypes/Blobs.java | 16 +++++----- .../examples/datatypes/CustomCodecs.java | 14 +++++---- .../examples/datatypes/TuplesMapped.java | 16 +++++----- .../examples/datatypes/TuplesSimple.java | 16 +++++----- .../datatypes/UserDefinedTypesMapped.java | 16 +++++----- .../datatypes/UserDefinedTypesSimple.java | 16 +++++----- .../failover/CrossDatacenterFailover.java | 16 +++++----- .../driver/examples/json/PlainTextJson.java | 14 +++++---- .../json/jackson/JacksonJsonColumn.java | 14 +++++---- .../json/jackson/JacksonJsonFunction.java | 14 +++++---- .../examples/json/jackson/JacksonJsonRow.java | 14 +++++---- .../examples/json/jsr/Jsr353JsonCodec.java | 14 +++++---- .../examples/json/jsr/Jsr353JsonColumn.java | 14 +++++---- .../examples/json/jsr/Jsr353JsonFunction.java | 14 +++++---- .../examples/json/jsr/Jsr353JsonRow.java | 14 +++++---- .../mapper/KillrVideoMapperExample.java | 14 +++++---- .../mapper/killrvideo/KillrVideoMapper.java | 14 +++++---- .../user/CreateUserQueryProvider.java | 14 +++++---- .../killrvideo/user/LoginQueryProvider.java | 14 +++++---- .../killrvideo/user/PasswordHashing.java | 14 +++++---- .../examples/mapper/killrvideo/user/User.java | 14 +++++---- .../killrvideo/user/UserCredentials.java | 14 +++++---- .../mapper/killrvideo/user/UserDao.java | 14 +++++---- .../video/CreateVideoQueryProvider.java | 14 +++++---- .../mapper/killrvideo/video/LatestVideo.java | 14 +++++---- .../mapper/killrvideo/video/UserVideo.java | 14 +++++---- .../mapper/killrvideo/video/Video.java | 14 +++++---- .../mapper/killrvideo/video/VideoBase.java | 14 +++++---- .../mapper/killrvideo/video/VideoByTag.java | 14 +++++---- .../mapper/killrvideo/video/VideoDao.java | 14 +++++---- .../examples/paging/ForwardPagingRestUi.java | 14 +++++---- .../examples/paging/RandomPagingRestUi.java | 14 +++++---- .../examples/retry/DowngradingRetry.java | 16 +++++----- examples/src/main/resources/logback.xml | 14 +++++---- integration-tests/pom.xml | 16 +++++----- .../DseGssApiAuthProviderAlternateIT.java | 14 +++++---- .../core/auth/DseGssApiAuthProviderIT.java | 14 +++++---- .../core/auth/DsePlainTextAuthProviderIT.java | 14 +++++---- .../core/auth/DseProxyAuthenticationIT.java | 14 +++++---- .../dse/driver/api/core/auth/EmbeddedAds.java | 14 +++++---- .../driver/api/core/auth/EmbeddedAdsRule.java | 14 +++++---- .../driver/api/core/auth/KerberosUtils.java | 14 +++++---- .../cql/continuous/ContinuousPagingIT.java | 14 +++++---- .../continuous/ContinuousPagingITBase.java | 14 +++++---- .../reactive/ContinuousPagingReactiveIT.java | 14 +++++---- .../api/core/data/geometry/GeometryIT.java | 14 +++++---- .../api/core/data/geometry/LineStringIT.java | 14 +++++---- .../api/core/data/geometry/PointIT.java | 14 +++++---- .../api/core/data/geometry/PolygonIT.java | 14 +++++---- .../api/core/data/time/DateRangeIT.java | 14 +++++---- .../graph/ClassicGraphDataTypeITBase.java | 14 +++++---- .../graph/ClassicGraphGeoSearchIndexIT.java | 14 +++++---- .../graph/ClassicGraphTextSearchIndexIT.java | 14 +++++---- .../core/graph/CoreGraphDataTypeITBase.java | 14 +++++---- .../core/graph/CoreGraphGeoSearchIndexIT.java | 14 +++++---- .../graph/CoreGraphTextSearchIndexIT.java | 14 +++++---- .../api/core/graph/CqlCollectionIT.java | 14 +++++---- .../api/core/graph/GraphAuthenticationIT.java | 14 +++++---- .../core/graph/GraphGeoSearchIndexITBase.java | 14 +++++---- .../driver/api/core/graph/GraphPagingIT.java | 14 +++++---- .../graph/GraphSpeculativeExecutionIT.java | 14 +++++---- .../api/core/graph/GraphTestSupport.java | 14 +++++---- .../graph/GraphTextSearchIndexITBase.java | 14 +++++---- .../api/core/graph/GraphTimeoutsIT.java | 14 +++++---- .../api/core/graph/SampleGraphScripts.java | 14 +++++---- .../api/core/graph/SocialTraversalDsl.java | 14 +++++---- .../core/graph/SocialTraversalSourceDsl.java | 14 +++++---- .../api/core/graph/TinkerEdgeAssert.java | 14 +++++---- .../api/core/graph/TinkerElementAssert.java | 14 +++++---- .../api/core/graph/TinkerGraphAssertions.java | 14 +++++---- .../api/core/graph/TinkerPathAssert.java | 14 +++++---- .../api/core/graph/TinkerTreeAssert.java | 14 +++++---- .../api/core/graph/TinkerVertexAssert.java | 14 +++++---- .../graph/TinkerVertexPropertyAssert.java | 14 +++++---- .../DefaultReactiveGraphResultSetIT.java | 14 +++++---- .../remote/ClassicGraphDataTypeRemoteIT.java | 14 +++++---- .../remote/ClassicGraphTraversalRemoteIT.java | 14 +++++---- .../remote/CoreGraphDataTypeRemoteIT.java | 14 +++++---- .../remote/CoreGraphTraversalRemoteIT.java | 14 +++++---- .../GraphTraversalMetaPropertiesRemoteIT.java | 14 +++++---- ...GraphTraversalMultiPropertiesRemoteIT.java | 14 +++++---- .../remote/GraphTraversalRemoteITBase.java | 14 +++++---- .../ClassicGraphDataTypeFluentIT.java | 14 +++++---- .../ClassicGraphDataTypeScriptIT.java | 14 +++++---- .../ClassicGraphTraversalBatchIT.java | 14 +++++---- .../statement/ClassicGraphTraversalIT.java | 14 +++++---- .../statement/CoreGraphDataTypeFluentIT.java | 14 +++++---- .../statement/CoreGraphDataTypeScriptIT.java | 14 +++++---- .../statement/CoreGraphTraversalBatchIT.java | 14 +++++---- .../graph/statement/CoreGraphTraversalIT.java | 14 +++++---- .../statement/GraphTraversalBatchITBase.java | 14 +++++---- .../graph/statement/GraphTraversalITBase.java | 14 +++++---- .../GraphTraversalMetaPropertiesIT.java | 14 +++++---- .../GraphTraversalMultiPropertiesIT.java | 14 +++++---- .../api/core/insights/InsightsClientIT.java | 14 +++++---- .../metadata/schema/AbstractMetadataIT.java | 14 +++++---- .../schema/DseAggregateMetadataIT.java | 14 +++++---- .../schema/DseFunctionMetadataIT.java | 14 +++++---- .../schema/KeyspaceGraphMetadataIT.java | 14 +++++---- .../TableGraphMetadataCaseSensitiveIT.java | 14 +++++---- .../metadata/schema/TableGraphMetadataIT.java | 14 +++++---- .../oss/driver/api/core/cloud/CloudIT.java | 14 +++++---- .../driver/api/core/cloud/SniProxyRule.java | 14 +++++---- .../driver/api/core/cloud/SniProxyServer.java | 14 +++++---- .../oss/driver/core/AllNodesFailedIT.java | 14 +++++---- .../datastax/oss/driver/core/ConnectIT.java | 14 +++++---- .../oss/driver/core/ConnectKeyspaceIT.java | 14 +++++---- .../oss/driver/core/PeersV2NodeRefreshIT.java | 14 +++++---- .../oss/driver/core/PoolBalancingIT.java | 14 +++++---- .../ProtocolVersionInitialNegotiationIT.java | 14 +++++---- .../core/ProtocolVersionMixedClusterIT.java | 14 +++++---- .../oss/driver/core/SerializationIT.java | 14 +++++---- .../oss/driver/core/SessionLeakIT.java | 14 +++++---- .../core/auth/PlainTextAuthProviderIT.java | 14 +++++---- .../core/compression/DirectCompressionIT.java | 14 +++++---- .../core/compression/HeapCompressionIT.java | 14 +++++---- .../core/config/DriverConfigValidationIT.java | 14 +++++---- .../config/DriverExecutionProfileCcmIT.java | 14 +++++---- .../DriverExecutionProfileReloadIT.java | 14 +++++---- .../DriverExecutionProfileSimulacronIT.java | 14 +++++---- .../core/config/MapBasedConfigLoaderIT.java | 14 +++++---- .../connection/ChannelSocketOptionsIT.java | 14 +++++---- .../driver/core/connection/FrameLengthIT.java | 14 +++++---- .../NettyResourceLeakDetectionIT.java | 14 +++++---- .../core/context/LifecycleListenerIT.java | 14 +++++---- .../oss/driver/core/cql/AsyncResultSetIT.java | 14 +++++---- .../oss/driver/core/cql/BatchStatementIT.java | 14 +++++---- .../driver/core/cql/BoundStatementCcmIT.java | 14 +++++---- .../core/cql/BoundStatementSimulacronIT.java | 14 +++++---- .../core/cql/ExecutionInfoWarningsIT.java | 14 +++++---- .../oss/driver/core/cql/NowInSecondsIT.java | 14 +++++---- .../core/cql/PagingIterableSpliteratorIT.java | 14 +++++---- .../oss/driver/core/cql/PagingStateIT.java | 14 +++++---- .../driver/core/cql/PerRequestKeyspaceIT.java | 14 +++++---- .../core/cql/PreparedStatementCachingIT.java | 14 +++++---- .../driver/core/cql/PreparedStatementIT.java | 14 +++++---- .../oss/driver/core/cql/QueryTraceIT.java | 14 +++++---- .../driver/core/cql/SimpleStatementCcmIT.java | 14 +++++---- .../core/cql/SimpleStatementSimulacronIT.java | 14 +++++---- .../reactive/DefaultReactiveResultSetIT.java | 14 +++++---- .../core/cql/reactive/ReactiveRetryIT.java | 14 +++++---- .../oss/driver/core/data/DataTypeIT.java | 14 +++++---- .../core/heartbeat/HeartbeatDisabledIT.java | 14 +++++---- .../driver/core/heartbeat/HeartbeatIT.java | 14 +++++---- .../AllLoadBalancingPoliciesSimulacronIT.java | 14 +++++---- .../DefaultLoadBalancingPolicyIT.java | 14 +++++---- .../core/loadbalancing/NodeTargetingIT.java | 14 +++++---- .../PerProfileLoadBalancingPolicyIT.java | 14 +++++---- .../core/metadata/ByteOrderedTokenIT.java | 14 +++++---- .../metadata/ByteOrderedTokenVnodesIT.java | 14 +++++---- .../core/metadata/CaseSensitiveUdtIT.java | 14 +++++---- .../oss/driver/core/metadata/DescribeIT.java | 14 +++++---- .../oss/driver/core/metadata/MetadataIT.java | 14 +++++---- .../driver/core/metadata/Murmur3TokenIT.java | 14 +++++---- .../core/metadata/Murmur3TokenVnodesIT.java | 14 +++++---- .../driver/core/metadata/NodeMetadataIT.java | 14 +++++---- .../oss/driver/core/metadata/NodeStateIT.java | 14 +++++---- .../driver/core/metadata/RandomTokenIT.java | 14 +++++---- .../core/metadata/RandomTokenVnodesIT.java | 14 +++++---- .../core/metadata/SchemaAgreementIT.java | 14 +++++---- .../driver/core/metadata/SchemaChangesIT.java | 14 +++++---- .../oss/driver/core/metadata/SchemaIT.java | 14 +++++---- .../oss/driver/core/metadata/TokenITBase.java | 14 +++++---- .../core/metrics/DropwizardMetricsIT.java | 14 +++++---- .../driver/core/metrics/MetricsITBase.java | 14 +++++---- .../ConsistencyDowngradingRetryPolicyIT.java | 14 +++++---- .../core/retry/DefaultRetryPolicyIT.java | 14 +++++---- .../core/retry/PerProfileRetryPolicyIT.java | 14 +++++---- .../oss/driver/core/session/AddedNodeIT.java | 14 +++++---- .../oss/driver/core/session/ExceptionIT.java | 14 +++++---- .../oss/driver/core/session/ListenersIT.java | 14 +++++---- .../driver/core/session/RemovedNodeIT.java | 14 +++++---- .../core/session/RequestProcessorIT.java | 14 +++++---- .../oss/driver/core/session/ShutdownIT.java | 14 +++++---- .../core/specex/SpeculativeExecutionIT.java | 14 +++++---- ...tSslEngineFactoryHostnameValidationIT.java | 14 +++++---- .../core/ssl/DefaultSslEngineFactoryIT.java | 14 +++++---- ...efaultSslEngineFactoryPropertyBasedIT.java | 14 +++++---- ...eFactoryPropertyBasedWithClientAuthIT.java | 14 +++++---- ...faultSslEngineFactoryWithClientAuthIT.java | 14 +++++---- .../driver/core/ssl/ProgrammaticSslIT.java | 14 +++++---- .../driver/core/throttling/ThrottlingIT.java | 14 +++++---- .../driver/core/tracker/RequestLoggerIT.java | 14 +++++---- .../tracker/RequestNodeLoggerExample.java | 14 +++++---- .../core/type/codec/CqlIntToStringCodec.java | 14 +++++---- .../core/type/codec/ExtraTypeCodecsIT.java | 14 +++++---- .../type/codec/registry/CodecRegistryIT.java | 14 +++++---- .../example/guava/api/GuavaSession.java | 14 +++++---- .../guava/api/GuavaSessionBuilder.java | 14 +++++---- .../example/guava/api/GuavaSessionUtils.java | 14 +++++---- .../guava/internal/DefaultGuavaSession.java | 14 +++++---- .../guava/internal/GuavaDriverContext.java | 14 +++++---- .../internal/GuavaRequestAsyncProcessor.java | 14 +++++---- .../example/guava/internal/KeyRequest.java | 14 +++++---- .../guava/internal/KeyRequestProcessor.java | 14 +++++---- .../DriverBlockHoundIntegrationCcmIT.java | 14 +++++---- .../DriverBlockHoundIntegrationIT.java | 14 +++++---- .../oss/driver/mapper/ComputedIT.java | 14 +++++---- .../oss/driver/mapper/CustomResultTypeIT.java | 14 +++++---- .../oss/driver/mapper/DefaultKeyspaceIT.java | 14 +++++---- .../mapper/DefaultNullSavingStrategyIT.java | 14 +++++---- .../datastax/oss/driver/mapper/DeleteIT.java | 14 +++++---- .../oss/driver/mapper/DeleteReactiveIT.java | 14 +++++---- .../driver/mapper/EntityPolymorphismIT.java | 14 +++++---- .../oss/driver/mapper/FluentEntityIT.java | 14 +++++---- .../oss/driver/mapper/GetEntityIT.java | 14 +++++---- .../mapper/GuavaFutureProducerService.java | 14 +++++---- .../oss/driver/mapper/ImmutableEntityIT.java | 14 +++++---- .../oss/driver/mapper/IncrementIT.java | 14 +++++---- .../driver/mapper/IncrementWithNullsIT.java | 14 +++++---- .../datastax/oss/driver/mapper/InsertIT.java | 14 +++++---- .../oss/driver/mapper/InsertReactiveIT.java | 14 +++++---- .../oss/driver/mapper/InventoryITBase.java | 14 +++++---- .../oss/driver/mapper/NamingStrategyIT.java | 14 +++++---- .../oss/driver/mapper/NestedUdtIT.java | 14 +++++---- .../driver/mapper/NullSavingStrategyIT.java | 14 +++++---- .../oss/driver/mapper/PrimitivesIT.java | 14 +++++---- .../datastax/oss/driver/mapper/ProfileIT.java | 14 +++++---- .../mapper/QueryKeyspaceAndTableIT.java | 14 +++++---- .../oss/driver/mapper/QueryProviderIT.java | 14 +++++---- .../oss/driver/mapper/QueryReactiveIT.java | 14 +++++---- .../oss/driver/mapper/QueryReturnTypesIT.java | 14 +++++---- .../oss/driver/mapper/SchemaValidationIT.java | 14 +++++---- .../mapper/SelectCustomWhereClauseIT.java | 14 +++++---- .../datastax/oss/driver/mapper/SelectIT.java | 14 +++++---- .../driver/mapper/SelectOtherClausesIT.java | 14 +++++---- .../oss/driver/mapper/SelectReactiveIT.java | 14 +++++---- .../oss/driver/mapper/SetEntityIT.java | 14 +++++---- .../driver/mapper/StatementAttributesIT.java | 14 +++++---- .../oss/driver/mapper/TransientIT.java | 14 +++++---- .../datastax/oss/driver/mapper/UdtKeyIT.java | 14 +++++---- .../driver/mapper/UpdateCustomIfClauseIT.java | 14 +++++---- .../datastax/oss/driver/mapper/UpdateIT.java | 14 +++++---- .../oss/driver/mapper/UpdateNamingIT.java | 14 +++++---- .../oss/driver/mapper/UpdateReactiveIT.java | 14 +++++---- .../micrometer/MicrometerMetricsIT.java | 14 +++++---- .../microprofile/MicroProfileMetricsIT.java | 14 +++++---- .../oss/driver/querybuilder/JsonInsertIT.java | 14 +++++---- .../src/test/resources/logback-test.xml | 14 +++++---- manual/case_sensitivity/README.md | 2 +- manual/cloud/README.md | 2 +- manual/core/detachable_types/README.md | 2 +- manual/core/dse/graph/results/README.md | 2 +- manual/core/integration/README.md | 4 +-- manual/core/native_protocol/README.md | 2 +- manual/core/non_blocking/README.md | 2 +- mapper-processor/pom.xml | 16 +++++----- .../mapper/processor/CodeGenerator.java | 14 +++++---- .../processor/CodeGeneratorFactory.java | 14 +++++---- .../mapper/processor/DecoratedMessager.java | 14 +++++---- .../DefaultCodeGeneratorFactory.java | 14 +++++---- .../processor/DefaultProcessorContext.java | 14 +++++---- .../mapper/processor/GeneratedNames.java | 14 +++++---- .../mapper/processor/JavaPoetFiler.java | 14 +++++---- .../mapper/processor/MapperProcessor.java | 14 +++++---- .../mapper/processor/MethodGenerator.java | 14 +++++---- .../mapper/processor/ProcessorContext.java | 14 +++++---- .../processor/SingleFileCodeGenerator.java | 14 +++++---- .../dao/DaoDeleteMethodGenerator.java | 14 +++++---- .../dao/DaoGetEntityMethodGenerator.java | 14 +++++---- .../dao/DaoImplementationGenerator.java | 14 +++++---- .../dao/DaoImplementationSharedCode.java | 14 +++++---- .../dao/DaoIncrementMethodGenerator.java | 14 +++++---- .../dao/DaoInsertMethodGenerator.java | 14 +++++---- .../processor/dao/DaoMethodGenerator.java | 14 +++++---- .../dao/DaoQueryMethodGenerator.java | 14 +++++---- .../dao/DaoQueryProviderMethodGenerator.java | 14 +++++---- .../mapper/processor/dao/DaoReturnType.java | 14 +++++---- .../processor/dao/DaoReturnTypeKind.java | 14 +++++---- .../processor/dao/DaoReturnTypeParser.java | 14 +++++---- .../dao/DaoSelectMethodGenerator.java | 14 +++++---- .../dao/DaoSetEntityMethodGenerator.java | 14 +++++---- .../dao/DaoUpdateMethodGenerator.java | 14 +++++---- .../dao/DefaultDaoReturnTypeKind.java | 14 +++++---- .../dao/DefaultDaoReturnTypeParser.java | 14 +++++---- .../mapper/processor/dao/EntityUtils.java | 14 +++++---- .../processor/dao/LoggingGenerator.java | 14 +++++---- .../dao/NullSavingStrategyValidation.java | 14 +++++---- .../entity/BuiltInNameConversions.java | 14 +++++---- .../processor/entity/CqlNameGenerator.java | 14 +++++---- .../entity/DefaultEntityDefinition.java | 14 +++++---- .../entity/DefaultEntityFactory.java | 14 +++++---- .../entity/DefaultPropertyDefinition.java | 14 +++++---- .../processor/entity/EntityDefinition.java | 14 +++++---- .../processor/entity/EntityFactory.java | 14 +++++---- ...lperDeleteByPrimaryKeyMethodGenerator.java | 14 +++++---- ...eleteByPrimaryKeyPartsMethodGenerator.java | 14 +++++---- ...ntityHelperDeleteStartMethodGenerator.java | 14 +++++---- .../entity/EntityHelperGenerator.java | 14 +++++---- .../EntityHelperGetMethodGenerator.java | 14 +++++---- .../EntityHelperInsertMethodGenerator.java | 14 +++++---- ...HelperSchemaValidationMethodGenerator.java | 14 +++++---- ...lperSelectByPrimaryKeyMethodGenerator.java | 14 +++++---- ...electByPrimaryKeyPartsMethodGenerator.java | 14 +++++---- ...ntityHelperSelectStartMethodGenerator.java | 14 +++++---- .../EntityHelperSetMethodGenerator.java | 14 +++++---- ...lperUpdateByPrimaryKeyMethodGenerator.java | 14 +++++---- ...ntityHelperUpdateStartMethodGenerator.java | 14 +++++---- .../processor/entity/PropertyDefinition.java | 14 +++++---- .../mapper/MapperBuilderGenerator.java | 14 +++++---- .../MapperDaoFactoryMethodGenerator.java | 14 +++++---- .../processor/mapper/MapperGenerator.java | 14 +++++---- .../mapper/MapperImplementationGenerator.java | 14 +++++---- .../MapperImplementationSharedCode.java | 14 +++++---- .../processor/util/AnnotationScanner.java | 14 +++++---- .../mapper/processor/util/Capitalizer.java | 14 +++++---- .../mapper/processor/util/Classes.java | 14 +++++---- .../processor/util/HierarchyScanner.java | 14 +++++---- .../mapper/processor/util/NameIndex.java | 14 +++++---- .../processor/util/ResolvedAnnotation.java | 14 +++++---- .../BindableHandlingSharedCode.java | 14 +++++---- .../generation/GeneratedCodePatterns.java | 14 +++++---- .../GenericTypeConstantGenerator.java | 14 +++++---- .../util/generation/PropertyType.java | 14 +++++---- .../mapper/processor/DependencyCheckTest.java | 14 +++++---- .../mapper/entity/EntityHelperBaseTest.java | 14 +++++---- .../mapper/processor/MapperProcessorTest.java | 14 +++++---- .../processor/dao/DaoAnnotationTest.java | 14 +++++---- .../dao/DaoDeleteMethodGeneratorTest.java | 14 +++++---- .../dao/DaoGetEntityMethodGeneratorTest.java | 14 +++++---- .../dao/DaoImplementationGeneratorTest.java | 14 +++++---- .../dao/DaoInsertMethodGeneratorTest.java | 14 +++++---- .../processor/dao/DaoMethodGeneratorTest.java | 14 +++++---- .../dao/DaoQueryMethodGeneratorTest.java | 14 +++++---- .../DaoQueryProviderMethodGeneratorTest.java | 14 +++++---- .../dao/DaoSelectMethodGeneratorTest.java | 14 +++++---- .../dao/DaoSetEntityMethodGeneratorTest.java | 14 +++++---- .../dao/DaoUpdateMethodGeneratorTest.java | 14 +++++---- .../dao/compiled/CompiledProduct.java | 14 +++++---- .../dao/compiled/CompiledProductDao.java | 14 +++++---- .../DaoCompiledMethodGeneratorTest.java | 14 +++++---- .../entity/BuiltInNameConversionsTest.java | 14 +++++---- .../entity/EntityAnnotationTest.java | 14 +++++---- .../entity/EntityNamingStrategyTest.java | 14 +++++---- .../entity/EntityPropertyAnnotationsTest.java | 14 +++++---- .../mapper/MapperAnnotationTest.java | 14 +++++---- .../MapperDaoFactoryMethodGeneratorTest.java | 14 +++++---- .../MapperImplementationGeneratorTest.java | 14 +++++---- .../mapper/MapperMethodGeneratorTest.java | 14 +++++---- .../processor/util/CapitalizerTest.java | 14 +++++---- .../processor/util/HierarchyScannerTest.java | 14 +++++---- .../src/test/resources/logback-test.xml | 14 +++++---- .../src/test/resources/project.properties | 14 +++++---- mapper-runtime/pom.xml | 16 +++++----- .../reactive/MappedReactiveResultSet.java | 14 +++++---- .../DefaultMappedReactiveResultSet.java | 14 +++++---- .../FailedMappedReactiveResultSet.java | 14 +++++---- .../mapper/reactive/ReactiveDaoBase.java | 14 +++++---- .../oss/driver/api/mapper/MapperBuilder.java | 14 +++++---- .../oss/driver/api/mapper/MapperContext.java | 14 +++++---- .../driver/api/mapper/MapperException.java | 14 +++++---- .../mapper/annotations/ClusteringColumn.java | 16 +++++----- .../api/mapper/annotations/Computed.java | 14 +++++---- .../api/mapper/annotations/CqlName.java | 14 +++++---- .../driver/api/mapper/annotations/Dao.java | 16 +++++----- .../api/mapper/annotations/DaoFactory.java | 16 +++++----- .../api/mapper/annotations/DaoKeyspace.java | 14 +++++---- .../api/mapper/annotations/DaoProfile.java | 14 +++++---- .../api/mapper/annotations/DaoTable.java | 14 +++++---- .../DefaultNullSavingStrategy.java | 16 +++++----- .../driver/api/mapper/annotations/Delete.java | 16 +++++----- .../driver/api/mapper/annotations/Entity.java | 14 +++++---- .../api/mapper/annotations/GetEntity.java | 16 +++++----- .../annotations/HierarchyScanStrategy.java | 14 +++++---- .../api/mapper/annotations/Increment.java | 16 +++++----- .../driver/api/mapper/annotations/Insert.java | 16 +++++----- .../driver/api/mapper/annotations/Mapper.java | 16 +++++----- .../mapper/annotations/NamingStrategy.java | 14 +++++---- .../api/mapper/annotations/PartitionKey.java | 14 +++++---- .../mapper/annotations/PropertyStrategy.java | 14 +++++---- .../driver/api/mapper/annotations/Query.java | 16 +++++----- .../api/mapper/annotations/QueryProvider.java | 14 +++++---- .../api/mapper/annotations/SchemaHint.java | 14 +++++---- .../driver/api/mapper/annotations/Select.java | 16 +++++----- .../api/mapper/annotations/SetEntity.java | 16 +++++----- .../annotations/StatementAttributes.java | 14 +++++---- .../api/mapper/annotations/Transient.java | 14 +++++---- .../annotations/TransientProperties.java | 14 +++++---- .../driver/api/mapper/annotations/Update.java | 16 +++++----- .../api/mapper/entity/EntityHelper.java | 14 +++++---- .../api/mapper/entity/naming/GetterStyle.java | 14 +++++---- .../mapper/entity/naming/NameConverter.java | 14 +++++---- .../entity/naming/NamingConvention.java | 14 +++++---- .../api/mapper/entity/naming/SetterStyle.java | 14 +++++---- .../entity/saving/NullSavingStrategy.java | 14 +++++---- .../mapper/result/MapperResultProducer.java | 14 +++++---- .../result/MapperResultProducerService.java | 14 +++++---- .../oss/driver/internal/mapper/DaoBase.java | 14 +++++---- .../driver/internal/mapper/DaoCacheKey.java | 14 +++++---- .../internal/mapper/DefaultMapperContext.java | 14 +++++---- .../mapper/entity/EntityHelperBase.java | 14 +++++---- .../api/mapper/DependencyCheckTest.java | 14 +++++---- .../MappedReactiveResultSetTckTest.java | 14 +++++---- .../mapper/reactive/MockAsyncResultSet.java | 14 +++++---- .../driver/api/mapper/reactive/MockRow.java | 14 +++++---- .../api/mapper/reactive/TestSubscriber.java | 14 +++++---- .../src/test/resources/project.properties | 14 +++++---- metrics/micrometer/pom.xml | 16 +++++----- .../micrometer/MicrometerMetricUpdater.java | 14 +++++---- .../micrometer/MicrometerMetricsFactory.java | 14 +++++---- .../MicrometerNodeMetricUpdater.java | 14 +++++---- .../MicrometerSessionMetricUpdater.java | 14 +++++---- .../metrics/micrometer/MicrometerTags.java | 14 +++++---- .../MicrometerMetricsFactoryTest.java | 14 +++++---- .../MicrometerNodeMetricUpdaterTest.java | 14 +++++---- .../MicrometerSessionMetricUpdaterTest.java | 14 +++++---- metrics/microprofile/pom.xml | 16 +++++----- .../MicroProfileMetricUpdater.java | 14 +++++---- .../MicroProfileMetricsFactory.java | 14 +++++---- .../MicroProfileNodeMetricUpdater.java | 14 +++++---- .../MicroProfileSessionMetricUpdater.java | 14 +++++---- .../microprofile/MicroProfileTags.java | 14 +++++---- .../MicroProfileMetricsFactoryTest.java | 14 +++++---- .../MicroProfileNodeMetricsUpdaterTest.java | 14 +++++---- osgi-tests/README.md | 2 +- osgi-tests/pom.xml | 16 +++++----- .../driver/api/osgi/CustomRetryPolicy.java | 14 +++++---- .../api/osgi/service/MailboxException.java | 14 +++++---- .../api/osgi/service/MailboxMessage.java | 14 +++++---- .../api/osgi/service/MailboxService.java | 14 +++++---- .../osgi/service/geo/GeoMailboxMessage.java | 14 +++++---- .../osgi/service/geo/GeoMailboxService.java | 14 +++++---- .../service/graph/GraphMailboxService.java | 14 +++++---- .../reactive/ReactiveMailboxService.java | 14 +++++---- .../internal/osgi/MailboxActivator.java | 14 +++++---- .../internal/osgi/service/MailboxMapper.java | 14 +++++---- .../osgi/service/MailboxMessageDao.java | 14 +++++---- .../osgi/service/MailboxServiceImpl.java | 14 +++++---- .../osgi/service/geo/GeoMailboxMapper.java | 14 +++++---- .../service/geo/GeoMailboxMessageDao.java | 14 +++++---- .../service/geo/GeoMailboxServiceImpl.java | 14 +++++---- .../graph/GraphMailboxServiceImpl.java | 14 +++++---- .../reactive/ReactiveMailboxMapper.java | 14 +++++---- .../reactive/ReactiveMailboxMessageDao.java | 14 +++++---- .../reactive/ReactiveMailboxServiceImpl.java | 14 +++++---- .../osgi/OsgiCustomLoadBalancingPolicyIT.java | 14 +++++---- .../driver/internal/osgi/OsgiDefaultIT.java | 14 +++++---- .../driver/internal/osgi/OsgiGeoTypesIT.java | 14 +++++---- .../oss/driver/internal/osgi/OsgiGraphIT.java | 14 +++++---- .../oss/driver/internal/osgi/OsgiLz4IT.java | 14 +++++---- .../driver/internal/osgi/OsgiReactiveIT.java | 14 +++++---- .../driver/internal/osgi/OsgiShadedIT.java | 14 +++++---- .../driver/internal/osgi/OsgiSnappyIT.java | 14 +++++---- .../osgi/checks/DefaultServiceChecks.java | 14 +++++---- .../osgi/checks/GeoServiceChecks.java | 14 +++++---- .../osgi/checks/GraphServiceChecks.java | 14 +++++---- .../osgi/checks/ReactiveServiceChecks.java | 14 +++++---- .../internal/osgi/support/BundleOptions.java | 14 +++++---- .../osgi/support/CcmExamReactorFactory.java | 14 +++++---- .../internal/osgi/support/CcmPaxExam.java | 14 +++++---- .../osgi/support/CcmStagedReactor.java | 14 +++++---- osgi-tests/src/test/resources/exam.properties | 14 +++++---- .../src/test/resources/logback-test.xml | 14 +++++---- performance/README.md | 2 +- pom.xml | 31 ++++++++++--------- query-builder/pom.xml | 16 +++++----- .../api/querybuilder/DseQueryBuilder.java | 14 +++++---- .../api/querybuilder/DseSchemaBuilder.java | 14 +++++---- .../driver/api/querybuilder/package-info.java | 14 +++++---- .../querybuilder/schema/AlterDseKeyspace.java | 14 +++++---- .../schema/AlterDseKeyspaceStart.java | 14 +++++---- .../schema/AlterDseTableAddColumn.java | 14 +++++---- .../schema/AlterDseTableAddColumnEnd.java | 14 +++++---- .../schema/AlterDseTableDropColumn.java | 14 +++++---- .../schema/AlterDseTableDropColumnEnd.java | 14 +++++---- .../schema/AlterDseTableRenameColumn.java | 14 +++++---- .../schema/AlterDseTableRenameColumnEnd.java | 14 +++++---- .../schema/AlterDseTableStart.java | 14 +++++---- .../schema/AlterDseTableWithOptions.java | 14 +++++---- .../schema/AlterDseTableWithOptionsEnd.java | 14 +++++---- .../schema/CreateDseAggregateEnd.java | 14 +++++---- .../schema/CreateDseAggregateStart.java | 14 +++++---- .../schema/CreateDseAggregateStateFunc.java | 14 +++++---- .../schema/CreateDseFunctionEnd.java | 14 +++++---- .../schema/CreateDseFunctionStart.java | 14 +++++---- .../schema/CreateDseFunctionWithLanguage.java | 14 +++++---- .../CreateDseFunctionWithNullOption.java | 14 +++++---- .../schema/CreateDseFunctionWithType.java | 14 +++++---- .../schema/CreateDseKeyspace.java | 14 +++++---- .../schema/CreateDseKeyspaceStart.java | 14 +++++---- .../querybuilder/schema/CreateDseTable.java | 14 +++++---- .../schema/CreateDseTableStart.java | 14 +++++---- .../schema/CreateDseTableWithOptions.java | 14 +++++---- .../querybuilder/schema/DseGraphEdgeSide.java | 14 +++++---- .../schema/DseRelationOptions.java | 14 +++++---- .../schema/DseRelationStructure.java | 14 +++++---- .../schema/DseTableGraphOptions.java | 14 +++++---- .../schema/OngoingDsePartitionKey.java | 14 +++++---- .../api/querybuilder/schema/package-info.java | 14 +++++---- .../schema/DefaultAlterDseKeyspace.java | 14 +++++---- .../schema/DefaultAlterDseTable.java | 14 +++++---- .../schema/DefaultCreateDseAggregate.java | 14 +++++---- .../schema/DefaultCreateDseFunction.java | 14 +++++---- .../schema/DefaultCreateDseKeyspace.java | 14 +++++---- .../schema/DefaultCreateDseTable.java | 14 +++++---- .../schema/DefaultDseGraphEdgeSide.java | 14 +++++---- .../schema/DseTableEdgeOperation.java | 14 +++++---- .../schema/DseTableGraphOperationType.java | 14 +++++---- .../schema/DseTableVertexOperation.java | 14 +++++---- .../querybuilder/schema/package-info.java | 14 +++++---- .../driver/api/querybuilder/BindMarker.java | 14 +++++---- .../api/querybuilder/BuildableQuery.java | 14 +++++---- .../driver/api/querybuilder/CqlSnippet.java | 14 +++++---- .../oss/driver/api/querybuilder/Literal.java | 14 +++++---- .../driver/api/querybuilder/QueryBuilder.java | 14 +++++---- .../oss/driver/api/querybuilder/Raw.java | 14 +++++---- .../api/querybuilder/SchemaBuilder.java | 14 +++++---- .../api/querybuilder/condition/Condition.java | 14 +++++---- .../condition/ConditionBuilder.java | 14 +++++---- .../condition/ConditionalStatement.java | 14 +++++---- .../api/querybuilder/delete/Delete.java | 14 +++++---- .../querybuilder/delete/DeleteSelection.java | 14 +++++---- .../api/querybuilder/insert/Insert.java | 14 +++++---- .../api/querybuilder/insert/InsertInto.java | 14 +++++---- .../api/querybuilder/insert/JsonInsert.java | 14 +++++---- .../querybuilder/insert/OngoingValues.java | 14 +++++---- .../querybuilder/insert/RegularInsert.java | 14 +++++---- .../relation/ArithmeticRelationBuilder.java | 14 +++++---- .../ColumnComponentRelationBuilder.java | 14 +++++---- .../relation/ColumnRelationBuilder.java | 14 +++++---- .../relation/InRelationBuilder.java | 14 +++++---- .../relation/MultiColumnRelationBuilder.java | 14 +++++---- .../relation/OngoingWhereClause.java | 14 +++++---- .../api/querybuilder/relation/Relation.java | 14 +++++---- .../relation/TokenRelationBuilder.java | 14 +++++---- .../querybuilder/schema/AlterKeyspace.java | 14 +++++---- .../schema/AlterKeyspaceStart.java | 14 +++++---- .../schema/AlterMaterializedView.java | 14 +++++---- .../schema/AlterMaterializedViewStart.java | 14 +++++---- .../schema/AlterTableAddColumn.java | 14 +++++---- .../schema/AlterTableAddColumnEnd.java | 14 +++++---- .../schema/AlterTableDropColumn.java | 14 +++++---- .../schema/AlterTableDropColumnEnd.java | 14 +++++---- .../schema/AlterTableRenameColumn.java | 14 +++++---- .../schema/AlterTableRenameColumnEnd.java | 14 +++++---- .../querybuilder/schema/AlterTableStart.java | 14 +++++---- .../schema/AlterTableWithOptions.java | 14 +++++---- .../schema/AlterTableWithOptionsEnd.java | 14 +++++---- .../schema/AlterTypeRenameField.java | 14 +++++---- .../schema/AlterTypeRenameFieldEnd.java | 14 +++++---- .../querybuilder/schema/AlterTypeStart.java | 14 +++++---- .../schema/CreateAggregateEnd.java | 14 +++++---- .../schema/CreateAggregateStart.java | 14 +++++---- .../schema/CreateAggregateStateFunc.java | 14 +++++---- .../schema/CreateFunctionEnd.java | 14 +++++---- .../schema/CreateFunctionStart.java | 14 +++++---- .../schema/CreateFunctionWithLanguage.java | 14 +++++---- .../schema/CreateFunctionWithNullOption.java | 14 +++++---- .../schema/CreateFunctionWithType.java | 14 +++++---- .../api/querybuilder/schema/CreateIndex.java | 14 +++++---- .../schema/CreateIndexOnTable.java | 14 +++++---- .../querybuilder/schema/CreateIndexStart.java | 14 +++++---- .../querybuilder/schema/CreateKeyspace.java | 14 +++++---- .../schema/CreateKeyspaceStart.java | 14 +++++---- .../schema/CreateMaterializedView.java | 14 +++++---- .../CreateMaterializedViewPrimaryKey.java | 14 +++++---- ...CreateMaterializedViewPrimaryKeyStart.java | 14 +++++---- .../CreateMaterializedViewSelection.java | 14 +++++---- ...eMaterializedViewSelectionWithColumns.java | 14 +++++---- .../schema/CreateMaterializedViewStart.java | 14 +++++---- .../schema/CreateMaterializedViewWhere.java | 14 +++++---- .../CreateMaterializedViewWhereStart.java | 14 +++++---- .../api/querybuilder/schema/CreateTable.java | 14 +++++---- .../querybuilder/schema/CreateTableStart.java | 14 +++++---- .../schema/CreateTableWithOptions.java | 14 +++++---- .../api/querybuilder/schema/CreateType.java | 14 +++++---- .../querybuilder/schema/CreateTypeStart.java | 14 +++++---- .../driver/api/querybuilder/schema/Drop.java | 14 +++++---- .../querybuilder/schema/KeyspaceOptions.java | 14 +++++---- .../schema/KeyspaceReplicationOptions.java | 14 +++++---- .../schema/OngoingCreateType.java | 14 +++++---- .../schema/OngoingPartitionKey.java | 14 +++++---- .../querybuilder/schema/OptionProvider.java | 14 +++++---- .../querybuilder/schema/RelationOptions.java | 14 +++++---- .../schema/RelationStructure.java | 14 +++++---- .../schema/compaction/CompactionStrategy.java | 14 +++++---- .../compaction/LeveledCompactionStrategy.java | 14 +++++---- .../SizeTieredCompactionStrategy.java | 14 +++++---- .../TimeWindowCompactionStrategy.java | 14 +++++---- .../querybuilder/select/OngoingSelection.java | 14 +++++---- .../api/querybuilder/select/Select.java | 14 +++++---- .../api/querybuilder/select/SelectFrom.java | 14 +++++---- .../api/querybuilder/select/Selector.java | 14 +++++---- .../driver/api/querybuilder/term/Term.java | 14 +++++---- .../api/querybuilder/truncate/Truncate.java | 14 +++++---- .../api/querybuilder/update/Assignment.java | 14 +++++---- .../update/OngoingAssignment.java | 14 +++++---- .../api/querybuilder/update/Update.java | 14 +++++---- .../api/querybuilder/update/UpdateStart.java | 14 +++++---- .../update/UpdateWithAssignments.java | 14 +++++---- .../querybuilder/ArithmeticOperator.java | 14 +++++---- .../internal/querybuilder/CqlHelper.java | 14 +++++---- .../internal/querybuilder/DefaultLiteral.java | 14 +++++---- .../internal/querybuilder/DefaultRaw.java | 14 +++++---- .../querybuilder/ImmutableCollections.java | 14 +++++---- .../condition/DefaultCondition.java | 14 +++++---- .../condition/DefaultConditionBuilder.java | 14 +++++---- .../querybuilder/delete/DefaultDelete.java | 14 +++++---- .../querybuilder/insert/DefaultInsert.java | 14 +++++---- .../lhs/ColumnComponentLeftOperand.java | 14 +++++---- .../querybuilder/lhs/ColumnLeftOperand.java | 14 +++++---- .../querybuilder/lhs/FieldLeftOperand.java | 14 +++++---- .../querybuilder/lhs/LeftOperand.java | 14 +++++---- .../querybuilder/lhs/TokenLeftOperand.java | 14 +++++---- .../querybuilder/lhs/TupleLeftOperand.java | 14 +++++---- .../relation/CustomIndexRelation.java | 14 +++++---- ...DefaultColumnComponentRelationBuilder.java | 14 +++++---- .../DefaultColumnRelationBuilder.java | 14 +++++---- .../DefaultMultiColumnRelationBuilder.java | 14 +++++---- .../relation/DefaultRelation.java | 14 +++++---- .../relation/DefaultTokenRelationBuilder.java | 14 +++++---- .../schema/DefaultAlterKeyspace.java | 14 +++++---- .../schema/DefaultAlterMaterializedView.java | 14 +++++---- .../schema/DefaultAlterTable.java | 14 +++++---- .../querybuilder/schema/DefaultAlterType.java | 14 +++++---- .../schema/DefaultCreateAggregate.java | 14 +++++---- .../schema/DefaultCreateFunction.java | 14 +++++---- .../schema/DefaultCreateIndex.java | 14 +++++---- .../schema/DefaultCreateKeyspace.java | 14 +++++---- .../schema/DefaultCreateMaterializedView.java | 14 +++++---- .../schema/DefaultCreateTable.java | 14 +++++---- .../schema/DefaultCreateType.java | 14 +++++---- .../querybuilder/schema/DefaultDrop.java | 14 +++++---- .../schema/DefaultDropKeyspace.java | 14 +++++---- .../querybuilder/schema/OptionsUtils.java | 14 +++++---- .../internal/querybuilder/schema/Utils.java | 14 +++++---- .../compaction/DefaultCompactionStrategy.java | 14 +++++---- .../DefaultLeveledCompactionStrategy.java | 14 +++++---- .../DefaultSizeTieredCompactionStrategy.java | 14 +++++---- .../DefaultTimeWindowCompactionStrategy.java | 14 +++++---- .../querybuilder/select/AllSelector.java | 14 +++++---- .../select/ArithmeticSelector.java | 14 +++++---- .../select/BinaryArithmeticSelector.java | 14 +++++---- .../querybuilder/select/CastSelector.java | 14 +++++---- .../select/CollectionSelector.java | 14 +++++---- .../querybuilder/select/ColumnSelector.java | 14 +++++---- .../querybuilder/select/CountAllSelector.java | 14 +++++---- .../select/DefaultBindMarker.java | 14 +++++---- .../querybuilder/select/DefaultSelect.java | 14 +++++---- .../querybuilder/select/ElementSelector.java | 14 +++++---- .../querybuilder/select/FieldSelector.java | 14 +++++---- .../querybuilder/select/FunctionSelector.java | 14 +++++---- .../querybuilder/select/ListSelector.java | 14 +++++---- .../querybuilder/select/MapSelector.java | 14 +++++---- .../querybuilder/select/OppositeSelector.java | 14 +++++---- .../querybuilder/select/RangeSelector.java | 14 +++++---- .../querybuilder/select/SetSelector.java | 14 +++++---- .../querybuilder/select/TupleSelector.java | 14 +++++---- .../querybuilder/select/TypeHintSelector.java | 14 +++++---- .../querybuilder/term/ArithmeticTerm.java | 14 +++++---- .../term/BinaryArithmeticTerm.java | 14 +++++---- .../querybuilder/term/FunctionTerm.java | 14 +++++---- .../querybuilder/term/OppositeTerm.java | 14 +++++---- .../internal/querybuilder/term/TupleTerm.java | 14 +++++---- .../querybuilder/term/TypeHintTerm.java | 14 +++++---- .../truncate/DefaultTruncate.java | 14 +++++---- .../querybuilder/update/AppendAssignment.java | 14 +++++---- .../update/AppendListElementAssignment.java | 14 +++++---- .../update/AppendMapEntryAssignment.java | 14 +++++---- .../update/AppendSetElementAssignment.java | 14 +++++---- .../update/CollectionAssignment.java | 14 +++++---- .../update/CollectionElementAssignment.java | 14 +++++---- .../update/CounterAssignment.java | 14 +++++---- .../update/DecrementAssignment.java | 14 +++++---- .../update/DefaultAssignment.java | 14 +++++---- .../querybuilder/update/DefaultUpdate.java | 14 +++++---- .../update/IncrementAssignment.java | 14 +++++---- .../update/PrependAssignment.java | 14 +++++---- .../update/PrependListElementAssignment.java | 14 +++++---- .../update/PrependMapEntryAssignment.java | 14 +++++---- .../update/PrependSetElementAssignment.java | 14 +++++---- .../querybuilder/update/RemoveAssignment.java | 14 +++++---- .../update/RemoveListElementAssignment.java | 14 +++++---- .../update/RemoveMapEntryAssignment.java | 14 +++++---- .../update/RemoveSetElementAssignment.java | 14 +++++---- .../driver/api/querybuilder/Assertions.java | 14 +++++---- .../querybuilder/BuildableQueryAssert.java | 14 +++++---- .../api/querybuilder/CqlSnippetAssert.java | 14 +++++---- .../schema/AlterDseKeyspaceTest.java | 14 +++++---- .../schema/AlterDseTableTest.java | 14 +++++---- .../schema/CreateDseKeyspaceTest.java | 14 +++++---- .../schema/CreateDseTableTest.java | 14 +++++---- .../querybuilder/DependencyCheckTest.java | 14 +++++---- .../schema/CreateDseAggregateTest.java | 14 +++++---- .../schema/CreateDseFunctionTest.java | 14 +++++---- .../driver/api/querybuilder/Assertions.java | 14 +++++---- .../querybuilder/BuildableQueryAssert.java | 14 +++++---- .../api/querybuilder/BuildableQueryTest.java | 14 +++++---- .../driver/api/querybuilder/CharsetCodec.java | 14 +++++---- .../api/querybuilder/CqlSnippetAssert.java | 14 +++++---- .../api/querybuilder/TokenLiteralTest.java | 14 +++++---- .../querybuilder/condition/ConditionTest.java | 14 +++++---- .../delete/DeleteFluentConditionTest.java | 14 +++++---- .../delete/DeleteFluentRelationTest.java | 14 +++++---- .../delete/DeleteIdempotenceTest.java | 14 +++++---- .../delete/DeleteSelectorTest.java | 14 +++++---- .../delete/DeleteTimestampTest.java | 14 +++++---- .../insert/InsertIdempotenceTest.java | 14 +++++---- .../querybuilder/insert/JsonInsertTest.java | 14 +++++---- .../insert/RegularInsertTest.java | 14 +++++---- .../querybuilder/relation/RelationTest.java | 14 +++++---- .../api/querybuilder/relation/TermTest.java | 14 +++++---- .../schema/AlterKeyspaceTest.java | 14 +++++---- .../schema/AlterMaterializedViewTest.java | 14 +++++---- .../querybuilder/schema/AlterTableTest.java | 14 +++++---- .../querybuilder/schema/AlterTypeTest.java | 14 +++++---- .../schema/CreateAggregateTest.java | 14 +++++---- .../schema/CreateFunctionTest.java | 14 +++++---- .../querybuilder/schema/CreateIndexTest.java | 14 +++++---- .../schema/CreateKeyspaceTest.java | 14 +++++---- .../schema/CreateMaterializedViewTest.java | 14 +++++---- .../querybuilder/schema/CreateTableTest.java | 14 +++++---- .../querybuilder/schema/CreateTypeTest.java | 14 +++++---- .../schema/DropAggregateTest.java | 14 +++++---- .../querybuilder/schema/DropFunctionTest.java | 14 +++++---- .../querybuilder/schema/DropIndexTest.java | 14 +++++---- .../querybuilder/schema/DropKeyspaceTest.java | 14 +++++---- .../schema/DropMaterializedViewTest.java | 14 +++++---- .../querybuilder/schema/DropTableTest.java | 14 +++++---- .../api/querybuilder/schema/DropTypeTest.java | 14 +++++---- .../select/SelectAllowFilteringTest.java | 14 +++++---- .../select/SelectFluentRelationTest.java | 14 +++++---- .../select/SelectGroupByTest.java | 14 +++++---- .../querybuilder/select/SelectLimitTest.java | 14 +++++---- .../select/SelectOrderingTest.java | 14 +++++---- .../select/SelectSelectorTest.java | 14 +++++---- .../querybuilder/truncate/TruncateTest.java | 14 +++++---- .../update/UpdateFluentAssignmentTest.java | 14 +++++---- .../update/UpdateFluentConditionTest.java | 14 +++++---- .../update/UpdateFluentRelationTest.java | 14 +++++---- .../update/UpdateIdempotenceTest.java | 14 +++++---- .../querybuilder/update/UpdateUsingTest.java | 14 +++++---- .../src/test/resources/project.properties | 14 +++++---- test-infra/pom.xml | 16 +++++----- .../api/testinfra/CassandraRequirement.java | 14 +++++---- .../api/testinfra/CassandraResourceRule.java | 14 +++++---- .../driver/api/testinfra/DseRequirement.java | 14 +++++---- .../driver/api/testinfra/ccm/BaseCcmRule.java | 14 +++++---- .../driver/api/testinfra/ccm/CcmBridge.java | 14 +++++---- .../oss/driver/api/testinfra/ccm/CcmRule.java | 14 +++++---- .../api/testinfra/ccm/CustomCcmRule.java | 14 +++++---- .../DefaultCcmBridgeBuilderCustomizer.java | 14 +++++---- .../loadbalancing/NodeComparator.java | 14 +++++---- .../SortingLoadBalancingPolicy.java | 14 +++++---- .../requirement/BackendRequirement.java | 14 +++++---- .../requirement/BackendRequirementRule.java | 14 +++++---- .../requirement/BackendRequirements.java | 14 +++++---- .../testinfra/requirement/BackendType.java | 14 +++++---- .../requirement/VersionRequirement.java | 14 +++++---- .../session/CqlSessionRuleBuilder.java | 14 +++++---- .../api/testinfra/session/SessionRule.java | 14 +++++---- .../testinfra/session/SessionRuleBuilder.java | 14 +++++---- .../api/testinfra/session/SessionUtils.java | 14 +++++---- .../testinfra/simulacron/QueryCounter.java | 14 +++++---- .../testinfra/simulacron/SimulacronRule.java | 14 +++++---- .../api/testinfra/utils/ConditionChecker.java | 14 +++++---- .../driver/api/testinfra/utils/NodeUtils.java | 14 +++++---- .../oss/driver/assertions/Assertions.java | 14 +++++---- .../driver/assertions/NodeMetadataAssert.java | 14 +++++---- .../oss/driver/categories/IsolatedTests.java | 14 +++++---- .../categories/ParallelizableTests.java | 14 +++++---- .../requirement/VersionRequirementTest.java | 14 +++++---- upgrade_guide/README.md | 6 ++-- 1907 files changed, 15235 insertions(+), 11430 deletions(-) create mode 100644 NOTICE.txt diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 00000000000..477f0645ed9 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,20 @@ +Apache Cassandra Java Driver +Copyright 2012- The Apache Software Foundation + +This product includes software developed by The Apache Software +Foundation (http://www.apache.org/). + +JNR project +Copyright (C) 2008-2010 Wayne Meissner +This product includes software developed as part of the JNR project ( https://github.com/jnr/jnr-ffi )s. +see core/src/main/java/com/datastax/oss/driver/internal/core/os/CpuInfo.java + +Protocol Buffers +Copyright 2008 Google Inc. +This product includes software developed as part of the Protocol Buffers project ( https://developers.google.com/protocol-buffers/ ). +see core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java + +Guava +Copyright (C) 2007 The Guava Authors +This product includes software developed as part of the Guava project ( https://guava.dev ). +see core/src/main/java/com/datastax/oss/driver/internal/core/util/CountingIterator.java \ No newline at end of file diff --git a/README.md b/README.md index e8a85027ab9..78aee1887db 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# DataStax Java Driver for Apache Cassandra® +# Java Driver for Apache Cassandra® [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core) @@ -66,14 +66,14 @@ offering. See the dedicated [manual page](manual/cloud/) for more details. ## Migrating from previous versions -Java driver 4 is **not binary compatible** with previous versions. However, most of the concepts +Java Driver 4 is **not binary compatible** with previous versions. However, most of the concepts remain unchanged, and the new API will look very familiar to 2.x and 3.x users. See the [upgrade guide](upgrade_guide/) for details. ## Error Handling -See the [Cassandra error handling done right blog](https://www.datastax.com/blog/cassandra-error-handling-done-right) for error handling with the DataStax Java Driver for Apache Cassandra™. +See the [Cassandra error handling done right blog](https://www.datastax.com/blog/cassandra-error-handling-done-right) for error handling with the Java Driver for Apache Cassandra™. ## Useful links @@ -81,7 +81,7 @@ See the [Cassandra error handling done right blog](https://www.datastax.com/blog * [API docs] * Bug tracking: [JIRA] * [Mailing list] -* Twitter: [@dsJavaDriver] tweets Java driver releases and important announcements (low frequency). +* Twitter: [@dsJavaDriver] tweets Java Driver releases and important announcements (low frequency). [@DataStaxEng] has more news, including other drivers, Cassandra, and DSE. * [Changelog] * [FAQ] diff --git a/bom/pom.xml b/bom/pom.xml index a60b9903fdc..33c454fcf75 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1,13 +1,15 @@ jar - DataStax Java driver for Apache Cassandra(R) - binary distribution + Apache Cassandra Java Driver - binary distribution + + 4.0.0 + + com.datastax.oss + java-driver-parent + 4.17.1-SNAPSHOT + + java-driver-distribution-tests + Apache Cassandra Java Driver - distribution tests + + + + ${project.groupId} + java-driver-bom + ${project.version} + pom + import + + + + + + com.datastax.oss + java-driver-test-infra + test + + + com.datastax.oss + java-driver-query-builder + test + + + com.datastax.oss + java-driver-mapper-processor + test + + + com.datastax.oss + java-driver-mapper-runtime + test + + + com.datastax.oss + java-driver-core + test + + + com.datastax.oss + java-driver-metrics-micrometer + test + + + com.datastax.oss + java-driver-metrics-microprofile + test + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${testing.jvm}/bin/java + ${mockitoopens.argline} + 1 + + + + org.revapi + revapi-maven-plugin + + true + + + + maven-install-plugin + + true + + + + maven-deploy-plugin + + true + + + + org.sonatype.plugins + nexus-staging-maven-plugin + + true + + + + + diff --git a/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/DriverDependencyTest.java b/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/DriverDependencyTest.java new file mode 100644 index 00000000000..16952e3d771 --- /dev/null +++ b/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/DriverDependencyTest.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.api.mapper.MapperBuilder; +import com.datastax.oss.driver.api.querybuilder.QueryBuilder; +import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; +import com.datastax.oss.driver.internal.core.util.Reflection; +import com.datastax.oss.driver.internal.mapper.processor.MapperProcessor; +import com.datastax.oss.driver.internal.metrics.micrometer.MicrometerMetricsFactory; +import com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileMetricsFactory; +import org.junit.Test; + +public class DriverDependencyTest { + @Test + public void should_include_core_jar() { + assertThat(Reflection.loadClass(null, "com.datastax.oss.driver.api.core.session.Session")) + .isEqualTo(Session.class); + } + + @Test + public void should_include_query_builder_jar() { + assertThat(Reflection.loadClass(null, "com.datastax.oss.driver.api.querybuilder.QueryBuilder")) + .isEqualTo(QueryBuilder.class); + } + + @Test + public void should_include_mapper_processor_jar() { + assertThat( + Reflection.loadClass( + null, "com.datastax.oss.driver.internal.mapper.processor.MapperProcessor")) + .isEqualTo(MapperProcessor.class); + } + + @Test + public void should_include_mapper_runtime_jar() { + assertThat(Reflection.loadClass(null, "com.datastax.oss.driver.api.mapper.MapperBuilder")) + .isEqualTo(MapperBuilder.class); + } + + @Test + public void should_include_metrics_micrometer_jar() { + assertThat( + Reflection.loadClass( + null, + "com.datastax.oss.driver.internal.metrics.micrometer.MicrometerMetricsFactory")) + .isEqualTo(MicrometerMetricsFactory.class); + } + + @Test + public void should_include_metrics_microprofile_jar() { + assertThat( + Reflection.loadClass( + null, + "com.datastax.oss.driver.internal.metrics.microprofile.MicroProfileMetricsFactory")) + .isEqualTo(MicroProfileMetricsFactory.class); + } + + @Test + public void should_include_test_infra_jar() { + assertThat( + Reflection.loadClass( + null, "com.datastax.oss.driver.api.testinfra.CassandraResourceRule")) + .isEqualTo(CassandraResourceRule.class); + } +} diff --git a/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/OptionalDependencyTest.java b/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/OptionalDependencyTest.java new file mode 100644 index 00000000000..28626413487 --- /dev/null +++ b/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/OptionalDependencyTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.internal.core.util.Dependency; +import com.datastax.oss.driver.internal.core.util.Reflection; +import org.junit.Test; + +public class OptionalDependencyTest { + @Test + public void should_not_include_snappy_jar() { + Dependency.SNAPPY + .classes() + .forEach(clazz -> assertThat(Reflection.loadClass(null, clazz)).isNull()); + } + + @Test + public void should_not_include_l4z_jar() { + Dependency.LZ4 + .classes() + .forEach(clazz -> assertThat(Reflection.loadClass(null, clazz)).isNull()); + } + + @Test + public void should_not_include_esri_jar() { + Dependency.ESRI + .classes() + .forEach(clazz -> assertThat(Reflection.loadClass(null, clazz)).isNull()); + } + + @Test + public void should_not_include_tinkerpop_jar() { + Dependency.TINKERPOP + .classes() + .forEach(clazz -> assertThat(Reflection.loadClass(null, clazz)).isNull()); + } +} diff --git a/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/ProvidedDependencyTest.java b/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/ProvidedDependencyTest.java new file mode 100644 index 00000000000..1070bbc2fb1 --- /dev/null +++ b/distribution-tests/src/test/java/com/datastax/oss/driver/api/core/ProvidedDependencyTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.internal.core.util.Reflection; +import org.junit.Test; + +public class ProvidedDependencyTest { + @Test + public void should_not_include_graal_sdk_jar() { + assertThat(Reflection.loadClass(null, "org.graalvm.nativeimage.VMRuntime")).isNull(); + } + + @Test + public void should_not_include_spotbugs_annotations_jar() { + assertThat(Reflection.loadClass(null, "edu.umd.cs.findbugs.annotations.NonNull")).isNull(); + } + + @Test + public void should_not_include_jicp_annotations_jar() { + assertThat(Reflection.loadClass(null, "net.jcip.annotations.ThreadSafe")).isNull(); + } + + @Test + public void should_not_include_blockhound_jar() { + assertThat(Reflection.loadClass(null, "reactor.blockhound.BlockHoundRuntime")).isNull(); + } +} diff --git a/examples/pom.xml b/examples/pom.xml index ec87d205ad8..a597f634d9a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -142,6 +142,11 @@ io.projectreactor reactor-core + + com.github.spotbugs + spotbugs-annotations + provided + diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 73c7e77b2c4..db77efb5166 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -83,6 +83,11 @@ java-driver-metrics-microprofile test + + com.github.stephenc.jcip + jcip-annotations + test + com.github.spotbugs spotbugs-annotations diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 37e04b230a2..16ed68f9e9b 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -610,25 +610,22 @@ The driver team uses annotations to document certain aspects of the code: * nullability with [SpotBugs](https://spotbugs.github.io/) annotations `@Nullable` and `@NonNull`. This is mostly used during development; while these annotations are retained in class files, they -serve no purpose at runtime. If you want to minimize the number of JARs in your classpath, you can -exclude them: +serve no purpose at runtime. This class is an optional dependency of the driver. If you wish to +make use of these annotations in your own code you have to explicitly depend on these jars: ```xml - - com.datastax.oss - java-driver-core - ${driver.version} - - - com.github.stephenc.jcip - jcip-annotations - - - com.github.spotbugs - spotbugs-annotations - - - + + + com.github.stephenc.jcip + jcip-annotations + 1.0-1 + + + com.github.spotbugs + spotbugs-annotations + 3.1.12 + + ``` However, there is one case when excluding those dependencies won't work: if you use [annotation diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 9f6c2572554..f9814b3dea4 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -54,10 +54,12 @@ com.github.stephenc.jcip jcip-annotations + provided com.github.spotbugs spotbugs-annotations + provided com.google.testing.compile diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 0b9bf61928f..3957bbe1505 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -51,10 +51,12 @@ com.github.stephenc.jcip jcip-annotations + provided com.github.spotbugs spotbugs-annotations + provided junit diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index e7751bafa61..1c28b636b86 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -59,6 +59,16 @@ + + com.github.stephenc.jcip + jcip-annotations + provided + + + com.github.spotbugs + spotbugs-annotations + provided + ch.qos.logback logback-classic diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 15b2818141d..0d2d5873330 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -59,6 +59,16 @@ + + com.github.stephenc.jcip + jcip-annotations + provided + + + com.github.spotbugs + spotbugs-annotations + provided + io.smallrye smallrye-metrics diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 366555fd995..a5085050930 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -56,9 +56,15 @@ com.datastax.oss java-driver-mapper-runtime + + com.github.stephenc.jcip + jcip-annotations + provided + com.github.spotbugs spotbugs-annotations + provided ch.qos.logback diff --git a/pom.xml b/pom.xml index 2d366502f3e..71ecd2a7915 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,7 @@ integration-tests osgi-tests distribution + distribution-tests examples bom diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 504596140d6..5ecbebf367b 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -51,10 +51,12 @@ com.github.stephenc.jcip jcip-annotations + provided com.github.spotbugs spotbugs-annotations + provided junit diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 21f8605a441..cf1da84f7dd 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -48,7 +48,7 @@ com.github.spotbugs spotbugs-annotations - true + provided junit From e4429a20e4620739297933b54edba5cfb874de92 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Fri, 10 Nov 2023 13:46:58 -0800 Subject: [PATCH 286/395] Changes as per RAT patch by Claude Warren; reviewed by Henry Hughes, Mick Semb Wever for CASSANDRA-18969 --- .asf.yaml | 17 +++++++++++++++ .snyk | 16 ++++++++++++++ .snyk.ignore.example | 9 -------- .travis.yml | 17 +++++++++++++++ CONTRIBUTING.md | 19 +++++++++++++++++ Jenkinsfile | 18 ++++++++++++++++ changelog/README.md | 19 +++++++++++++++++ core/console.scala | 21 ++++++++++++++++++- .../java-driver-core/native-image.properties | 17 +++++++++++++++ core/src/main/resources/reference.conf | 17 +++++++++++++++ core/src/test/resources/application.conf | 19 ++++++++++++++++- .../resources/config/customApplication.conf | 17 +++++++++++++++ docs.yaml | 17 +++++++++++++++ examples/README.md | 19 +++++++++++++++++ examples/src/main/resources/application.conf | 19 ++++++++++++++++- .../src/main/resources/killrvideo_schema.cql | 19 +++++++++++++++++ faq/README.md | 19 +++++++++++++++++ install-snapshots.sh | 16 ++++++++++++++ .../src/test/resources/DescribeIT/dse/4.8.cql | 21 ++++++++++++++++++- .../src/test/resources/DescribeIT/dse/5.0.cql | 21 ++++++++++++++++++- .../src/test/resources/DescribeIT/dse/5.1.cql | 21 ++++++++++++++++++- .../src/test/resources/DescribeIT/dse/6.8.cql | 19 +++++++++++++++++ .../src/test/resources/DescribeIT/oss/2.1.cql | 21 ++++++++++++++++++- .../src/test/resources/DescribeIT/oss/2.2.cql | 21 ++++++++++++++++++- .../src/test/resources/DescribeIT/oss/3.0.cql | 21 ++++++++++++++++++- .../test/resources/DescribeIT/oss/3.11.cql | 21 ++++++++++++++++++- .../src/test/resources/DescribeIT/oss/4.0.cql | 19 +++++++++++++++++ .../src/test/resources/application.conf | 19 ++++++++++++++++- manual/README.md | 21 ++++++++++++++++++- manual/api_conventions/README.md | 21 ++++++++++++++++++- manual/case_sensitivity/README.md | 21 ++++++++++++++++++- manual/cloud/README.md | 19 +++++++++++++++++ manual/core/README.md | 21 ++++++++++++++++++- manual/core/address_resolution/README.md | 19 +++++++++++++++++ manual/core/async/README.md | 21 ++++++++++++++++++- manual/core/authentication/README.md | 21 ++++++++++++++++++- manual/core/bom/README.md | 19 +++++++++++++++++ manual/core/compression/README.md | 21 ++++++++++++++++++- manual/core/configuration/README.md | 19 +++++++++++++++++ .../core/configuration/reference/README.rst | 18 ++++++++++++++++ manual/core/control_connection/README.md | 21 ++++++++++++++++++- manual/core/custom_codecs/README.md | 21 ++++++++++++++++++- manual/core/detachable_types/README.md | 19 +++++++++++++++++ manual/core/dse/README.md | 19 +++++++++++++++++ manual/core/dse/geotypes/README.md | 19 +++++++++++++++++ manual/core/dse/graph/README.md | 19 +++++++++++++++++ manual/core/dse/graph/fluent/README.md | 19 +++++++++++++++++ .../core/dse/graph/fluent/explicit/README.md | 19 +++++++++++++++++ .../core/dse/graph/fluent/implicit/README.md | 19 +++++++++++++++++ manual/core/dse/graph/options/README.md | 21 ++++++++++++++++++- manual/core/dse/graph/results/README.md | 21 ++++++++++++++++++- manual/core/dse/graph/script/README.md | 21 ++++++++++++++++++- manual/core/graalvm/README.md | 19 +++++++++++++++++ manual/core/idempotence/README.md | 19 +++++++++++++++++ manual/core/integration/README.md | 19 +++++++++++++++++ manual/core/load_balancing/README.md | 19 +++++++++++++++++ manual/core/logging/README.md | 21 ++++++++++++++++++- manual/core/metadata/README.md | 21 ++++++++++++++++++- manual/core/metadata/node/README.md | 19 +++++++++++++++++ manual/core/metadata/schema/README.md | 19 +++++++++++++++++ manual/core/metadata/token/README.md | 21 ++++++++++++++++++- manual/core/metrics/README.md | 21 ++++++++++++++++++- manual/core/native_protocol/README.md | 19 +++++++++++++++++ manual/core/non_blocking/README.md | 19 +++++++++++++++++ manual/core/paging/README.md | 19 +++++++++++++++++ manual/core/performance/README.md | 21 ++++++++++++++++++- manual/core/pooling/README.md | 21 ++++++++++++++++++- manual/core/query_timestamps/README.md | 19 +++++++++++++++++ manual/core/reactive/README.md | 19 +++++++++++++++++ manual/core/reconnection/README.md | 21 ++++++++++++++++++- manual/core/request_tracker/README.md | 21 ++++++++++++++++++- manual/core/retries/README.md | 19 +++++++++++++++++ manual/core/shaded_jar/README.md | 19 +++++++++++++++++ manual/core/speculative_execution/README.md | 21 ++++++++++++++++++- manual/core/ssl/README.md | 19 +++++++++++++++++ manual/core/statements/README.md | 19 +++++++++++++++++ manual/core/statements/batch/README.md | 19 +++++++++++++++++ .../statements/per_query_keyspace/README.md | 21 ++++++++++++++++++- manual/core/statements/prepared/README.md | 19 +++++++++++++++++ manual/core/statements/simple/README.md | 19 +++++++++++++++++ manual/core/temporal_types/README.md | 21 ++++++++++++++++++- manual/core/throttling/README.md | 21 ++++++++++++++++++- manual/core/tracing/README.md | 19 +++++++++++++++++ manual/core/tuples/README.md | 19 +++++++++++++++++ manual/core/udts/README.md | 21 ++++++++++++++++++- manual/developer/README.md | 21 ++++++++++++++++++- manual/developer/admin/README.md | 21 ++++++++++++++++++- manual/developer/common/README.md | 19 +++++++++++++++++ manual/developer/common/concurrency/README.md | 19 +++++++++++++++++ manual/developer/common/context/README.md | 19 +++++++++++++++++ manual/developer/common/event_bus/README.md | 19 +++++++++++++++++ manual/developer/native_protocol/README.md | 19 +++++++++++++++++ manual/developer/netty_pipeline/README.md | 21 ++++++++++++++++++- manual/developer/request_execution/README.md | 19 +++++++++++++++++ manual/mapper/README.md | 19 +++++++++++++++++ manual/mapper/config/README.md | 19 +++++++++++++++++ manual/mapper/config/kotlin/README.md | 19 +++++++++++++++++ manual/mapper/config/lombok/README.md | 19 +++++++++++++++++ manual/mapper/config/record/README.md | 19 +++++++++++++++++ manual/mapper/config/scala/README.md | 19 +++++++++++++++++ manual/mapper/daos/README.md | 19 +++++++++++++++++ manual/mapper/daos/custom_types/README.md | 19 +++++++++++++++++ manual/mapper/daos/delete/README.md | 21 ++++++++++++++++++- manual/mapper/daos/getentity/README.md | 19 +++++++++++++++++ manual/mapper/daos/increment/README.md | 19 +++++++++++++++++ manual/mapper/daos/insert/README.md | 19 +++++++++++++++++ manual/mapper/daos/null_saving/README.md | 19 +++++++++++++++++ manual/mapper/daos/query/README.md | 19 +++++++++++++++++ manual/mapper/daos/queryprovider/README.md | 19 +++++++++++++++++ manual/mapper/daos/select/README.md | 19 +++++++++++++++++ manual/mapper/daos/setentity/README.md | 19 +++++++++++++++++ .../daos/statement_attributes/README.md | 21 ++++++++++++++++++- manual/mapper/daos/update/README.md | 19 +++++++++++++++++ manual/mapper/entities/README.md | 19 +++++++++++++++++ manual/mapper/mapper/README.md | 19 +++++++++++++++++ manual/osgi/README.md | 19 +++++++++++++++++ manual/query_builder/README.md | 19 +++++++++++++++++ manual/query_builder/condition/README.md | 19 +++++++++++++++++ manual/query_builder/delete/README.md | 19 +++++++++++++++++ manual/query_builder/idempotence/README.md | 21 ++++++++++++++++++- manual/query_builder/insert/README.md | 21 ++++++++++++++++++- manual/query_builder/relation/README.md | 19 +++++++++++++++++ manual/query_builder/schema/README.md | 19 +++++++++++++++++ .../query_builder/schema/aggregate/README.md | 19 +++++++++++++++++ .../query_builder/schema/function/README.md | 19 +++++++++++++++++ manual/query_builder/schema/index/README.md | 19 +++++++++++++++++ .../query_builder/schema/keyspace/README.md | 19 +++++++++++++++++ .../schema/materialized_view/README.md | 19 +++++++++++++++++ manual/query_builder/schema/table/README.md | 19 +++++++++++++++++ manual/query_builder/schema/type/README.md | 19 +++++++++++++++++ manual/query_builder/select/README.md | 19 +++++++++++++++++ manual/query_builder/term/README.md | 21 ++++++++++++++++++- manual/query_builder/truncate/README.md | 19 +++++++++++++++++ manual/query_builder/update/README.md | 19 +++++++++++++++++ mapper-processor/CONTRIBUTING.md | 19 +++++++++++++++++ .../native-image.properties | 17 +++++++++++++++ .../native-image.properties | 17 +++++++++++++++ osgi-tests/README.md | 21 ++++++++++++++++++- .../src/main/resources/application.conf | 19 ++++++++++++++++- performance/README.md | 19 +++++++++++++++++ performance/duration-test.yaml | 17 +++++++++++++++ performance/graphite-setup.yaml | 17 +++++++++++++++ pre-commit.sh | 16 ++++++++++++++ upgrade_guide/README.md | 19 +++++++++++++++++ 144 files changed, 2724 insertions(+), 55 deletions(-) delete mode 100644 .snyk.ignore.example diff --git a/.asf.yaml b/.asf.yaml index c6549f8ee81..5ebca4b6e33 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + notifications: commits: commits@cassandra.apache.org issues: commits@cassandra.apache.org diff --git a/.snyk b/.snyk index 3c6284addca..a081b17225c 100644 --- a/.snyk +++ b/.snyk @@ -1,3 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.22.2 # ignores vulnerabilities until expiry date; change duration by modifying expiry date diff --git a/.snyk.ignore.example b/.snyk.ignore.example deleted file mode 100644 index a4690b27223..00000000000 --- a/.snyk.ignore.example +++ /dev/null @@ -1,9 +0,0 @@ -# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. -version: v1.22.2 -# ignores vulnerabilities until expiry date; change duration by modifying expiry date -ignore: - SNYK-PYTHON-URLLIB3-1533435: - - '*': - reason: state your ignore reason here - expires: 2030-01-01T00:00:00.000Z - created: 2022-03-21T00:00:00.000Z \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 7b868941bc3..84d40ce1356 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + language: java dist: trusty sudo: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 927c7a7aa8c..53857383cf2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,22 @@ + + # Contributing guidelines ## Code formatting diff --git a/Jenkinsfile b/Jenkinsfile index 3ecb70e0d30..c8247769631 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,22 @@ #!groovy +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ def initializeEnvironment() { env.DRIVER_DISPLAY_NAME = 'CassandraⓇ Java Driver' diff --git a/changelog/README.md b/changelog/README.md index 54d0d7a6c37..8ff2913b72d 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -1,3 +1,22 @@ + + ## Changelog diff --git a/core/console.scala b/core/console.scala index 0ae13620ff8..491add7edea 100644 --- a/core/console.scala +++ b/core/console.scala @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* * Allows quick manual tests from the Scala console: * @@ -36,4 +55,4 @@ println("********************************************") def fire(event: AnyRef)(implicit session: CqlSession): Unit = { session.getContext.asInstanceOf[InternalDriverContext].getEventBus().fire(event) -} \ No newline at end of file +} diff --git a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties index 7900d35f81a..2baa59f3b07 100644 --- a/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties +++ b/core/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-core/native-image.properties @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + Args=-H:IncludeResources=reference\\.conf \ -H:IncludeResources=application\\.conf \ -H:IncludeResources=application\\.json \ diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index d9cd8e079d2..9e4fb9c7948 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # Reference configuration for the Java Driver for Apache Cassandra®. # # Unless you use a custom mechanism to load your configuration (see diff --git a/core/src/test/resources/application.conf b/core/src/test/resources/application.conf index 75cd8820639..efea37cc078 100644 --- a/core/src/test/resources/application.conf +++ b/core/src/test/resources/application.conf @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + datastax-java-driver { basic.request.timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} -} \ No newline at end of file +} diff --git a/core/src/test/resources/config/customApplication.conf b/core/src/test/resources/config/customApplication.conf index 92b5f492b9c..c3e3dc7b468 100644 --- a/core/src/test/resources/config/customApplication.conf +++ b/core/src/test/resources/config/customApplication.conf @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + datastax-java-driver { // Check that references to other options in `reference.conf` are correctly resolved basic.request.timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} diff --git a/docs.yaml b/docs.yaml index 0731c398a1b..7c679a0f47e 100644 --- a/docs.yaml +++ b/docs.yaml @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + title: Java Driver summary: Java Driver for Apache Cassandra® homepage: http://docs.datastax.com/en/developer/java-driver diff --git a/examples/README.md b/examples/README.md index 5c8df3d2568..9d2210d8a4a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,3 +1,22 @@ + + # Java Driver for Apache Cassandra(R) - Examples This module contains examples of how to use the Java Driver for diff --git a/examples/src/main/resources/application.conf b/examples/src/main/resources/application.conf index 12cb19a84d0..170c08d973a 100644 --- a/examples/src/main/resources/application.conf +++ b/examples/src/main/resources/application.conf @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + datastax-java-driver { basic.contact-points = ["127.0.0.1:9042"] basic { @@ -19,4 +36,4 @@ datastax-java-driver { basic.request.timeout = 10 seconds } } -} \ No newline at end of file +} diff --git a/examples/src/main/resources/killrvideo_schema.cql b/examples/src/main/resources/killrvideo_schema.cql index 24728d550d0..0c604ba5922 100644 --- a/examples/src/main/resources/killrvideo_schema.cql +++ b/examples/src/main/resources/killrvideo_schema.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // User credentials, keyed by email address so we can authenticate CREATE TABLE IF NOT EXISTS user_credentials ( email text, diff --git a/faq/README.md b/faq/README.md index 315bf934cd2..97cb4decd00 100644 --- a/faq/README.md +++ b/faq/README.md @@ -1,3 +1,22 @@ + + ## Frequently asked questions ### I'm modifying a statement and the changes get ignored, why? diff --git a/install-snapshots.sh b/install-snapshots.sh index 4f5d79665ab..795b4098f52 100755 --- a/install-snapshots.sh +++ b/install-snapshots.sh @@ -1,4 +1,20 @@ #!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. # Install dependencies in the Travis build environment if they are snapshots. # See .travis.yml diff --git a/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql b/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql index 05408ba0924..35eee187776 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -63,4 +82,4 @@ CREATE TABLE ks_0.ztable ( AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 AND read_repair_chance = 0.0 - AND speculative_retry = '99.0PERCENTILE'; \ No newline at end of file + AND speculative_retry = '99.0PERCENTILE'; diff --git a/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql b/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql index 25b42c58d68..077c9dd1399 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -185,4 +204,4 @@ CREATE AGGREGATE ks_0.mean(int) SFUNC avgstate STYPE tuple FINALFUNC avgfinal - INITCOND (0,0); \ No newline at end of file + INITCOND (0,0); diff --git a/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql b/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql index 25b42c58d68..077c9dd1399 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -185,4 +204,4 @@ CREATE AGGREGATE ks_0.mean(int) SFUNC avgstate STYPE tuple FINALFUNC avgfinal - INITCOND (0,0); \ No newline at end of file + INITCOND (0,0); diff --git a/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql b/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql index 416c397ba97..76871de4e1f 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( diff --git a/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql b/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql index 05408ba0924..35eee187776 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -63,4 +82,4 @@ CREATE TABLE ks_0.ztable ( AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 AND read_repair_chance = 0.0 - AND speculative_retry = '99.0PERCENTILE'; \ No newline at end of file + AND speculative_retry = '99.0PERCENTILE'; diff --git a/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql b/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql index 5b4442133c3..e35703b30cc 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -110,4 +129,4 @@ CREATE AGGREGATE ks_0.mean(int) SFUNC avgstate STYPE tuple FINALFUNC avgfinal - INITCOND (0,0); \ No newline at end of file + INITCOND (0,0); diff --git a/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql b/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql index 25b42c58d68..077c9dd1399 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -185,4 +204,4 @@ CREATE AGGREGATE ks_0.mean(int) SFUNC avgstate STYPE tuple FINALFUNC avgfinal - INITCOND (0,0); \ No newline at end of file + INITCOND (0,0); diff --git a/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql b/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql index 25b42c58d68..077c9dd1399 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( @@ -185,4 +204,4 @@ CREATE AGGREGATE ks_0.mean(int) SFUNC avgstate STYPE tuple FINALFUNC avgfinal - INITCOND (0,0); \ No newline at end of file + INITCOND (0,0); diff --git a/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql b/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql index 15ff0f5e9dc..a78bed4b816 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; CREATE TYPE ks_0.btype ( diff --git a/integration-tests/src/test/resources/application.conf b/integration-tests/src/test/resources/application.conf index 668a71059cf..f3ab31bcb76 100644 --- a/integration-tests/src/test/resources/application.conf +++ b/integration-tests/src/test/resources/application.conf @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # Configuration overrides for integration tests datastax-java-driver { basic { @@ -45,4 +62,4 @@ datastax-java-driver { } } } -} \ No newline at end of file +} diff --git a/manual/README.md b/manual/README.md index c3111debe2f..049ddc8c8e9 100644 --- a/manual/README.md +++ b/manual/README.md @@ -1,3 +1,22 @@ + + ## Manual Driver modules: @@ -14,4 +33,4 @@ Common topics: * [API conventions](api_conventions/) * [Case sensitivity](case_sensitivity/) * [OSGi](osgi/) -* [Cloud](cloud/) \ No newline at end of file +* [Cloud](cloud/) diff --git a/manual/api_conventions/README.md b/manual/api_conventions/README.md index a76067ebef2..553392658dd 100644 --- a/manual/api_conventions/README.md +++ b/manual/api_conventions/README.md @@ -1,3 +1,22 @@ + + ## API conventions In previous versions, the driver relied solely on Java visibility rules: everything was either @@ -41,4 +60,4 @@ internalContext.getEventBus().fire(TopologyEvent.forceDown(address)); So the risk of unintentionally using the internal API is very low. To double-check, you can always grep `import com.datastax.oss.driver.internal` in your source files. -[semantic versioning]: http://semver.org/ \ No newline at end of file +[semantic versioning]: http://semver.org/ diff --git a/manual/case_sensitivity/README.md b/manual/case_sensitivity/README.md index 7430b65eabd..e9dbf1bf9a8 100644 --- a/manual/case_sensitivity/README.md +++ b/manual/case_sensitivity/README.md @@ -1,3 +1,22 @@ + + ## Case sensitivity ### In Cassandra @@ -130,4 +149,4 @@ If you worry about readability, use snake case (`shopping_cart`), or simply stic The only reason to use case sensitivity should be if you don't control the data model. In that case, either pass quoted strings to the driver, or use `CqlIdentifier` instances (stored as -constants to avoid creating them over and over). \ No newline at end of file +constants to avoid creating them over and over). diff --git a/manual/cloud/README.md b/manual/cloud/README.md index 5149f140708..48197c49425 100644 --- a/manual/cloud/README.md +++ b/manual/cloud/README.md @@ -1,3 +1,22 @@ + + ## Connecting to Astra (Cloud) Using the Java Driver to connect to a DataStax Astra database is almost identical to using diff --git a/manual/core/README.md b/manual/core/README.md index a11c5e624be..a8f97cc4106 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -1,3 +1,22 @@ + + ## Core driver The core module handles cluster connectivity and request execution. It is published under the @@ -330,4 +349,4 @@ for (ColumnDefinitions.Definition definition : row.getColumnDefinitions()) { [SessionBuilder.addContactPoints()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addContactPoints-java.util.Collection- [SessionBuilder.withLocalDatacenter()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withLocalDatacenter-java.lang.String- -[CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file +[CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index 433ffe58a75..84efb4a796c 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -1,3 +1,22 @@ + + ## Address resolution ### Quick overview diff --git a/manual/core/async/README.md b/manual/core/async/README.md index d64ee2c9b85..5b4bac3dccf 100644 --- a/manual/core/async/README.md +++ b/manual/core/async/README.md @@ -1,3 +1,22 @@ + + ## Asynchronous programming ### Quick overview @@ -207,4 +226,4 @@ documentation for more details and an example. [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html \ No newline at end of file +[AsyncResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html diff --git a/manual/core/authentication/README.md b/manual/core/authentication/README.md index ebb52bfc5a8..516e47f558f 100644 --- a/manual/core/authentication/README.md +++ b/manual/core/authentication/README.md @@ -1,3 +1,22 @@ + + ## Authentication ### Quick overview @@ -236,4 +255,4 @@ session.execute(statement); [ProxyAuthentication.executeAs]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/auth/ProxyAuthentication.html#executeAs-java.lang.String-StatementT- [SessionBuilder.withAuthCredentials]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthCredentials-java.lang.String-java.lang.String- [SessionBuilder.withAuthProvider]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withAuthProvider-com.datastax.oss.driver.api.core.auth.AuthProvider- -[reference.conf]: ../configuration/reference/ \ No newline at end of file +[reference.conf]: ../configuration/reference/ diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index d0797264263..b2a8f205554 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -1,3 +1,22 @@ + + ## Bill of Materials (BOM) A "Bill Of Materials" is a special Maven descriptor that defines the versions of a set of related diff --git a/manual/core/compression/README.md b/manual/core/compression/README.md index 0697ea1737b..9e84fde917d 100644 --- a/manual/core/compression/README.md +++ b/manual/core/compression/README.md @@ -1,3 +1,22 @@ + + ## Compression ### Quick overview @@ -82,4 +101,4 @@ Dependency: Always double-check the exact Snappy version needed; you can find it in the driver's [parent POM]. -[parent POM]: https://search.maven.org/search?q=g:com.datastax.oss%20AND%20a:java-driver-parent&core=gav \ No newline at end of file +[parent POM]: https://search.maven.org/search?q=g:com.datastax.oss%20AND%20a:java-driver-parent&core=gav diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index bccfb7d3fce..a30b79842bb 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -1,3 +1,22 @@ + + ## Configuration ### Quick overview diff --git a/manual/core/configuration/reference/README.rst b/manual/core/configuration/reference/README.rst index e6da9306a75..d4989ecf641 100644 --- a/manual/core/configuration/reference/README.rst +++ b/manual/core/configuration/reference/README.rst @@ -1,3 +1,21 @@ +.. + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + Reference configuration ----------------------- diff --git a/manual/core/control_connection/README.md b/manual/core/control_connection/README.md index 570919fdc94..38544797aed 100644 --- a/manual/core/control_connection/README.md +++ b/manual/core/control_connection/README.md @@ -1,3 +1,22 @@ + + ## Control connection The control connection is a dedicated connection used for administrative tasks: @@ -23,4 +42,4 @@ There are a few options to fine tune the control connection behavior in the `advanced.control-connection` and `advanced.metadata` sections; see the [metadata](../metadata/) pages and the [reference configuration](../configuration/reference/) for all the details. -[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- \ No newline at end of file +[Node.getOpenConnections]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html#getOpenConnections-- diff --git a/manual/core/custom_codecs/README.md b/manual/core/custom_codecs/README.md index e68e5d78029..f3b7be1e3d9 100644 --- a/manual/core/custom_codecs/README.md +++ b/manual/core/custom_codecs/README.md @@ -1,3 +1,22 @@ + + ## Custom codecs ### Quick overview @@ -726,4 +745,4 @@ private static String formatRow(Row row) { [ObjectMapper]: http://fasterxml.github.io/jackson-databind/javadoc/2.10/com/fasterxml/jackson/databind/ObjectMapper.html -[CQL blob example]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/datatypes/Blobs.java \ No newline at end of file +[CQL blob example]: https://github.com/datastax/java-driver/blob/4.x/examples/src/main/java/com/datastax/oss/driver/examples/datatypes/Blobs.java diff --git a/manual/core/detachable_types/README.md b/manual/core/detachable_types/README.md index afd7a3ab0f1..7968835dd8a 100644 --- a/manual/core/detachable_types/README.md +++ b/manual/core/detachable_types/README.md @@ -1,3 +1,22 @@ + + ## Detachable types ### Quick overview diff --git a/manual/core/dse/README.md b/manual/core/dse/README.md index 8df3568e1ff..75abeafb3d7 100644 --- a/manual/core/dse/README.md +++ b/manual/core/dse/README.md @@ -1,3 +1,22 @@ + + ## DSE-specific features Some driver features only work with DataStax Enterprise: diff --git a/manual/core/dse/geotypes/README.md b/manual/core/dse/geotypes/README.md index 79a4c034052..eb414de4f8d 100644 --- a/manual/core/dse/geotypes/README.md +++ b/manual/core/dse/geotypes/README.md @@ -1,3 +1,22 @@ + + ## Geospatial types The driver comes with client-side representations of the DSE geospatial data types: [Point], diff --git a/manual/core/dse/graph/README.md b/manual/core/dse/graph/README.md index 9d6ef39f2f3..6bcacd44c4e 100644 --- a/manual/core/dse/graph/README.md +++ b/manual/core/dse/graph/README.md @@ -1,3 +1,22 @@ + + ## Graph The driver provides full support for DSE graph, the distributed graph database available in DataStax diff --git a/manual/core/dse/graph/fluent/README.md b/manual/core/dse/graph/fluent/README.md index 9201470b6a5..c1645fdb234 100644 --- a/manual/core/dse/graph/fluent/README.md +++ b/manual/core/dse/graph/fluent/README.md @@ -1,3 +1,22 @@ + + ## Fluent API The driver depends on [Apache TinkerPop™], a graph computing framework that provides a fluent API to diff --git a/manual/core/dse/graph/fluent/explicit/README.md b/manual/core/dse/graph/fluent/explicit/README.md index f3d8072dcb9..163180a4a8a 100644 --- a/manual/core/dse/graph/fluent/explicit/README.md +++ b/manual/core/dse/graph/fluent/explicit/README.md @@ -1,3 +1,22 @@ + + ## Explicit execution Fluent traversals can be wrapped into a [FluentGraphStatement] and passed to the session: diff --git a/manual/core/dse/graph/fluent/implicit/README.md b/manual/core/dse/graph/fluent/implicit/README.md index 797189a9ae1..f838c376022 100644 --- a/manual/core/dse/graph/fluent/implicit/README.md +++ b/manual/core/dse/graph/fluent/implicit/README.md @@ -1,3 +1,22 @@ + + ## Implicit execution Instead of passing traversals to the driver, you can create a *remote traversal source* connected to diff --git a/manual/core/dse/graph/options/README.md b/manual/core/dse/graph/options/README.md index ad439448aa0..e4649ff34f3 100644 --- a/manual/core/dse/graph/options/README.md +++ b/manual/core/dse/graph/options/README.md @@ -1,3 +1,22 @@ + + ## Graph options There are various [configuration](../../../configuration/) options that control the execution of @@ -157,4 +176,4 @@ not explicitly set through `advanced.graph.sub-protocol` in configuration, the v which the driver is connected will determine the default sub-protocol version used by the driver. For DSE 6.8.0 and later, the driver will pick "graph-binary-1.0" as the default sub-protocol version. For DSE 6.7.x and older (or in cases where the driver can't determine the DSE version), the -driver will pick "graphson-2.0" as the default sub-protocol version. \ No newline at end of file +driver will pick "graphson-2.0" as the default sub-protocol version. diff --git a/manual/core/dse/graph/results/README.md b/manual/core/dse/graph/results/README.md index abbc56f68fc..3b4d25fa012 100644 --- a/manual/core/dse/graph/results/README.md +++ b/manual/core/dse/graph/results/README.md @@ -1,3 +1,22 @@ + + ## Handling graph results [Script queries](../script/) and [explicit fluent traversals](../fluent/explicit/) return graph @@ -141,4 +160,4 @@ UUID uuid = graphNode.as(UUID.class); [GraphResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/GraphResultSet.html [AsyncGraphResultSet]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/AsyncGraphResultSet.html -[DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html \ No newline at end of file +[DSE data types]: https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/reference/refDSEGraphDataTypes.html diff --git a/manual/core/dse/graph/script/README.md b/manual/core/dse/graph/script/README.md index 2b98664ea16..cec8e4e94ef 100644 --- a/manual/core/dse/graph/script/README.md +++ b/manual/core/dse/graph/script/README.md @@ -1,3 +1,22 @@ + + ## Script API The script API handles Gremlin-groovy requests provided as plain Java strings. To execute a script, @@ -103,4 +122,4 @@ Note however that some types of queries can only be performed through the script [ScriptGraphStatement]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html [ScriptGraphStatement.newInstance]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#newInstance-java.lang.String- -[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- \ No newline at end of file +[ScriptGraphStatement.builder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/graph/ScriptGraphStatement.html#builder-java.lang.String- diff --git a/manual/core/graalvm/README.md b/manual/core/graalvm/README.md index 6ee713a2b30..d20fb739f19 100644 --- a/manual/core/graalvm/README.md +++ b/manual/core/graalvm/README.md @@ -1,3 +1,22 @@ + + ## GraalVM native images ### Quick overview diff --git a/manual/core/idempotence/README.md b/manual/core/idempotence/README.md index 3746825390a..be784dfa40b 100644 --- a/manual/core/idempotence/README.md +++ b/manual/core/idempotence/README.md @@ -1,3 +1,22 @@ + + ## Query idempotence ### Quick overview diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 16ed68f9e9b..1f102c2189e 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -1,3 +1,22 @@ + + ## Integration ### Quick overview diff --git a/manual/core/load_balancing/README.md b/manual/core/load_balancing/README.md index 2b60dcb1580..3f391c14f56 100644 --- a/manual/core/load_balancing/README.md +++ b/manual/core/load_balancing/README.md @@ -1,3 +1,22 @@ + + ## Load balancing ### Quick overview diff --git a/manual/core/logging/README.md b/manual/core/logging/README.md index ff0ee5303b6..e3f8bfa7777 100644 --- a/manual/core/logging/README.md +++ b/manual/core/logging/README.md @@ -1,3 +1,22 @@ + + ## Logging ### Quick overview @@ -215,4 +234,4 @@ console). [SLF4J]: https://www.slf4j.org/ [binding]: https://www.slf4j.org/manual.html#swapping [Logback]: http://logback.qos.ch -[Log4J]: https://logging.apache.org/log4j \ No newline at end of file +[Log4J]: https://logging.apache.org/log4j diff --git a/manual/core/metadata/README.md b/manual/core/metadata/README.md index 1bb07483869..73609ee0542 100644 --- a/manual/core/metadata/README.md +++ b/manual/core/metadata/README.md @@ -1,3 +1,22 @@ + + ## Metadata ### Quick overview @@ -58,4 +77,4 @@ refreshed. See the [Performance](../performance/#debouncing) page for more detai [Session#getMetadata]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Session.html#getMetadata-- [Metadata]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Metadata.html -[Node]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html \ No newline at end of file +[Node]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Node.html diff --git a/manual/core/metadata/node/README.md b/manual/core/metadata/node/README.md index 0f0b6176f42..fea04e5f262 100644 --- a/manual/core/metadata/node/README.md +++ b/manual/core/metadata/node/README.md @@ -1,3 +1,22 @@ + + ## Node metadata ### Quick overview diff --git a/manual/core/metadata/schema/README.md b/manual/core/metadata/schema/README.md index ed2c4c70750..20521d1def4 100644 --- a/manual/core/metadata/schema/README.md +++ b/manual/core/metadata/schema/README.md @@ -1,3 +1,22 @@ + + ## Schema metadata ### Quick overview diff --git a/manual/core/metadata/token/README.md b/manual/core/metadata/token/README.md index 1c6a9c08ae7..4d7cd9252df 100644 --- a/manual/core/metadata/token/README.md +++ b/manual/core/metadata/token/README.md @@ -1,3 +1,22 @@ + + ## Token metadata ### Quick overview @@ -170,4 +189,4 @@ also be unavailable for the excluded keyspaces. [Metadata#getTokenMap]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/Metadata.html#getTokenMap-- -[TokenMap]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/TokenMap.html \ No newline at end of file +[TokenMap]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/TokenMap.html diff --git a/manual/core/metrics/README.md b/manual/core/metrics/README.md index 65a93eb1fbf..b5dda977d5c 100644 --- a/manual/core/metrics/README.md +++ b/manual/core/metrics/README.md @@ -1,3 +1,22 @@ + + ## Metrics ### Quick overview @@ -346,4 +365,4 @@ CSV files, SLF4J logs and Graphite. Refer to their [manual][Dropwizard manual] f [Micrometer Metrics]: https://micrometer.io/docs [Micrometer JMX]: https://micrometer.io/docs/registry/jmx [MicroProfile Metrics]: https://github.com/eclipse/microprofile-metrics -[reference configuration]: ../configuration/reference/ \ No newline at end of file +[reference configuration]: ../configuration/reference/ diff --git a/manual/core/native_protocol/README.md b/manual/core/native_protocol/README.md index 33eca0b09d0..42146e63f42 100644 --- a/manual/core/native_protocol/README.md +++ b/manual/core/native_protocol/README.md @@ -1,3 +1,22 @@ + + ## Native protocol ### Quick overview diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 7dd184707ec..7abe9d856a3 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -1,3 +1,22 @@ + + ## Non-blocking programming ### Quick overview diff --git a/manual/core/paging/README.md b/manual/core/paging/README.md index 761a6bfbc66..2df92bd69d1 100644 --- a/manual/core/paging/README.md +++ b/manual/core/paging/README.md @@ -1,3 +1,22 @@ + + ## Paging ### Quick overview diff --git a/manual/core/performance/README.md b/manual/core/performance/README.md index aaaebdaa6c9..3afb321968e 100644 --- a/manual/core/performance/README.md +++ b/manual/core/performance/README.md @@ -1,3 +1,22 @@ + + ## Performance This page is intended as a checklist for everything related to driver performance. Most of the @@ -349,4 +368,4 @@ the only one that will have to stay on a separate thread. [CqlIdentifier]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlIdentifier.html [CqlSession.prepare(SimpleStatement)]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html#prepare-com.datastax.oss.driver.api.core.cql.SimpleStatement- [GenericType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/reflect/GenericType.html -[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- \ No newline at end of file +[Statement.setNode()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Statement.html#setNode-com.datastax.oss.driver.api.core.metadata.Node- diff --git a/manual/core/pooling/README.md b/manual/core/pooling/README.md index ad9e6f97a02..578de6b4abd 100644 --- a/manual/core/pooling/README.md +++ b/manual/core/pooling/README.md @@ -1,3 +1,22 @@ + + ## Connection pooling ### Quick overview @@ -171,4 +190,4 @@ Try adding more connections per node. Thanks to the driver's hot-reload mechanis at runtime and see the effects immediately. [CqlSession]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/CqlSession.html -[CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 \ No newline at end of file +[CASSANDRA-8086]: https://issues.apache.org/jira/browse/CASSANDRA-8086 diff --git a/manual/core/query_timestamps/README.md b/manual/core/query_timestamps/README.md index c851e023e14..4498afe21c4 100644 --- a/manual/core/query_timestamps/README.md +++ b/manual/core/query_timestamps/README.md @@ -1,3 +1,22 @@ + + ## Query timestamps ### Quick overview diff --git a/manual/core/reactive/README.md b/manual/core/reactive/README.md index d0182c4fbc2..37a2e3411b8 100644 --- a/manual/core/reactive/README.md +++ b/manual/core/reactive/README.md @@ -1,3 +1,22 @@ + + ## Reactive Style Programming The driver provides built-in support for reactive queries. The [CqlSession] interface extends diff --git a/manual/core/reconnection/README.md b/manual/core/reconnection/README.md index b27dd19aa27..3eb6dad9c05 100644 --- a/manual/core/reconnection/README.md +++ b/manual/core/reconnection/README.md @@ -1,3 +1,22 @@ + + ## Reconnection ### Quick overview @@ -87,4 +106,4 @@ was established. [ConstantReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/internal/core/connection/ConstantReconnectionPolicy.html [DriverContext]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/context/DriverContext.html [ExponentialReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/internal/core/connection/ExponentialReconnectionPolicy.html -[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html \ No newline at end of file +[ReconnectionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/ReconnectionPolicy.html diff --git a/manual/core/request_tracker/README.md b/manual/core/request_tracker/README.md index 0862654e53f..c135abfe53f 100644 --- a/manual/core/request_tracker/README.md +++ b/manual/core/request_tracker/README.md @@ -1,3 +1,22 @@ + + ## Request tracker ### Quick overview @@ -124,4 +143,4 @@ com.datastax.oss.driver.api.core.servererrors.InvalidQueryException: Undefined c ``` [RequestTracker]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/tracker/RequestTracker.html -[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- \ No newline at end of file +[SessionBuilder.addRequestTracker]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#addRequestTracker-com.datastax.oss.driver.api.core.tracker.RequestTracker- diff --git a/manual/core/retries/README.md b/manual/core/retries/README.md index cdd3a5740a2..e92f8e214aa 100644 --- a/manual/core/retries/README.md +++ b/manual/core/retries/README.md @@ -1,3 +1,22 @@ + + ## Retries ### Quick overview diff --git a/manual/core/shaded_jar/README.md b/manual/core/shaded_jar/README.md index 2f52e44c6a4..a6dfac9053e 100644 --- a/manual/core/shaded_jar/README.md +++ b/manual/core/shaded_jar/README.md @@ -1,3 +1,22 @@ + + ## Using the shaded JAR The default `java-driver-core` JAR depends on a number of [third party diff --git a/manual/core/speculative_execution/README.md b/manual/core/speculative_execution/README.md index 53913a6eda7..5666d6a1363 100644 --- a/manual/core/speculative_execution/README.md +++ b/manual/core/speculative_execution/README.md @@ -1,3 +1,22 @@ + + ## Speculative query execution ### Quick overview @@ -250,4 +269,4 @@ profiles have the same configuration). Each request uses its declared profile's policy. If it doesn't declare any profile, or if the profile doesn't have a dedicated policy, then the default profile's policy is used. -[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html \ No newline at end of file +[SpeculativeExecutionPolicy]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/specex/SpeculativeExecutionPolicy.html diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index 37396c6d4c0..b8aa9b89192 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -1,3 +1,22 @@ + + ## SSL ### Quick overview diff --git a/manual/core/statements/README.md b/manual/core/statements/README.md index f02806fb940..394e81ae00e 100644 --- a/manual/core/statements/README.md +++ b/manual/core/statements/README.md @@ -1,3 +1,22 @@ + + ## Statements ### Quick overview diff --git a/manual/core/statements/batch/README.md b/manual/core/statements/batch/README.md index 05e803770eb..f080fe16ab0 100644 --- a/manual/core/statements/batch/README.md +++ b/manual/core/statements/batch/README.md @@ -1,3 +1,22 @@ + + ## Batch statements ### Quick overview diff --git a/manual/core/statements/per_query_keyspace/README.md b/manual/core/statements/per_query_keyspace/README.md index f9076b5b5b6..9a7ffa338c9 100644 --- a/manual/core/statements/per_query_keyspace/README.md +++ b/manual/core/statements/per_query_keyspace/README.md @@ -1,3 +1,22 @@ + + ## Per-query keyspace ### Quick overview @@ -126,4 +145,4 @@ the norm, we'll probably deprecate `setRoutingKeyspace()`. [token-aware routing]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/Request.html#getRoutingKey-- -[CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 \ No newline at end of file +[CASSANDRA-10145]: https://issues.apache.org/jira/browse/CASSANDRA-10145 diff --git a/manual/core/statements/prepared/README.md b/manual/core/statements/prepared/README.md index d5a4739c11b..5a87b238cbc 100644 --- a/manual/core/statements/prepared/README.md +++ b/manual/core/statements/prepared/README.md @@ -1,3 +1,22 @@ + + ## Prepared statements ### Quick overview diff --git a/manual/core/statements/simple/README.md b/manual/core/statements/simple/README.md index df56698b4ee..13ddbb7a389 100644 --- a/manual/core/statements/simple/README.md +++ b/manual/core/statements/simple/README.md @@ -1,3 +1,22 @@ + + ## Simple statements ### Quick overview diff --git a/manual/core/temporal_types/README.md b/manual/core/temporal_types/README.md index 2128f822694..6542d5b8dac 100644 --- a/manual/core/temporal_types/README.md +++ b/manual/core/temporal_types/README.md @@ -1,3 +1,22 @@ + + ## Temporal types ### Quick overview @@ -149,4 +168,4 @@ System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); [CqlDuration]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/CqlDuration.html [TypeCodecs.ZONED_TIMESTAMP_SYSTEM]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_SYSTEM [TypeCodecs.ZONED_TIMESTAMP_UTC]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#ZONED_TIMESTAMP_UTC -[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- \ No newline at end of file +[TypeCodecs.zonedTimestampAt()]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.html#zonedTimestampAt-java.time.ZoneId- diff --git a/manual/core/throttling/README.md b/manual/core/throttling/README.md index 0e1605dafb5..275c0cb5b40 100644 --- a/manual/core/throttling/README.md +++ b/manual/core/throttling/README.md @@ -1,3 +1,22 @@ + + ## Request throttling ### Quick overview @@ -147,4 +166,4 @@ size the underlying histograms (`metrics.session.throttling.delay.*`). [RequestThrottlingException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/RequestThrottlingException.html [AllNodesFailedException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/AllNodesFailedException.html -[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html \ No newline at end of file +[BusyConnectionException]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/connection/BusyConnectionException.html diff --git a/manual/core/tracing/README.md b/manual/core/tracing/README.md index f3154600f9f..f9beca8e49b 100644 --- a/manual/core/tracing/README.md +++ b/manual/core/tracing/README.md @@ -1,3 +1,22 @@ + + ## Query tracing ### Quick overview diff --git a/manual/core/tuples/README.md b/manual/core/tuples/README.md index 69c2f24a46b..d0684b77569 100644 --- a/manual/core/tuples/README.md +++ b/manual/core/tuples/README.md @@ -1,3 +1,22 @@ + + ## Tuples ### Quick overview diff --git a/manual/core/udts/README.md b/manual/core/udts/README.md index f45cf658b89..a22057030ae 100644 --- a/manual/core/udts/README.md +++ b/manual/core/udts/README.md @@ -1,3 +1,22 @@ + + ## User-defined types ### Quick overview @@ -136,4 +155,4 @@ session.execute(bs); [cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html [UdtValue]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/data/UdtValue.html -[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/UserDefinedType.html \ No newline at end of file +[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/UserDefinedType.html diff --git a/manual/developer/README.md b/manual/developer/README.md index 975ab16c176..b6e0bda16ed 100644 --- a/manual/developer/README.md +++ b/manual/developer/README.md @@ -1,3 +1,22 @@ + + ## Developer docs This section explains how driver internals work. The intended audience is: @@ -16,4 +35,4 @@ from lowest to highest level: * [Request execution](request_execution/): higher-level handling of user requests and responses; * [Administrative tasks](admin/): everything else (cluster state and metadata). -If you're reading this on GitHub, the `.nav` file in each directory contains a suggested order. \ No newline at end of file +If you're reading this on GitHub, the `.nav` file in each directory contains a suggested order. diff --git a/manual/developer/admin/README.md b/manual/developer/admin/README.md index def3b6a2927..0ebd9e2d746 100644 --- a/manual/developer/admin/README.md +++ b/manual/developer/admin/README.md @@ -1,3 +1,22 @@ + + ## Administrative tasks Aside from the main task of [executing user requests](../request_execution), the driver also needs @@ -320,4 +339,4 @@ It's less likely that this will be overridden directly. But the schema querying abstracted behind two factories that handle the differences between Cassandra versions: `SchemaQueriesFactory` and `SchemaParserFactory`. These are pluggable by [extending the context](../common/context/#overriding-a-context-component) and overriding the corresponding -`buildXxx` methods. \ No newline at end of file +`buildXxx` methods. diff --git a/manual/developer/common/README.md b/manual/developer/common/README.md index c227f0826a5..13ad8639e62 100644 --- a/manual/developer/common/README.md +++ b/manual/developer/common/README.md @@ -1,3 +1,22 @@ + + ## Common infrastructure This covers utilities or concept that are shared throughout the codebase: diff --git a/manual/developer/common/concurrency/README.md b/manual/developer/common/concurrency/README.md index a09d1c9fd63..fb493930d6e 100644 --- a/manual/developer/common/concurrency/README.md +++ b/manual/developer/common/concurrency/README.md @@ -1,3 +1,22 @@ + + ## Concurrency The driver is a highly concurrent environment. We try to use thread confinement to simplify the diff --git a/manual/developer/common/context/README.md b/manual/developer/common/context/README.md index 3c6143e970d..e20d5ad0ddb 100644 --- a/manual/developer/common/context/README.md +++ b/manual/developer/common/context/README.md @@ -1,3 +1,22 @@ + + ## Driver context The context holds the driver's internal components. It is exposed in the public API as diff --git a/manual/developer/common/event_bus/README.md b/manual/developer/common/event_bus/README.md index 837f8c69082..74729ac6656 100644 --- a/manual/developer/common/event_bus/README.md +++ b/manual/developer/common/event_bus/README.md @@ -1,3 +1,22 @@ + + ## Event bus `EventBus` is a bare-bones messaging mechanism, to decouple components from each other, and diff --git a/manual/developer/native_protocol/README.md b/manual/developer/native_protocol/README.md index cbda8f794ff..b96553fc51b 100644 --- a/manual/developer/native_protocol/README.md +++ b/manual/developer/native_protocol/README.md @@ -1,3 +1,22 @@ + + ## Native protocol layer The native protocol layer encodes protocol messages into binary, before they are sent over the diff --git a/manual/developer/netty_pipeline/README.md b/manual/developer/netty_pipeline/README.md index 58a32a67a59..b596832e202 100644 --- a/manual/developer/netty_pipeline/README.md +++ b/manual/developer/netty_pipeline/README.md @@ -1,3 +1,22 @@ + + ## Netty pipeline With the [protocol layer](../native_protocol) in place, the next step is to build the logic for a @@ -158,4 +177,4 @@ boringssl. This requires a bit of custom development against the internal API: [SslContext]: https://netty.io/4.1/api/io/netty/handler/ssl/SslContext.html [SslContext.newHandler]: https://netty.io/4.1/api/io/netty/handler/ssl/SslContext.html#newHandler-io.netty.buffer.ByteBufAllocator- -[SslContextBuilder.forClient]: https://netty.io/4.1/api/io/netty/handler/ssl/SslContextBuilder.html#forClient-- \ No newline at end of file +[SslContextBuilder.forClient]: https://netty.io/4.1/api/io/netty/handler/ssl/SslContextBuilder.html#forClient-- diff --git a/manual/developer/request_execution/README.md b/manual/developer/request_execution/README.md index c6ec04e3b1a..38a0a55fbd7 100644 --- a/manual/developer/request_execution/README.md +++ b/manual/developer/request_execution/README.md @@ -1,3 +1,22 @@ + + ## Request execution The [Netty pipeline](../netty_pipeline/) gives us the ability to send low-level protocol messages on diff --git a/manual/mapper/README.md b/manual/mapper/README.md index 8e745bf44f9..2c64897243f 100644 --- a/manual/mapper/README.md +++ b/manual/mapper/README.md @@ -1,3 +1,22 @@ + + ## Mapper The mapper generates the boilerplate to execute queries and convert the results into diff --git a/manual/mapper/config/README.md b/manual/mapper/config/README.md index 5a6df9d2ba7..8adc0e63b33 100644 --- a/manual/mapper/config/README.md +++ b/manual/mapper/config/README.md @@ -1,3 +1,22 @@ + + ## Integration ### Builds tools diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index 4ee234ffa14..07dcf20f4bf 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -1,3 +1,22 @@ + + ## Kotlin [Kotlin](https://kotlinlang.org/) is an alternative language for the JVM. Its compact syntax and diff --git a/manual/mapper/config/lombok/README.md b/manual/mapper/config/lombok/README.md index e2a4f0263c8..b87f8f79ea4 100644 --- a/manual/mapper/config/lombok/README.md +++ b/manual/mapper/config/lombok/README.md @@ -1,3 +1,22 @@ + + ## Lombok [Lombok](https://projectlombok.org/) is a popular library that automates repetitive code, such as diff --git a/manual/mapper/config/record/README.md b/manual/mapper/config/record/README.md index 7466812fc9b..95530d52742 100644 --- a/manual/mapper/config/record/README.md +++ b/manual/mapper/config/record/README.md @@ -1,3 +1,22 @@ + + ## Java 14 Records Java 14 introduced [Record] as a lightweight, immutable alternative to POJOs. You can map annotated diff --git a/manual/mapper/config/scala/README.md b/manual/mapper/config/scala/README.md index b043bd784ad..2cb75273d0b 100644 --- a/manual/mapper/config/scala/README.md +++ b/manual/mapper/config/scala/README.md @@ -1,3 +1,22 @@ + + ## Scala [Scala](https://www.scala-lang.org/) is an alternative language for the JVM. It doesn't support diff --git a/manual/mapper/daos/README.md b/manual/mapper/daos/README.md index e76dde55314..d12172bf056 100644 --- a/manual/mapper/daos/README.md +++ b/manual/mapper/daos/README.md @@ -1,3 +1,22 @@ + + ## DAOs ### Quick overview diff --git a/manual/mapper/daos/custom_types/README.md b/manual/mapper/daos/custom_types/README.md index 75e9733cb2f..19f689655a7 100644 --- a/manual/mapper/daos/custom_types/README.md +++ b/manual/mapper/daos/custom_types/README.md @@ -1,3 +1,22 @@ + + ## Custom result types The mapper supports a pre-defined set of built-in types for DAO method results. For example, a diff --git a/manual/mapper/daos/delete/README.md b/manual/mapper/daos/delete/README.md index 10f4ad249d2..e67ecdc8a6e 100644 --- a/manual/mapper/daos/delete/README.md +++ b/manual/mapper/daos/delete/README.md @@ -1,3 +1,22 @@ + + ## Delete methods Annotate a DAO method with [@Delete] to generate a query that deletes an [Entity](../../entities): @@ -163,4 +182,4 @@ entity class and the [naming strategy](../../entities/#naming-strategy)). [CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html -[CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html \ No newline at end of file +[CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index cea11e34d17..abb7cb076c8 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -1,3 +1,22 @@ + + ## GetEntity methods Annotate a DAO method with [@GetEntity] to convert a core driver data structure into one or more diff --git a/manual/mapper/daos/increment/README.md b/manual/mapper/daos/increment/README.md index c8e90a51627..44b017be2e1 100644 --- a/manual/mapper/daos/increment/README.md +++ b/manual/mapper/daos/increment/README.md @@ -1,3 +1,22 @@ + + ## Increment methods Annotate a DAO method with [@Increment] to generate a query that updates a counter table that is diff --git a/manual/mapper/daos/insert/README.md b/manual/mapper/daos/insert/README.md index bfd95229e1b..b90ffa33a32 100644 --- a/manual/mapper/daos/insert/README.md +++ b/manual/mapper/daos/insert/README.md @@ -1,3 +1,22 @@ + + ## Insert methods Annotate a DAO method with [@Insert] to generate a query that inserts an [Entity](../../entities): diff --git a/manual/mapper/daos/null_saving/README.md b/manual/mapper/daos/null_saving/README.md index e2858f43b4d..eed98934356 100644 --- a/manual/mapper/daos/null_saving/README.md +++ b/manual/mapper/daos/null_saving/README.md @@ -1,3 +1,22 @@ + + ## Null saving strategy The null saving strategy controls how null entity properties are handled when writing to the diff --git a/manual/mapper/daos/query/README.md b/manual/mapper/daos/query/README.md index 0d4293b5f15..a11753da880 100644 --- a/manual/mapper/daos/query/README.md +++ b/manual/mapper/daos/query/README.md @@ -1,3 +1,22 @@ + + ## Query methods Annotate a DAO method with [@Query] to provide your own query string: diff --git a/manual/mapper/daos/queryprovider/README.md b/manual/mapper/daos/queryprovider/README.md index 7c750bcce1f..593a3a6b1a4 100644 --- a/manual/mapper/daos/queryprovider/README.md +++ b/manual/mapper/daos/queryprovider/README.md @@ -1,3 +1,22 @@ + + ## Query provider methods Annotate a DAO method with [@QueryProvider] to delegate the execution of the query to one of your diff --git a/manual/mapper/daos/select/README.md b/manual/mapper/daos/select/README.md index 9d5357ad546..fb6c4ca2077 100644 --- a/manual/mapper/daos/select/README.md +++ b/manual/mapper/daos/select/README.md @@ -1,3 +1,22 @@ + + ## Select methods Annotate a DAO method with [@Select] to generate a query that selects one or more rows, and maps diff --git a/manual/mapper/daos/setentity/README.md b/manual/mapper/daos/setentity/README.md index cedb6e3dc45..eeb7957f62e 100644 --- a/manual/mapper/daos/setentity/README.md +++ b/manual/mapper/daos/setentity/README.md @@ -1,3 +1,22 @@ + + ## SetEntity methods Annotate a DAO method with [@SetEntity] to fill a core driver data structure from an diff --git a/manual/mapper/daos/statement_attributes/README.md b/manual/mapper/daos/statement_attributes/README.md index aa11e065b4f..f772df36775 100644 --- a/manual/mapper/daos/statement_attributes/README.md +++ b/manual/mapper/daos/statement_attributes/README.md @@ -1,3 +1,22 @@ + + ## Statement attributes The [@Delete](../delete/), [@Insert](../insert/), [@Query](../query/), [@Select](../select/) and @@ -60,4 +79,4 @@ Product product = dao.findById(1, builder -> builder.setConsistencyLevel(DefaultConsistencyLevel.QUORUM)); ``` -[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html \ No newline at end of file +[@StatementAttributes]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/StatementAttributes.html diff --git a/manual/mapper/daos/update/README.md b/manual/mapper/daos/update/README.md index 6a14a4a6140..87e9286c800 100644 --- a/manual/mapper/daos/update/README.md +++ b/manual/mapper/daos/update/README.md @@ -1,3 +1,22 @@ + + ## Update methods Annotate a DAO method with [@Update] to generate a query that updates one or more diff --git a/manual/mapper/entities/README.md b/manual/mapper/entities/README.md index b857203ef32..978c781245f 100644 --- a/manual/mapper/entities/README.md +++ b/manual/mapper/entities/README.md @@ -1,3 +1,22 @@ + + ## Entities ### Quick overview diff --git a/manual/mapper/mapper/README.md b/manual/mapper/mapper/README.md index 894143f0b9b..752424c9a3b 100644 --- a/manual/mapper/mapper/README.md +++ b/manual/mapper/mapper/README.md @@ -1,3 +1,22 @@ + + ## Mapper interface ### Quick overview diff --git a/manual/osgi/README.md b/manual/osgi/README.md index 88254334f25..92cd4625b68 100644 --- a/manual/osgi/README.md +++ b/manual/osgi/README.md @@ -1,3 +1,22 @@ + + # OSGi The driver is available as an [OSGi] bundle. More specifically, the following maven artifacts are diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index b9ea6a36205..c17cd30d161 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -1,3 +1,22 @@ + + ## Query builder The query builder is a utility to **generate CQL queries programmatically**. For example, it could diff --git a/manual/query_builder/condition/README.md b/manual/query_builder/condition/README.md index 0530b33d5bc..1a6a37eb2ef 100644 --- a/manual/query_builder/condition/README.md +++ b/manual/query_builder/condition/README.md @@ -1,3 +1,22 @@ + + ## Conditions A condition is a clause that appears after the IF keyword in a conditional [UPDATE](../update/) or diff --git a/manual/query_builder/delete/README.md b/manual/query_builder/delete/README.md index 031291c311f..8e97920ae9f 100644 --- a/manual/query_builder/delete/README.md +++ b/manual/query_builder/delete/README.md @@ -1,3 +1,22 @@ + + ## DELETE To start a DELETE query, use one of the `deleteFrom` methods in [QueryBuilder]. There are several diff --git a/manual/query_builder/idempotence/README.md b/manual/query_builder/idempotence/README.md index 9fd6d39114d..2f97151d277 100644 --- a/manual/query_builder/idempotence/README.md +++ b/manual/query_builder/idempotence/README.md @@ -1,3 +1,22 @@ + + ## Idempotence in the query builder When you generate a statement (or a statement builder) from the query builder, it automatically @@ -225,4 +244,4 @@ sequential history that is correct. From our clients' point of view, there were But overall the column changed from 1 to 2. There is no ordering of the two operations that can explain that change. We broke linearizability by doing a transparent retry at step 6. -[linearizability]: https://en.wikipedia.org/wiki/Linearizability#Definition_of_linearizability \ No newline at end of file +[linearizability]: https://en.wikipedia.org/wiki/Linearizability#Definition_of_linearizability diff --git a/manual/query_builder/insert/README.md b/manual/query_builder/insert/README.md index ede99602af0..6bac896d9b8 100644 --- a/manual/query_builder/insert/README.md +++ b/manual/query_builder/insert/README.md @@ -1,3 +1,22 @@ + + ## INSERT To start an INSERT query, use one of the `insertInto` methods in [QueryBuilder]. There are @@ -114,4 +133,4 @@ is executed. This is distinctly different than setting the value to null. Passin this method will only remove the USING TTL clause from the query, which will not alter the TTL (if one is set) in Cassandra. -[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html \ No newline at end of file +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html diff --git a/manual/query_builder/relation/README.md b/manual/query_builder/relation/README.md index 3c72e28cbee..eb1c728888e 100644 --- a/manual/query_builder/relation/README.md +++ b/manual/query_builder/relation/README.md @@ -1,3 +1,22 @@ + + ## Relations A relation is a clause that appears after the WHERE keyword, and restricts the rows that the diff --git a/manual/query_builder/schema/README.md b/manual/query_builder/schema/README.md index e4021c3068f..0472c8e8c6f 100644 --- a/manual/query_builder/schema/README.md +++ b/manual/query_builder/schema/README.md @@ -1,3 +1,22 @@ + + # Schema builder The schema builder is an additional API provided by [java-driver-query-builder](../) that enables diff --git a/manual/query_builder/schema/aggregate/README.md b/manual/query_builder/schema/aggregate/README.md index 42f1952a105..a54f8703d69 100644 --- a/manual/query_builder/schema/aggregate/README.md +++ b/manual/query_builder/schema/aggregate/README.md @@ -1,3 +1,22 @@ + + ## Aggregate Aggregates enable users to apply User-defined functions (UDF) to rows in a data set and combine diff --git a/manual/query_builder/schema/function/README.md b/manual/query_builder/schema/function/README.md index 7d02f0f8349..001327626b1 100644 --- a/manual/query_builder/schema/function/README.md +++ b/manual/query_builder/schema/function/README.md @@ -1,3 +1,22 @@ + + ## Function User-defined functions (UDF) enable users to create user code written in JSR-232 compliant scripting diff --git a/manual/query_builder/schema/index/README.md b/manual/query_builder/schema/index/README.md index 8541831c1f2..c0c9448dfab 100644 --- a/manual/query_builder/schema/index/README.md +++ b/manual/query_builder/schema/index/README.md @@ -1,3 +1,22 @@ + + # Index An index provides a means of expanding the query capabilities of a table. [SchemaBuilder] offers diff --git a/manual/query_builder/schema/keyspace/README.md b/manual/query_builder/schema/keyspace/README.md index 25e165f32c1..572e8af1658 100644 --- a/manual/query_builder/schema/keyspace/README.md +++ b/manual/query_builder/schema/keyspace/README.md @@ -1,3 +1,22 @@ + + ## Keyspace A keyspace is a top-level namespace that defines a name, replication strategy and configurable diff --git a/manual/query_builder/schema/materialized_view/README.md b/manual/query_builder/schema/materialized_view/README.md index 7bcdda0bd3f..c4f495f95aa 100644 --- a/manual/query_builder/schema/materialized_view/README.md +++ b/manual/query_builder/schema/materialized_view/README.md @@ -1,3 +1,22 @@ + + ## Materialized View Materialized Views are an experimental feature introduced in Apache Cassandra 3.0 that provide a diff --git a/manual/query_builder/schema/table/README.md b/manual/query_builder/schema/table/README.md index 8a68d676851..090f8a1f67b 100644 --- a/manual/query_builder/schema/table/README.md +++ b/manual/query_builder/schema/table/README.md @@ -1,3 +1,22 @@ + + ## Table Data in Apache Cassandra is stored in tables. [SchemaBuilder] offers API methods for creating, diff --git a/manual/query_builder/schema/type/README.md b/manual/query_builder/schema/type/README.md index e474dc29419..c289ad776a8 100644 --- a/manual/query_builder/schema/type/README.md +++ b/manual/query_builder/schema/type/README.md @@ -1,3 +1,22 @@ + + ## Type User-defined types are special types that can associate multiple named fields to a single column. diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index 19f0085508a..92c058608e7 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -1,3 +1,22 @@ + + ## SELECT Start your SELECT with the `selectFrom` method in [QueryBuilder]. There are several variants diff --git a/manual/query_builder/term/README.md b/manual/query_builder/term/README.md index 214dedb3274..460ed8dcb10 100644 --- a/manual/query_builder/term/README.md +++ b/manual/query_builder/term/README.md @@ -1,3 +1,22 @@ + + ## Terms A term is an expression that does not involve the value of a column. It is used: @@ -106,4 +125,4 @@ execution time; on the other hand, it can be used as a workaround to handle new are not yet covered by the query builder. [QueryBuilder]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/querybuilder/QueryBuilder.html -[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html \ No newline at end of file +[CodecRegistry]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/type/codec/registry/CodecRegistry.html diff --git a/manual/query_builder/truncate/README.md b/manual/query_builder/truncate/README.md index 9b37160c0c9..c8cd6945123 100644 --- a/manual/query_builder/truncate/README.md +++ b/manual/query_builder/truncate/README.md @@ -1,3 +1,22 @@ + + ## TRUNCATE To create a TRUNCATE query, use one of the `truncate` methods in [QueryBuilder]. There are several diff --git a/manual/query_builder/update/README.md b/manual/query_builder/update/README.md index d85f71f11cc..15502f52bb7 100644 --- a/manual/query_builder/update/README.md +++ b/manual/query_builder/update/README.md @@ -1,3 +1,22 @@ + + ## UPDATE To start an UPDATE query, use one of the `update` methods in [QueryBuilder]. There are several diff --git a/mapper-processor/CONTRIBUTING.md b/mapper-processor/CONTRIBUTING.md index 11659a9f936..c6d324106c4 100644 --- a/mapper-processor/CONTRIBUTING.md +++ b/mapper-processor/CONTRIBUTING.md @@ -1,3 +1,22 @@ + + # Mapper contributing guidelines Everything in the [main contribution guidelines](../CONTRIBUTING.md) also applies to the mapper. diff --git a/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties b/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties index 4971c6cb7ee..fdbf4ccc7c2 100644 --- a/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties +++ b/metrics/micrometer/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-micrometer/native-image.properties @@ -1 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + Args = -H:ReflectionConfigurationResources=${.}/reflection.json diff --git a/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties b/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties index 4971c6cb7ee..fdbf4ccc7c2 100644 --- a/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties +++ b/metrics/microprofile/src/main/resources/META-INF/native-image/com.datastax.oss/java-driver-metrics-microprofile/native-image.properties @@ -1 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + Args = -H:ReflectionConfigurationResources=${.}/reflection.json diff --git a/osgi-tests/README.md b/osgi-tests/README.md index 1647bad6949..89ad0ba27c8 100644 --- a/osgi-tests/README.md +++ b/osgi-tests/README.md @@ -1,3 +1,22 @@ + + # Java Driver OSGi Tests This module contains OSGi tests for the driver. @@ -45,4 +64,4 @@ First, you can enable DEBUG logs for the Pax Exam framework by editing the Alternatively, you can debug the remote OSGi container by passing the system property `-Dosgi.debug=true`. In this case the framework will prompt for a -remote debugger on port 5005. \ No newline at end of file +remote debugger on port 5005. diff --git a/osgi-tests/src/main/resources/application.conf b/osgi-tests/src/main/resources/application.conf index 8f795524ed2..0c3e8e76c98 100644 --- a/osgi-tests/src/main/resources/application.conf +++ b/osgi-tests/src/main/resources/application.conf @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # Configuration overrides for integration tests datastax-java-driver { basic { @@ -39,4 +56,4 @@ datastax-java-driver { } } } -} \ No newline at end of file +} diff --git a/performance/README.md b/performance/README.md index f13c76d18cc..ff66a453e9b 100644 --- a/performance/README.md +++ b/performance/README.md @@ -1,3 +1,22 @@ + + # How to run the Driver duration tests Note: the procedure described in this page is currently only accessible to DataStax employees. diff --git a/performance/duration-test.yaml b/performance/duration-test.yaml index 8a50e0de3b5..6e718f2add8 100644 --- a/performance/duration-test.yaml +++ b/performance/duration-test.yaml @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # Possible values: cassandra or dse server_type: cassandra # Server version (e.g. 3.11.7 or 6.8.8) diff --git a/performance/graphite-setup.yaml b/performance/graphite-setup.yaml index 04c37aecfd9..99bb8ecc8cc 100644 --- a/performance/graphite-setup.yaml +++ b/performance/graphite-setup.yaml @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # How long should the Graphite server be kept alive, default: 15 days keep_alive: 15d # Cloud-specific settings diff --git a/pre-commit.sh b/pre-commit.sh index c87ea5bf9ca..912564ae81e 100755 --- a/pre-commit.sh +++ b/pre-commit.sh @@ -1,4 +1,20 @@ #!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. # STASH_NAME="pre-commit-$(date +%s)" # git stash save --keep-index $STASH_NAME diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index de624bc436f..e79e8f8cc6d 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -1,3 +1,22 @@ + + ## Upgrade guide ### 4.17.0 From 0e4f40121d65d600b123cea4bfe365dbc09bfbad Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Mon, 13 Nov 2023 17:05:59 -0800 Subject: [PATCH 287/395] Move copyright notices to LICENSE, add bundled ASL dep notices to NOTICE patch by Claude Warren; reviewed by Henry Hughes, Mick Semb Wever for CASSANDRA-18969 --- LICENSE | 21 +++++ NOTICE.txt | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 261 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index d6456956733..a157e31d058 100644 --- a/LICENSE +++ b/LICENSE @@ -200,3 +200,24 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +Apache Cassandra Java Driver bundles code and files from the following projects: + +JNR project +Copyright (C) 2008-2010 Wayne Meissner +This product includes software developed as part of the JNR project ( https://github.com/jnr/jnr-ffi )s. +see core/src/main/java/com/datastax/oss/driver/internal/core/os/CpuInfo.java + +Protocol Buffers +Copyright 2008 Google Inc. +This product includes software developed as part of the Protocol Buffers project ( https://developers.google.com/protocol-buffers/ ). +see core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java + +Guava +Copyright (C) 2007 The Guava Authors +This product includes software developed as part of the Guava project ( https://guava.dev ). +see core/src/main/java/com/datastax/oss/driver/internal/core/util/CountingIterator.java + +Copyright (C) 2018 Christian Stein +This product includes software developed by Christian Stein +see ci/install-jdk.sh diff --git a/NOTICE.txt b/NOTICE.txt index 477f0645ed9..b7a91be2318 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -4,17 +4,243 @@ Copyright 2012- The Apache Software Foundation This product includes software developed by The Apache Software Foundation (http://www.apache.org/). -JNR project -Copyright (C) 2008-2010 Wayne Meissner -This product includes software developed as part of the JNR project ( https://github.com/jnr/jnr-ffi )s. -see core/src/main/java/com/datastax/oss/driver/internal/core/os/CpuInfo.java - -Protocol Buffers -Copyright 2008 Google Inc. -This product includes software developed as part of the Protocol Buffers project ( https://developers.google.com/protocol-buffers/ ). -see core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java - -Guava -Copyright (C) 2007 The Guava Authors -This product includes software developed as part of the Guava project ( https://guava.dev ). -see core/src/main/java/com/datastax/oss/driver/internal/core/util/CountingIterator.java \ No newline at end of file +================================================================== +io.netty:netty-handler NOTICE.txt +================================================================== +This product contains the extensions to Java Collections Framework which has +been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: + + * LICENSE: + * license/LICENSE.jsr166y.txt (Public Domain) + * HOMEPAGE: + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ + * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ + +This product contains a modified version of Robert Harder's Public Domain +Base64 Encoder and Decoder, which can be obtained at: + + * LICENSE: + * license/LICENSE.base64.txt (Public Domain) + * HOMEPAGE: + * http://iharder.sourceforge.net/current/java/base64/ + +This product contains a modified portion of 'Webbit', an event based +WebSocket and HTTP server, which can be obtained at: + + * LICENSE: + * license/LICENSE.webbit.txt (BSD License) + * HOMEPAGE: + * https://github.com/joewalnes/webbit + +This product contains a modified portion of 'SLF4J', a simple logging +facade for Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.slf4j.txt (MIT License) + * HOMEPAGE: + * https://www.slf4j.org/ + +This product contains a modified portion of 'Apache Harmony', an open source +Java SE, which can be obtained at: + + * NOTICE: + * license/NOTICE.harmony.txt + * LICENSE: + * license/LICENSE.harmony.txt (Apache License 2.0) + * HOMEPAGE: + * https://archive.apache.org/dist/harmony/ + +This product contains a modified portion of 'jbzip2', a Java bzip2 compression +and decompression library written by Matthew J. Francis. It can be obtained at: + + * LICENSE: + * license/LICENSE.jbzip2.txt (MIT License) + * HOMEPAGE: + * https://code.google.com/p/jbzip2/ + +This product contains a modified portion of 'libdivsufsort', a C API library to construct +the suffix array and the Burrows-Wheeler transformed string for any input string of +a constant-size alphabet written by Yuta Mori. It can be obtained at: + + * LICENSE: + * license/LICENSE.libdivsufsort.txt (MIT License) + * HOMEPAGE: + * https://github.com/y-256/libdivsufsort + +This product contains a modified portion of Nitsan Wakart's 'JCTools', Java Concurrency Tools for the JVM, + which can be obtained at: + + * LICENSE: + * license/LICENSE.jctools.txt (ASL2 License) + * HOMEPAGE: + * https://github.com/JCTools/JCTools + +This product optionally depends on 'JZlib', a re-implementation of zlib in +pure Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.jzlib.txt (BSD style License) + * HOMEPAGE: + * http://www.jcraft.com/jzlib/ + +This product optionally depends on 'Compress-LZF', a Java library for encoding and +decoding data in LZF format, written by Tatu Saloranta. It can be obtained at: + + * LICENSE: + * license/LICENSE.compress-lzf.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/ning/compress + +This product optionally depends on 'lz4', a LZ4 Java compression +and decompression library written by Adrien Grand. It can be obtained at: + + * LICENSE: + * license/LICENSE.lz4.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jpountz/lz4-java + +This product optionally depends on 'lzma-java', a LZMA Java compression +and decompression library, which can be obtained at: + + * LICENSE: + * license/LICENSE.lzma-java.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jponge/lzma-java + +This product optionally depends on 'zstd-jni', a zstd-jni Java compression +and decompression library, which can be obtained at: + + * LICENSE: + * license/LICENSE.zstd-jni.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/luben/zstd-jni + +This product contains a modified portion of 'jfastlz', a Java port of FastLZ compression +and decompression library written by William Kinney. It can be obtained at: + + * LICENSE: + * license/LICENSE.jfastlz.txt (MIT License) + * HOMEPAGE: + * https://code.google.com/p/jfastlz/ + +This product contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data +interchange format, which can be obtained at: + + * LICENSE: + * license/LICENSE.protobuf.txt (New BSD License) + * HOMEPAGE: + * https://github.com/google/protobuf + +This product optionally depends on 'Bouncy Castle Crypto APIs' to generate +a temporary self-signed X.509 certificate when the JVM does not provide the +equivalent functionality. It can be obtained at: + + * LICENSE: + * license/LICENSE.bouncycastle.txt (MIT License) + * HOMEPAGE: + * https://www.bouncycastle.org/ + +This product optionally depends on 'Snappy', a compression library produced +by Google Inc, which can be obtained at: + + * LICENSE: + * license/LICENSE.snappy.txt (New BSD License) + * HOMEPAGE: + * https://github.com/google/snappy + +This product optionally depends on 'JBoss Marshalling', an alternative Java +serialization API, which can be obtained at: + + * LICENSE: + * license/LICENSE.jboss-marshalling.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jboss-remoting/jboss-marshalling + +This product optionally depends on 'Caliper', Google's micro- +benchmarking framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.caliper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/google/caliper + +This product optionally depends on 'Apache Commons Logging', a logging +framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-logging.txt (Apache License 2.0) + * HOMEPAGE: + * https://commons.apache.org/logging/ + +This product optionally depends on 'Apache Log4J', a logging framework, which +can be obtained at: + + * LICENSE: + * license/LICENSE.log4j.txt (Apache License 2.0) + * HOMEPAGE: + * https://logging.apache.org/log4j/ + +This product optionally depends on 'Aalto XML', an ultra-high performance +non-blocking XML processor, which can be obtained at: + + * LICENSE: + * license/LICENSE.aalto-xml.txt (Apache License 2.0) + * HOMEPAGE: + * https://wiki.fasterxml.com/AaltoHome + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Twitter. It can be obtained at: + + * LICENSE: + * license/LICENSE.hpack.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/twitter/hpack + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Cory Benfield. It can be obtained at: + + * LICENSE: + * license/LICENSE.hyper-hpack.txt (MIT License) + * HOMEPAGE: + * https://github.com/python-hyper/hpack/ + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Tatsuhiro Tsujikawa. It can be obtained at: + + * LICENSE: + * license/LICENSE.nghttp2-hpack.txt (MIT License) + * HOMEPAGE: + * https://github.com/nghttp2/nghttp2/ + +This product contains a modified portion of 'Apache Commons Lang', a Java library +provides utilities for the java.lang API, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-lang.txt (Apache License 2.0) + * HOMEPAGE: + * https://commons.apache.org/proper/commons-lang/ + + +This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. + + * LICENSE: + * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/takari/maven-wrapper + +This product contains the dnsinfo.h header file, that provides a way to retrieve the system DNS configuration on MacOS. +This private header is also used by Apple's open source + mDNSResponder (https://opensource.apple.com/tarballs/mDNSResponder/). + + * LICENSE: + * license/LICENSE.dnsinfo.txt (Apple Public Source License 2.0) + * HOMEPAGE: + * https://www.opensource.apple.com/source/configd/configd-453.19/dnsinfo/dnsinfo.h + +This product optionally depends on 'Brotli4j', Brotli compression and +decompression for Java., which can be obtained at: + + * LICENSE: + * license/LICENSE.brotli4j.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/hyperxpro/Brotli4j From 12e3e3ea027c51c5807e5e46ba542f894edfa4e7 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Thu, 16 Nov 2023 23:15:10 -0800 Subject: [PATCH 288/395] Add LICENSE and NOTICE.txt/NOTICE_binary to published jars LICENSE + NOTICE.txt is added to source jars, LICENSE + NOTICE_binary.txt is added to regular jars. Make parent project inherit from apache pom. Updated NOTICE wording to "developed at ..." per latest instructions. patch by Henry Hughes; reviewed by Mick Semb Wever for CASSANDRA-18969 --- NOTICE.txt | 243 +----------------- NOTICE_binary.txt | 249 +++++++++++++++++++ core-shaded/pom.xml | 13 + core/pom.xml | 8 + distribution/src/assembly/binary-tarball.xml | 1 + mapper-processor/pom.xml | 13 + mapper-runtime/pom.xml | 13 + metrics/micrometer/pom.xml | 13 + metrics/microprofile/pom.xml | 13 + pom.xml | 21 ++ query-builder/pom.xml | 13 + test-infra/pom.xml | 13 + 12 files changed, 371 insertions(+), 242 deletions(-) create mode 100644 NOTICE_binary.txt diff --git a/NOTICE.txt b/NOTICE.txt index b7a91be2318..8e27ae3e52f 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,246 +1,5 @@ Apache Cassandra Java Driver Copyright 2012- The Apache Software Foundation -This product includes software developed by The Apache Software +This product includes software developed at The Apache Software Foundation (http://www.apache.org/). - -================================================================== -io.netty:netty-handler NOTICE.txt -================================================================== -This product contains the extensions to Java Collections Framework which has -been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: - - * LICENSE: - * license/LICENSE.jsr166y.txt (Public Domain) - * HOMEPAGE: - * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ - * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ - -This product contains a modified version of Robert Harder's Public Domain -Base64 Encoder and Decoder, which can be obtained at: - - * LICENSE: - * license/LICENSE.base64.txt (Public Domain) - * HOMEPAGE: - * http://iharder.sourceforge.net/current/java/base64/ - -This product contains a modified portion of 'Webbit', an event based -WebSocket and HTTP server, which can be obtained at: - - * LICENSE: - * license/LICENSE.webbit.txt (BSD License) - * HOMEPAGE: - * https://github.com/joewalnes/webbit - -This product contains a modified portion of 'SLF4J', a simple logging -facade for Java, which can be obtained at: - - * LICENSE: - * license/LICENSE.slf4j.txt (MIT License) - * HOMEPAGE: - * https://www.slf4j.org/ - -This product contains a modified portion of 'Apache Harmony', an open source -Java SE, which can be obtained at: - - * NOTICE: - * license/NOTICE.harmony.txt - * LICENSE: - * license/LICENSE.harmony.txt (Apache License 2.0) - * HOMEPAGE: - * https://archive.apache.org/dist/harmony/ - -This product contains a modified portion of 'jbzip2', a Java bzip2 compression -and decompression library written by Matthew J. Francis. It can be obtained at: - - * LICENSE: - * license/LICENSE.jbzip2.txt (MIT License) - * HOMEPAGE: - * https://code.google.com/p/jbzip2/ - -This product contains a modified portion of 'libdivsufsort', a C API library to construct -the suffix array and the Burrows-Wheeler transformed string for any input string of -a constant-size alphabet written by Yuta Mori. It can be obtained at: - - * LICENSE: - * license/LICENSE.libdivsufsort.txt (MIT License) - * HOMEPAGE: - * https://github.com/y-256/libdivsufsort - -This product contains a modified portion of Nitsan Wakart's 'JCTools', Java Concurrency Tools for the JVM, - which can be obtained at: - - * LICENSE: - * license/LICENSE.jctools.txt (ASL2 License) - * HOMEPAGE: - * https://github.com/JCTools/JCTools - -This product optionally depends on 'JZlib', a re-implementation of zlib in -pure Java, which can be obtained at: - - * LICENSE: - * license/LICENSE.jzlib.txt (BSD style License) - * HOMEPAGE: - * http://www.jcraft.com/jzlib/ - -This product optionally depends on 'Compress-LZF', a Java library for encoding and -decoding data in LZF format, written by Tatu Saloranta. It can be obtained at: - - * LICENSE: - * license/LICENSE.compress-lzf.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/ning/compress - -This product optionally depends on 'lz4', a LZ4 Java compression -and decompression library written by Adrien Grand. It can be obtained at: - - * LICENSE: - * license/LICENSE.lz4.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/jpountz/lz4-java - -This product optionally depends on 'lzma-java', a LZMA Java compression -and decompression library, which can be obtained at: - - * LICENSE: - * license/LICENSE.lzma-java.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/jponge/lzma-java - -This product optionally depends on 'zstd-jni', a zstd-jni Java compression -and decompression library, which can be obtained at: - - * LICENSE: - * license/LICENSE.zstd-jni.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/luben/zstd-jni - -This product contains a modified portion of 'jfastlz', a Java port of FastLZ compression -and decompression library written by William Kinney. It can be obtained at: - - * LICENSE: - * license/LICENSE.jfastlz.txt (MIT License) - * HOMEPAGE: - * https://code.google.com/p/jfastlz/ - -This product contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data -interchange format, which can be obtained at: - - * LICENSE: - * license/LICENSE.protobuf.txt (New BSD License) - * HOMEPAGE: - * https://github.com/google/protobuf - -This product optionally depends on 'Bouncy Castle Crypto APIs' to generate -a temporary self-signed X.509 certificate when the JVM does not provide the -equivalent functionality. It can be obtained at: - - * LICENSE: - * license/LICENSE.bouncycastle.txt (MIT License) - * HOMEPAGE: - * https://www.bouncycastle.org/ - -This product optionally depends on 'Snappy', a compression library produced -by Google Inc, which can be obtained at: - - * LICENSE: - * license/LICENSE.snappy.txt (New BSD License) - * HOMEPAGE: - * https://github.com/google/snappy - -This product optionally depends on 'JBoss Marshalling', an alternative Java -serialization API, which can be obtained at: - - * LICENSE: - * license/LICENSE.jboss-marshalling.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/jboss-remoting/jboss-marshalling - -This product optionally depends on 'Caliper', Google's micro- -benchmarking framework, which can be obtained at: - - * LICENSE: - * license/LICENSE.caliper.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/google/caliper - -This product optionally depends on 'Apache Commons Logging', a logging -framework, which can be obtained at: - - * LICENSE: - * license/LICENSE.commons-logging.txt (Apache License 2.0) - * HOMEPAGE: - * https://commons.apache.org/logging/ - -This product optionally depends on 'Apache Log4J', a logging framework, which -can be obtained at: - - * LICENSE: - * license/LICENSE.log4j.txt (Apache License 2.0) - * HOMEPAGE: - * https://logging.apache.org/log4j/ - -This product optionally depends on 'Aalto XML', an ultra-high performance -non-blocking XML processor, which can be obtained at: - - * LICENSE: - * license/LICENSE.aalto-xml.txt (Apache License 2.0) - * HOMEPAGE: - * https://wiki.fasterxml.com/AaltoHome - -This product contains a modified version of 'HPACK', a Java implementation of -the HTTP/2 HPACK algorithm written by Twitter. It can be obtained at: - - * LICENSE: - * license/LICENSE.hpack.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/twitter/hpack - -This product contains a modified version of 'HPACK', a Java implementation of -the HTTP/2 HPACK algorithm written by Cory Benfield. It can be obtained at: - - * LICENSE: - * license/LICENSE.hyper-hpack.txt (MIT License) - * HOMEPAGE: - * https://github.com/python-hyper/hpack/ - -This product contains a modified version of 'HPACK', a Java implementation of -the HTTP/2 HPACK algorithm written by Tatsuhiro Tsujikawa. It can be obtained at: - - * LICENSE: - * license/LICENSE.nghttp2-hpack.txt (MIT License) - * HOMEPAGE: - * https://github.com/nghttp2/nghttp2/ - -This product contains a modified portion of 'Apache Commons Lang', a Java library -provides utilities for the java.lang API, which can be obtained at: - - * LICENSE: - * license/LICENSE.commons-lang.txt (Apache License 2.0) - * HOMEPAGE: - * https://commons.apache.org/proper/commons-lang/ - - -This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. - - * LICENSE: - * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/takari/maven-wrapper - -This product contains the dnsinfo.h header file, that provides a way to retrieve the system DNS configuration on MacOS. -This private header is also used by Apple's open source - mDNSResponder (https://opensource.apple.com/tarballs/mDNSResponder/). - - * LICENSE: - * license/LICENSE.dnsinfo.txt (Apple Public Source License 2.0) - * HOMEPAGE: - * https://www.opensource.apple.com/source/configd/configd-453.19/dnsinfo/dnsinfo.h - -This product optionally depends on 'Brotli4j', Brotli compression and -decompression for Java., which can be obtained at: - - * LICENSE: - * license/LICENSE.brotli4j.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/hyperxpro/Brotli4j diff --git a/NOTICE_binary.txt b/NOTICE_binary.txt new file mode 100644 index 00000000000..c60d8ceb245 --- /dev/null +++ b/NOTICE_binary.txt @@ -0,0 +1,249 @@ +Apache Cassandra Java Driver +Copyright 2012- The Apache Software Foundation + +This product includes software developed at The Apache Software +Foundation (http://www.apache.org/). + +This compiled product also includes Apache-licensed dependencies +that contain the following NOTICE information: + +================================================================== +io.netty:netty-handler NOTICE.txt +================================================================== +This product contains the extensions to Java Collections Framework which has +been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: + + * LICENSE: + * license/LICENSE.jsr166y.txt (Public Domain) + * HOMEPAGE: + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ + * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ + +This product contains a modified version of Robert Harder's Public Domain +Base64 Encoder and Decoder, which can be obtained at: + + * LICENSE: + * license/LICENSE.base64.txt (Public Domain) + * HOMEPAGE: + * http://iharder.sourceforge.net/current/java/base64/ + +This product contains a modified portion of 'Webbit', an event based +WebSocket and HTTP server, which can be obtained at: + + * LICENSE: + * license/LICENSE.webbit.txt (BSD License) + * HOMEPAGE: + * https://github.com/joewalnes/webbit + +This product contains a modified portion of 'SLF4J', a simple logging +facade for Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.slf4j.txt (MIT License) + * HOMEPAGE: + * https://www.slf4j.org/ + +This product contains a modified portion of 'Apache Harmony', an open source +Java SE, which can be obtained at: + + * NOTICE: + * license/NOTICE.harmony.txt + * LICENSE: + * license/LICENSE.harmony.txt (Apache License 2.0) + * HOMEPAGE: + * https://archive.apache.org/dist/harmony/ + +This product contains a modified portion of 'jbzip2', a Java bzip2 compression +and decompression library written by Matthew J. Francis. It can be obtained at: + + * LICENSE: + * license/LICENSE.jbzip2.txt (MIT License) + * HOMEPAGE: + * https://code.google.com/p/jbzip2/ + +This product contains a modified portion of 'libdivsufsort', a C API library to construct +the suffix array and the Burrows-Wheeler transformed string for any input string of +a constant-size alphabet written by Yuta Mori. It can be obtained at: + + * LICENSE: + * license/LICENSE.libdivsufsort.txt (MIT License) + * HOMEPAGE: + * https://github.com/y-256/libdivsufsort + +This product contains a modified portion of Nitsan Wakart's 'JCTools', Java Concurrency Tools for the JVM, + which can be obtained at: + + * LICENSE: + * license/LICENSE.jctools.txt (ASL2 License) + * HOMEPAGE: + * https://github.com/JCTools/JCTools + +This product optionally depends on 'JZlib', a re-implementation of zlib in +pure Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.jzlib.txt (BSD style License) + * HOMEPAGE: + * http://www.jcraft.com/jzlib/ + +This product optionally depends on 'Compress-LZF', a Java library for encoding and +decoding data in LZF format, written by Tatu Saloranta. It can be obtained at: + + * LICENSE: + * license/LICENSE.compress-lzf.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/ning/compress + +This product optionally depends on 'lz4', a LZ4 Java compression +and decompression library written by Adrien Grand. It can be obtained at: + + * LICENSE: + * license/LICENSE.lz4.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jpountz/lz4-java + +This product optionally depends on 'lzma-java', a LZMA Java compression +and decompression library, which can be obtained at: + + * LICENSE: + * license/LICENSE.lzma-java.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jponge/lzma-java + +This product optionally depends on 'zstd-jni', a zstd-jni Java compression +and decompression library, which can be obtained at: + + * LICENSE: + * license/LICENSE.zstd-jni.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/luben/zstd-jni + +This product contains a modified portion of 'jfastlz', a Java port of FastLZ compression +and decompression library written by William Kinney. It can be obtained at: + + * LICENSE: + * license/LICENSE.jfastlz.txt (MIT License) + * HOMEPAGE: + * https://code.google.com/p/jfastlz/ + +This product contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data +interchange format, which can be obtained at: + + * LICENSE: + * license/LICENSE.protobuf.txt (New BSD License) + * HOMEPAGE: + * https://github.com/google/protobuf + +This product optionally depends on 'Bouncy Castle Crypto APIs' to generate +a temporary self-signed X.509 certificate when the JVM does not provide the +equivalent functionality. It can be obtained at: + + * LICENSE: + * license/LICENSE.bouncycastle.txt (MIT License) + * HOMEPAGE: + * https://www.bouncycastle.org/ + +This product optionally depends on 'Snappy', a compression library produced +by Google Inc, which can be obtained at: + + * LICENSE: + * license/LICENSE.snappy.txt (New BSD License) + * HOMEPAGE: + * https://github.com/google/snappy + +This product optionally depends on 'JBoss Marshalling', an alternative Java +serialization API, which can be obtained at: + + * LICENSE: + * license/LICENSE.jboss-marshalling.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jboss-remoting/jboss-marshalling + +This product optionally depends on 'Caliper', Google's micro- +benchmarking framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.caliper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/google/caliper + +This product optionally depends on 'Apache Commons Logging', a logging +framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-logging.txt (Apache License 2.0) + * HOMEPAGE: + * https://commons.apache.org/logging/ + +This product optionally depends on 'Apache Log4J', a logging framework, which +can be obtained at: + + * LICENSE: + * license/LICENSE.log4j.txt (Apache License 2.0) + * HOMEPAGE: + * https://logging.apache.org/log4j/ + +This product optionally depends on 'Aalto XML', an ultra-high performance +non-blocking XML processor, which can be obtained at: + + * LICENSE: + * license/LICENSE.aalto-xml.txt (Apache License 2.0) + * HOMEPAGE: + * https://wiki.fasterxml.com/AaltoHome + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Twitter. It can be obtained at: + + * LICENSE: + * license/LICENSE.hpack.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/twitter/hpack + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Cory Benfield. It can be obtained at: + + * LICENSE: + * license/LICENSE.hyper-hpack.txt (MIT License) + * HOMEPAGE: + * https://github.com/python-hyper/hpack/ + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Tatsuhiro Tsujikawa. It can be obtained at: + + * LICENSE: + * license/LICENSE.nghttp2-hpack.txt (MIT License) + * HOMEPAGE: + * https://github.com/nghttp2/nghttp2/ + +This product contains a modified portion of 'Apache Commons Lang', a Java library +provides utilities for the java.lang API, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-lang.txt (Apache License 2.0) + * HOMEPAGE: + * https://commons.apache.org/proper/commons-lang/ + + +This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. + + * LICENSE: + * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/takari/maven-wrapper + +This product contains the dnsinfo.h header file, that provides a way to retrieve the system DNS configuration on MacOS. +This private header is also used by Apple's open source + mDNSResponder (https://opensource.apple.com/tarballs/mDNSResponder/). + + * LICENSE: + * license/LICENSE.dnsinfo.txt (Apple Public Source License 2.0) + * HOMEPAGE: + * https://www.opensource.apple.com/source/configd/configd-453.19/dnsinfo/dnsinfo.h + +This product optionally depends on 'Brotli4j', Brotli compression and +decompression for Java., which can be obtained at: + + * LICENSE: + * license/LICENSE.brotli4j.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/hyperxpro/Brotli4j diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index fa321503e02..e651ee1cf75 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -128,6 +128,19 @@ 4) assembly plugin re-creates the shaded jar by packing target/classes + manifest + shaded pom --> + + + src/main/resources + + + ${project.basedir}/.. + + LICENSE + NOTICE_binary.txt + + META-INF + + maven-shade-plugin diff --git a/core/pom.xml b/core/pom.xml index f4c7e2a5547..a1858c3afb0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -208,6 +208,14 @@ false + + ${project.basedir}/.. + + LICENSE + NOTICE_binary.txt + + META-INF + diff --git a/distribution/src/assembly/binary-tarball.xml b/distribution/src/assembly/binary-tarball.xml index 17364aa858a..9f44898713d 100644 --- a/distribution/src/assembly/binary-tarball.xml +++ b/distribution/src/assembly/binary-tarball.xml @@ -157,6 +157,7 @@ README* LICENSE* + NOTICE* diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index f9814b3dea4..f845bf85a07 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -99,6 +99,19 @@ + + + src/main/resources + + + ${project.basedir}/.. + + LICENSE + NOTICE_binary.txt + + META-INF + + src/test/resources diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 3957bbe1505..8967581e05a 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -96,6 +96,19 @@ + + + src/main/resources + + + ${project.basedir}/.. + + LICENSE + NOTICE_binary.txt + + META-INF + + src/test/resources diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 1c28b636b86..c202e9113d5 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -102,6 +102,19 @@ + + + src/main/resources + + + ${project.basedir}/../.. + + LICENSE + NOTICE_binary.txt + + META-INF + + maven-jar-plugin diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 0d2d5873330..f0045c35974 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -107,6 +107,19 @@ + + + src/main/resources + + + ${project.basedir}/../.. + + LICENSE + NOTICE_binary.txt + + META-INF + + maven-jar-plugin diff --git a/pom.xml b/pom.xml index 71ecd2a7915..aac375139b5 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,11 @@ --> 4.0.0 + + org.apache + apache + 23 + com.datastax.oss java-driver-parent 4.17.1-SNAPSHOT @@ -753,6 +758,14 @@ limitations under the License.]]> jar-no-fork + + + NOTICE.txt + + + NOTICE_binary.txt + + @@ -910,6 +923,14 @@ height="0" width="0" style="display:none;visibility:hidden"> + + org.apache.maven.plugins + maven-remote-resources-plugin + 1.7.0 + + true + + diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 5ecbebf367b..d35fd834748 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -81,6 +81,19 @@ + + + src/main/resources + + + ${project.basedir}/.. + + LICENSE + NOTICE_binary.txt + + META-INF + + src/test/resources diff --git a/test-infra/pom.xml b/test-infra/pom.xml index cf1da84f7dd..3b20ad2f4f1 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -76,6 +76,19 @@ + + + src/main/resources + + + ${project.basedir}/.. + + LICENSE + NOTICE_binary.txt + + META-INF + + maven-jar-plugin From f11622308d031bf85047c4811e737aeb6ae236e9 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Mon, 4 Dec 2023 13:01:09 -0800 Subject: [PATCH 289/395] Compliance changes for generated source and binary distributable tarballs * Source files missing from sources jars due to maven-source-plugin include rule * New submodule to generate distribution source tarball * Binary/source tarball artifacts should be prefixed with apache-cassandra * Change groupId to org.apache.cassandra * Remove javadoc jars (javadoc plugin is still used for leak detections) * Create binary versions for LICENSE and NOTICE, with licenses and entries for asm, HdrHistogram, jnr-posix, jnr-x86asm, reactive-streams, slf4j-api * Add checksums to distribution tarballs, and clean toplevel readme a little patch by Henry Hughes; reviewed by Mick Semb Wever for CASSANDRA-18969 --- .github/workflows/dep-lic-scan.yaml | 16 + LICENSE_binary | 247 ++++ README.md | 21 +- bom/pom.xml | 18 +- core-shaded/pom.xml | 45 +- core/pom.xml | 3 +- core/src/main/resources/reference.conf | 4 +- distribution-source/pom.xml | 125 ++ .../src/assembly/source-tarball.xml | 43 + distribution-tests/pom.xml | 16 +- distribution/pom.xml | 62 +- distribution/src/assembly/binary-tarball.xml | 44 +- examples/pom.xml | 4 +- integration-tests/pom.xml | 16 +- licenses/HdrHistogram.txt | 41 + licenses/asm.txt | 27 + licenses/jnr-posix.txt | 1076 +++++++++++++++++ licenses/jnr-x86asm.txt | 24 + licenses/reactive-streams.txt | 7 + licenses/slf4j-api.txt | 21 + manual/core/README.md | 2 +- manual/core/bom/README.md | 12 +- manual/core/configuration/README.md | 2 +- manual/core/integration/README.md | 18 +- manual/core/metrics/README.md | 8 +- manual/core/shaded_jar/README.md | 10 +- manual/mapper/README.md | 4 +- manual/mapper/config/README.md | 8 +- manual/mapper/config/kotlin/README.md | 2 +- manual/query_builder/README.md | 2 +- mapper-processor/pom.xml | 7 +- mapper-runtime/pom.xml | 5 +- metrics/micrometer/pom.xml | 7 +- metrics/microprofile/pom.xml | 7 +- osgi-tests/pom.xml | 12 +- pom.xml | 39 +- query-builder/pom.xml | 7 +- test-infra/pom.xml | 5 +- 38 files changed, 1789 insertions(+), 228 deletions(-) create mode 100644 LICENSE_binary create mode 100644 distribution-source/pom.xml create mode 100644 distribution-source/src/assembly/source-tarball.xml create mode 100644 licenses/HdrHistogram.txt create mode 100644 licenses/asm.txt create mode 100644 licenses/jnr-posix.txt create mode 100644 licenses/jnr-x86asm.txt create mode 100644 licenses/reactive-streams.txt create mode 100644 licenses/slf4j-api.txt diff --git a/.github/workflows/dep-lic-scan.yaml b/.github/workflows/dep-lic-scan.yaml index afb197bf137..54fabe2dc8f 100644 --- a/.github/workflows/dep-lic-scan.yaml +++ b/.github/workflows/dep-lic-scan.yaml @@ -1,3 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# name: Dependency and License Scan on: push: diff --git a/LICENSE_binary b/LICENSE_binary new file mode 100644 index 00000000000..b59c6ec22bb --- /dev/null +++ b/LICENSE_binary @@ -0,0 +1,247 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Apache Cassandra Java Driver bundles code and files from the following projects: + +JNR project +Copyright (C) 2008-2010 Wayne Meissner +This product includes software developed as part of the JNR project ( https://github.com/jnr/jnr-ffi )s. +see core/src/main/java/com/datastax/oss/driver/internal/core/os/CpuInfo.java + +Protocol Buffers +Copyright 2008 Google Inc. +This product includes software developed as part of the Protocol Buffers project ( https://developers.google.com/protocol-buffers/ ). +see core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java + +Guava +Copyright (C) 2007 The Guava Authors +This product includes software developed as part of the Guava project ( https://guava.dev ). +see core/src/main/java/com/datastax/oss/driver/internal/core/util/CountingIterator.java + +Copyright (C) 2018 Christian Stein +This product includes software developed by Christian Stein +see ci/install-jdk.sh + +This product bundles Java Native Runtime - POSIX 3.1.15, +which is available under the Eclipse Public License version 2.0. +see licenses/jnr-posix.txt + +This product bundles jnr-x86asm 1.0.2, +which is available under the MIT License. +see licenses/jnr-x86asm.txt + +This product bundles ASM 9.2: a very small and fast Java bytecode manipulation framework, +which is available under the 3-Clause BSD License. +see licenses/asm.txt + +This product bundles HdrHistogram 2.1.12: A High Dynamic Range (HDR) Histogram, +which is available under the 2-Clause BSD License. +see licenses/HdrHistogram.txt + +This product bundles The Simple Logging Facade for Java (SLF4J) API 1.7.26, +which is available under the MIT License. +see licenses/slf4j-api.txt + +This product bundles Reactive Streams 1.0.3, +which is available under the MIT License. +see licenses/reactive-streams.txt diff --git a/README.md b/README.md index b43b90b71d8..2e8fe862f49 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Java Driver for Apache Cassandra® +:warning: The java-driver has recently been donated by Datastax to The Apache Software Foundation and the Apache Cassandra project. Bear with us as we move assets and coordinates. + [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core) *If you're reading this on github.com, please note that this is the readme for the development @@ -13,8 +15,6 @@ and Cassandra Query Language (CQL) v3. [DataStax Docs]: http://docs.datastax.com/en/developer/java-driver/ [Apache Cassandra®]: http://cassandra.apache.org/ -[DataStax Enterprise]: https://www.datastax.com/products/datastax-enterprise -[DataStax Astra]: https://www.datastax.com/products/datastax-astra ## Getting the driver @@ -23,19 +23,19 @@ are multiple modules, all prefixed with `java-driver-`. ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} - com.datastax.oss + org.apache.cassandra java-driver-query-builder ${driver.version} - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime ${driver.version} @@ -59,11 +59,6 @@ It requires Java 8 or higher. Disclaimer: Some DataStax/DataStax Enterprise products might partially work on big-endian systems, but DataStax does not officially support these systems. -## Connecting to DataStax Astra - -The driver comes with built-in support for Astra, DataStax's cloud-native Cassandra-as-a-service -offering. See the dedicated [manual page](manual/cloud/) for more details. - ## Migrating from previous versions Java Driver 4 is **not binary compatible** with previous versions. However, most of the concepts @@ -81,16 +76,12 @@ See the [Cassandra error handling done right blog](https://www.datastax.com/blog * [API docs] * Bug tracking: [JIRA] * [Mailing list] -* Twitter: [@dsJavaDriver] tweets Java Driver releases and important announcements (low frequency). - [@DataStaxEng] has more news, including other drivers, Cassandra, and DSE. * [Changelog] * [FAQ] [API docs]: https://docs.datastax.com/en/drivers/java/4.17 [JIRA]: https://datastax-oss.atlassian.net/browse/JAVA [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user -[@dsJavaDriver]: https://twitter.com/dsJavaDriver -[@DataStaxEng]: https://twitter.com/datastaxeng [Changelog]: changelog/ [FAQ]: faq/ @@ -115,3 +106,5 @@ limitations under the License. Apache Cassandra, Apache, Tomcat, Lucene, Solr, Hadoop, Spark, TinkerPop, and Cassandra are trademarks of the [Apache Software Foundation](http://www.apache.org/) or its subsidiaries in Canada, the United States and/or other countries. + +Binary artifacts of this product bundle Java Native Runtime libraries, which is available under the Eclipse Public License version 2.0. \ No newline at end of file diff --git a/bom/pom.xml b/bom/pom.xml index 33c454fcf75..973171c5c5d 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -31,42 +31,42 @@ - com.datastax.oss + org.apache.cassandra java-driver-core 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-core-shaded 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-query-builder 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-test-infra 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-metrics-micrometer 4.17.1-SNAPSHOT - com.datastax.oss + org.apache.cassandra java-driver-metrics-microprofile 4.17.1-SNAPSHOT diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index e651ee1cf75..55250d59d6e 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -44,7 +44,7 @@ this dependency will be removed from the final pom by the shade plugin. --> - com.datastax.oss + org.apache.cassandra java-driver-core - com.datastax.oss:java-driver-core + org.apache.cassandra:java-driver-core io.netty:* com.fasterxml.jackson.core:* @@ -183,7 +184,7 @@ - com.datastax.oss:* + org.apache.cassandra:* META-INF/MANIFEST.MF @@ -219,7 +220,7 @@ - com.datastax.oss + org.apache.cassandra java-driver-core-shaded jar ${project.build.outputDirectory} @@ -237,7 +238,7 @@ - com.datastax.oss + org.apache.cassandra java-driver-core-shaded jar sources @@ -273,38 +274,6 @@ - - maven-javadoc-plugin - - - attach-javadocs - - jar - - - ${project.build.directory}/shaded-sources - com.datastax.*.driver.internal*,com.datastax.oss.driver.shaded* - - - - org.jctools - jctools-core - 2.1.2 - - - com.esri.geometry - esri-geometry-api - 1.2.1 - - - - - - org.apache.felix maven-bundle-plugin diff --git a/core/pom.xml b/core/pom.xml index a1858c3afb0..ebe7a286b21 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -213,6 +213,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 9e4fb9c7948..75bed97e498 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1370,8 +1370,8 @@ datastax-java-driver { # To select Micrometer, set the value to "MicrometerMetricsFactory", and to select # MicroProfile Metrics, set the value to "MicroProfileMetricsFactory". For these libraries to # be used, you will also need to add an additional dependency: - # - Micrometer: com.datastax.oss:java-driver-metrics-micrometer - # - MicroProfile: com.datastax.oss:java-driver-metrics-microprofile + # - Micrometer: org.apache.cassandra:java-driver-metrics-micrometer + # - MicroProfile: org.apache.cassandra:java-driver-metrics-microprofile # # If you would like to use another metrics library, set this value to the fully-qualified name # of a class that implements com.datastax.oss.driver.internal.core.metrics.MetricsFactory. diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml new file mode 100644 index 00000000000..d4db09c7091 --- /dev/null +++ b/distribution-source/pom.xml @@ -0,0 +1,125 @@ + + + + 4.0.0 + + org.apache.cassandra + java-driver-parent + 4.17.1-SNAPSHOT + + java-driver-distribution-source + pom + Apache Cassandra Java Driver - source distribution + + apache-cassandra-java-driver-${project.version}-source + + + maven-jar-plugin + + + + default-jar + none + + + + + maven-source-plugin + + true + + + + maven-install-plugin + + true + + + + maven-deploy-plugin + + true + + + + org.revapi + revapi-maven-plugin + + true + + + + org.sonatype.plugins + nexus-staging-maven-plugin + + true + + + + + + + release + + + + maven-assembly-plugin + + + assemble-source-tarball + package + + single + + + + + false + + src/assembly/source-tarball.xml + + posix + + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + 1.7 + + + + artifacts + + + + + true + + sha256 + sha512 + + + + + + + + diff --git a/distribution-source/src/assembly/source-tarball.xml b/distribution-source/src/assembly/source-tarball.xml new file mode 100644 index 00000000000..b3e2d0f463a --- /dev/null +++ b/distribution-source/src/assembly/source-tarball.xml @@ -0,0 +1,43 @@ + + + + source-tarball + + tar.gz + + + + .. + . + true + + + **/*.iml + **/.classpath + **/.project + **/.java-version + **/.flattened-pom.xml + **/dependency-reduced-pom.xml + **/${project.build.directory}/** + + + + diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index ba1bae8511b..fd5378afc25 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -40,37 +40,37 @@ - com.datastax.oss + org.apache.cassandra java-driver-test-infra test - com.datastax.oss + org.apache.cassandra java-driver-query-builder test - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor test - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime test - com.datastax.oss + org.apache.cassandra java-driver-core test - com.datastax.oss + org.apache.cassandra java-driver-metrics-micrometer test - com.datastax.oss + org.apache.cassandra java-driver-metrics-microprofile test diff --git a/distribution/pom.xml b/distribution/pom.xml index 0a1d3d71e65..706157d9a98 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -67,7 +67,7 @@ - datastax-java-driver-${project.version} + apache-cassandra-java-driver-${project.version} maven-jar-plugin @@ -118,45 +118,6 @@ release - - maven-javadoc-plugin - - - attach-javadocs - package - - jar - - - true - Java Driver for Apache Cassandra® ${project.version} API - Apache Cassandra Java Driver ${project.version} API - - - org.lz4 - lz4-java - ${lz4.version} - - - org.xerial.snappy - snappy-java - ${snappy.version} - - - org.apache.tinkerpop - gremlin-core - ${tinkerpop.version} - - - org.apache.tinkerpop - tinkergraph-gremlin - ${tinkerpop.version} - - - - - - maven-assembly-plugin @@ -176,6 +137,25 @@ posix + + net.nicoulaj.maven.plugins + checksum-maven-plugin + 1.7 + + + + artifacts + + + + + true + + sha256 + sha512 + + + diff --git a/distribution/src/assembly/binary-tarball.xml b/distribution/src/assembly/binary-tarball.xml index 9f44898713d..0d025fafb2c 100644 --- a/distribution/src/assembly/binary-tarball.xml +++ b/distribution/src/assembly/binary-tarball.xml @@ -29,7 +29,7 @@ true - com.datastax.oss:java-driver-core + org.apache.cassandra:java-driver-core lib/core @@ -42,9 +42,9 @@ For some reason, we need to exclude all other modules here, even though our moduleSet targets core only --> - com.datastax.oss:java-driver-query-builder - com.datastax.oss:java-driver-mapper-runtime - com.datastax.oss:java-driver-mapper-processor + org.apache.cassandra:java-driver-query-builder + org.apache.cassandra:java-driver-mapper-runtime + org.apache.cassandra:java-driver-mapper-processor true @@ -55,7 +55,7 @@ true - com.datastax.oss:java-driver-query-builder + org.apache.cassandra:java-driver-query-builder lib/query-builder @@ -63,9 +63,9 @@ - com.datastax.oss:java-driver-core - com.datastax.oss:java-driver-mapper-runtime - com.datastax.oss:java-driver-mapper-processor + org.apache.cassandra:java-driver-core + org.apache.cassandra:java-driver-mapper-runtime + org.apache.cassandra:java-driver-mapper-processor com.datastax.oss:java-driver-shaded-guava com.github.stephenc.jcip:jcip-annotations @@ -80,7 +80,7 @@ true - com.datastax.oss:java-driver-mapper-runtime + org.apache.cassandra:java-driver-mapper-runtime lib/mapper-runtime @@ -88,9 +88,9 @@ - com.datastax.oss:java-driver-core - com.datastax.oss:java-driver-query-builder - com.datastax.oss:java-driver-mapper-processor + org.apache.cassandra:java-driver-core + org.apache.cassandra:java-driver-query-builder + org.apache.cassandra:java-driver-mapper-processor com.datastax.oss:java-driver-shaded-guava com.github.stephenc.jcip:jcip-annotations @@ -105,7 +105,7 @@ true - com.datastax.oss:java-driver-mapper-processor + org.apache.cassandra:java-driver-mapper-processor lib/mapper-processor @@ -113,9 +113,9 @@ - com.datastax.oss:java-driver-core - com.datastax.oss:java-driver-query-builder - com.datastax.oss:java-driver-mapper-runtime + org.apache.cassandra:java-driver-core + org.apache.cassandra:java-driver-query-builder + org.apache.cassandra:java-driver-mapper-runtime com.datastax.oss:java-driver-shaded-guava com.github.stephenc.jcip:jcip-annotations @@ -130,10 +130,10 @@ true - com.datastax.oss:java-driver-core - com.datastax.oss:java-driver-query-builder - com.datastax.oss:java-driver-mapper-runtime - com.datastax.oss:java-driver-mapper-processor + org.apache.cassandra:java-driver-core + org.apache.cassandra:java-driver-query-builder + org.apache.cassandra:java-driver-mapper-runtime + org.apache.cassandra:java-driver-mapper-processor false @@ -156,8 +156,8 @@ . README* - LICENSE* - NOTICE* + LICENSE_binary + NOTICE_binary.txt diff --git a/examples/pom.xml b/examples/pom.xml index a597f634d9a..c971c0355ae 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -22,7 +22,7 @@ 4.0.0 java-driver-parent - com.datastax.oss + org.apache.cassandra 4.17.1-SNAPSHOT java-driver-examples @@ -157,7 +157,7 @@ 1.8 - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor ${project.version} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index db77efb5166..5e12c2f9ae2 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -47,39 +47,39 @@ - com.datastax.oss + org.apache.cassandra java-driver-test-infra test - com.datastax.oss + org.apache.cassandra java-driver-query-builder test - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor test true - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime test - com.datastax.oss + org.apache.cassandra java-driver-core test-jar test - com.datastax.oss + org.apache.cassandra java-driver-metrics-micrometer test - com.datastax.oss + org.apache.cassandra java-driver-metrics-microprofile test diff --git a/licenses/HdrHistogram.txt b/licenses/HdrHistogram.txt new file mode 100644 index 00000000000..401ccfb0ec5 --- /dev/null +++ b/licenses/HdrHistogram.txt @@ -0,0 +1,41 @@ +The code in this repository code was Written by Gil Tene, Michael Barker, +and Matt Warren, and released to the public domain, as explained at +http://creativecommons.org/publicdomain/zero/1.0/ + +For users of this code who wish to consume it under the "BSD" license +rather than under the public domain or CC0 contribution text mentioned +above, the code found under this directory is *also* provided under the +following license (commonly referred to as the BSD 2-Clause License). This +license does not detract from the above stated release of the code into +the public domain, and simply represents an additional license granted by +the Author. + +----------------------------------------------------------------------------- +** Beginning of "BSD 2-Clause License" text. ** + + Copyright (c) 2012, 2013, 2014, 2015, 2016 Gil Tene + Copyright (c) 2014 Michael Barker + Copyright (c) 2014 Matt Warren + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/asm.txt b/licenses/asm.txt new file mode 100644 index 00000000000..c71bb7bac5d --- /dev/null +++ b/licenses/asm.txt @@ -0,0 +1,27 @@ +ASM: a very small and fast Java bytecode manipulation framework +Copyright (c) 2000-2011 INRIA, France Telecom +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/jnr-posix.txt b/licenses/jnr-posix.txt new file mode 100644 index 00000000000..4dc4217a306 --- /dev/null +++ b/licenses/jnr-posix.txt @@ -0,0 +1,1076 @@ +jnr-posix is released under a tri EPL/GPL/LGPL license. You can use it, +redistribute it and/or modify it under the terms of the: + + Eclipse Public License version 2.0 + OR + GNU General Public License version 2 + OR + GNU Lesser General Public License version 2.1 + +The complete text of the Eclipse Public License is as follows: + + Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + + "Contributor" means any person or entity that Distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions Distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement + or any Secondary License (as applicable), including Contributors. + + "Derivative Works" shall mean any work, whether in Source Code or other + form, that is based on (or derived from) the Program and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. + + "Modified Works" shall mean any work in Source Code or other form that + results from an addition to, deletion from, or modification of the + contents of the Program, including, for purposes of clarity any new file + in Source Code form that contains any contents of the Program. Modified + Works shall not include works that contain only declarations, + interfaces, types, classes, structures, or files of the Program solely + in each case in order to link to, bind by name, or subclass the Program + or Modified Works thereof. + + "Distribute" means the acts of a) distributing or b) making available + in any manner that enables the transfer of a copy. + + "Source Code" means the form of a Program preferred for making + modifications, including but not limited to software source code, + documentation source, and configuration files. + + "Secondary License" means either the GNU General Public License, + Version 2.0, or any later versions of that license, including any + exceptions or additional permissions as identified by the initial + Contributor. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + + 3. REQUIREMENTS + + 3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + + 3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + + 3.3 Contributors may not remove or alter any copyright, patent, + trademark, attribution notices, disclaimers of warranty, or limitations + of liability ("notices") contained within the Program from any copy of + the Program which they Distribute, provided that Contributors may add + their own appropriate notices. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the Indemnified + Contributor to the extent caused by the acts or omissions of such + Commercial Contributor in connection with its distribution of the Program + in a commercial product offering. The obligations in this section do not + apply to any claims or Losses relating to any actual or alleged + intellectual property infringement. In order to qualify, an Indemnified + Contributor must: a) promptly notify the Commercial Contributor in + writing of such claim, and b) allow the Commercial Contributor to control, + and cooperate with the Commercial Contributor in, the defense and any + related settlement negotiations. The Indemnified Contributor may + participate in any such claim at its own expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those performance + claims and warranties, and if a court requires any other Contributor to + pay any damages as a result, the Commercial Contributor must pay + those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR + IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF + TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. Each Recipient is solely responsible for determining the + appropriateness of using and distributing the Program and assumes all + risks associated with its exercise of rights under this Agreement, + including but not limited to the risks and costs of program errors, + compliance with applicable laws, damage to or loss of data, programs + or equipment, and unavailability or interruption of operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS + SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST + PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE + EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity + (including a cross-claim or counterclaim in a lawsuit) alleging that the + Program itself (excluding combinations of the Program with other software + or hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it + fails to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of + time after becoming aware of such noncompliance. If all Recipient's + rights under this Agreement terminate, Recipient agrees to cease use + and distribution of the Program as soon as reasonably practicable. + However, Recipient's obligations under this Agreement and any licenses + granted by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a distinguishing + version number. The Program (including Contributions) may always be + Distributed subject to the version of the Agreement under which it was + received. In addition, after a new version of the Agreement is published, + Contributor may elect to Distribute the Program (including its + Contributions) under the new version. + + Except as expressly stated in Sections 2(a) and 2(b) above, Recipient + receives no rights or licenses to the intellectual property of any + Contributor under this Agreement, whether expressly, by implication, + estoppel or otherwise. All rights in the Program not expressly granted + under this Agreement are reserved. Nothing in this Agreement is intended + to be enforceable by any entity that is not a Contributor or Recipient. + No third-party beneficiary rights are created under this Agreement. + + Exhibit A - Form of Secondary Licenses Notice + + "This Source Code may also be made available under the following + Secondary Licenses when the conditions for such availability set forth + in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), + version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. + +The complete text of the GNU General Public License v2 is as follows: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +The complete text of the GNU Lesser General Public License 2.1 is as follows: + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + Licenses are intended to guarantee your freedom to share and change + free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some + specially designated software packages--typically libraries--of the + Free Software Foundation and other authors who decide to use it. You + can use it too, but we suggest you first think carefully about whether + this license or the ordinary General Public License is the better + strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, + not price. Our General Public Licenses are designed to make sure that + you have the freedom to distribute copies of free software (and charge + for this service if you wish); that you receive source code or can get + it if you want it; that you can change the software and use pieces of + it in new free programs; and that you are informed that you can do + these things. + + To protect your rights, we need to make restrictions that forbid + distributors to deny you these rights or to ask you to surrender these + rights. These restrictions translate to certain responsibilities for + you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis + or for a fee, you must give the recipients all the rights that we gave + you. You must make sure that they, too, receive or can get the source + code. If you link other code with the library, you must provide + complete object files to the recipients, so that they can relink them + with the library after making changes to the library and recompiling + it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the + library, and (2) we offer you this license, which gives you legal + permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that + there is no warranty for the free library. Also, if the library is + modified by someone else and passed on, the recipients should know + that what they have is not the original version, so that the original + author's reputation will not be affected by problems that might be + introduced by others. + + Finally, software patents pose a constant threat to the existence of + any free program. We wish to make sure that a company cannot + effectively restrict the users of a free program by obtaining a + restrictive license from a patent holder. Therefore, we insist that + any patent license obtained for a version of the library must be + consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the + ordinary GNU General Public License. This license, the GNU Lesser + General Public License, applies to certain designated libraries, and + is quite different from the ordinary General Public License. We use + this license for certain libraries in order to permit linking those + libraries into non-free programs. + + When a program is linked with a library, whether statically or using + a shared library, the combination of the two is legally speaking a + combined work, a derivative of the original library. The ordinary + General Public License therefore permits such linking only if the + entire combination fits its criteria of freedom. The Lesser General + Public License permits more lax criteria for linking other code with + the library. + + We call this license the "Lesser" General Public License because it + does Less to protect the user's freedom than the ordinary General + Public License. It also provides other free software developers Less + of an advantage over competing non-free programs. These disadvantages + are the reason we use the ordinary General Public License for many + libraries. However, the Lesser license provides advantages in certain + special circumstances. + + For example, on rare occasions, there may be a special need to + encourage the widest possible use of a certain library, so that it becomes + a de-facto standard. To achieve this, non-free programs must be + allowed to use the library. A more frequent case is that a free + library does the same job as widely used non-free libraries. In this + case, there is little to gain by limiting the free library to free + software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free + programs enables a greater number of people to use a large body of + free software. For example, permission to use the GNU C Library in + non-free programs enables many more people to use the whole GNU + operating system, as well as its variant, the GNU/Linux operating + system. + + Although the Lesser General Public License is Less protective of the + users' freedom, it does ensure that the user of a program that is + linked with the Library has the freedom and the wherewithal to run + that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and + modification follow. Pay close attention to the difference between a + "work based on the library" and a "work that uses the library". The + former contains code derived from the library, whereas the latter must + be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other + program which contains a notice placed by the copyright holder or + other authorized party saying it may be distributed under the terms of + this Lesser General Public License (also called "this License"). + Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work + which has been distributed under these terms. A "work based on the + Library" means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or translated + straightforwardly into another language. (Hereinafter, translation is + included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for + making modifications to it. For a library, complete source code means + all the source code for all modules it contains, plus any associated + interface definition files, plus the scripts used to control compilation + and installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running a program using the Library is not restricted, and output from + such a program is covered only if its contents constitute a work based + on the Library (independent of the use of the Library in a tool for + writing it). Whether that is true depends on what the Library does + and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's + complete source code as you receive it, in any medium, provided that + you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep intact + all the notices that refer to this License and to the absence of any + warranty; and distribute a copy of this License along with the + Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange for a + fee. + + 2. You may modify your copy or copies of the Library or any portion + of it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Library, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so + that they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in + these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of + the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or + derivative of it, under Section 2) in object code or executable form + under the terms of Sections 1 and 2 above provided that you accompany + it with the complete corresponding machine-readable source code, which + must be distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy the + source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the + Library, but is designed to work with the Library by being compiled or + linked with it, is called a "work that uses the Library". Such a + work, in isolation, is not a derivative work of the Library, and + therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library + creates an executable that is a derivative of the Library (because it + contains portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. + Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is not. + Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section 6. + Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or + link a "work that uses the Library" with the Library to produce a + work containing portions of the Library, and distribute that work + under terms of your choice, provided that the terms permit + modification of the work for the customer's own use and reverse + engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work + during execution displays copyright notices, you must include the + copyright notice for the Library among them, as well as a reference + directing the user to the copy of this License. Also, you must do one + of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the + Library" must include any data and utility programs needed for + reproducing the executable from it. However, as a special exception, + the materials to be distributed need not include anything that is + normally distributed (in either source or binary form) with the major + components (compiler, kernel, and so on) of the operating system on + which the executable runs, unless that component itself accompanies + the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you cannot + use both them and the Library together in an executable that you + distribute. + + 7. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other library + facilities not covered by this License, and distribute such a combined + library, provided that the separate distribution of the work based on + the Library and of the other library facilities is otherwise + permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute + the Library except as expressly provided under this License. Any + attempt otherwise to copy, modify, sublicense, link with, or + distribute the Library is void, and will automatically terminate your + rights under this License. However, parties who have received copies, + or rights, from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Library or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Library (or any work based on the + Library), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties with + this License. + + 11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent + license would not permit royalty-free redistribution of the Library by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply, + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Library under this License may add + an explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new + versions of the Lesser General Public License from time to time. + Such new versions will be similar in spirit to the present version, + but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and + "any later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a + license version number, you may choose any version ever published by + the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free status + of all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR + OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest + possible use to the public, we recommend making it free software that + everyone can redistribute and change. You can do so by permitting + redistribution under these terms (or, alternatively, under the terms of the + ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is + safest to attach them to the start of each source file to most effectively + convey the exclusion of warranty; and each file should have at least the + "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Also add information on how to contact you by electronic and paper mail. + + You should also get your employer (if you work as a programmer) or your + school, if any, to sign a "copyright disclaimer" for the library, if + necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + + That's all there is to it! diff --git a/licenses/jnr-x86asm.txt b/licenses/jnr-x86asm.txt new file mode 100644 index 00000000000..c9583db05fd --- /dev/null +++ b/licenses/jnr-x86asm.txt @@ -0,0 +1,24 @@ + + Copyright (C) 2010 Wayne Meissner + Copyright (c) 2008-2009, Petr Kobalicek + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/reactive-streams.txt b/licenses/reactive-streams.txt new file mode 100644 index 00000000000..1e141c13ddb --- /dev/null +++ b/licenses/reactive-streams.txt @@ -0,0 +1,7 @@ +MIT No Attribution + +Copyright 2014 Reactive Streams + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/slf4j-api.txt b/licenses/slf4j-api.txt new file mode 100644 index 00000000000..bb09a9ad4ec --- /dev/null +++ b/licenses/slf4j-api.txt @@ -0,0 +1,21 @@ +Copyright (c) 2004-2023 QOS.ch +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/manual/core/README.md b/manual/core/README.md index a8f97cc4106..5ca4cd7872f 100644 --- a/manual/core/README.md +++ b/manual/core/README.md @@ -24,7 +24,7 @@ following coordinates: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} diff --git a/manual/core/bom/README.md b/manual/core/bom/README.md index b2a8f205554..235edcf632c 100644 --- a/manual/core/bom/README.md +++ b/manual/core/bom/README.md @@ -30,7 +30,7 @@ To import the driver's BOM, add the following section in your application's own - com.datastax.oss + org.apache.cassandra java-driver-bom 4.17.0 pom @@ -47,7 +47,7 @@ This allows you to omit the version when you later reference the driver artifact ... - com.datastax.oss + org.apache.cassandra java-driver-query-builder @@ -71,7 +71,7 @@ scope: ```xml - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor provided @@ -89,7 +89,7 @@ good idea to extract a property to keep it in sync with the BOM: - com.datastax.oss + org.apache.cassandra java-driver-bom ${java-driver.version} pom @@ -100,7 +100,7 @@ good idea to extract a property to keep it in sync with the BOM: - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime @@ -112,7 +112,7 @@ good idea to extract a property to keep it in sync with the BOM: - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor ${java-driver.version} diff --git a/manual/core/configuration/README.md b/manual/core/configuration/README.md index a30b79842bb..deefadbe3d4 100644 --- a/manual/core/configuration/README.md +++ b/manual/core/configuration/README.md @@ -376,7 +376,7 @@ using Maven, this can be achieved as follows: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ... diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 1f102c2189e..2dfc0155c63 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -149,7 +149,7 @@ dependencies, and tell Maven that we're going to use Java 8: - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -374,7 +374,7 @@ In that case, you can exclude the dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -402,7 +402,7 @@ are not available on your platform, you can exclude the following dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -433,7 +433,7 @@ your application, then you can remove the dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -456,7 +456,7 @@ dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -481,7 +481,7 @@ don't use any of the above features, you can safely exclude the dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -504,7 +504,7 @@ anywhere in your application you can exclude the dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -544,7 +544,7 @@ you can exclude the TinkerPop dependencies: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} @@ -608,7 +608,7 @@ without it. If you never call any of the `executeReactive` methods, you can excl ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} diff --git a/manual/core/metrics/README.md b/manual/core/metrics/README.md index b5dda977d5c..ef5d9b453f0 100644 --- a/manual/core/metrics/README.md +++ b/manual/core/metrics/README.md @@ -56,7 +56,7 @@ module contains the actual bindings for Micrometer, and depends itself on the Mi ```xml - com.datastax.oss + org.apache.cassandra java-driver-metrics-micrometer ${driver.version} @@ -67,7 +67,7 @@ driver, because they are not relevant when using Micrometer: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core @@ -100,7 +100,7 @@ library: ```xml - com.datastax.oss + org.apache.cassandra java-driver-metrics-microprofile ${driver.version} @@ -111,7 +111,7 @@ driver, because they are not relevant when using MicroProfile Metrics: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core diff --git a/manual/core/shaded_jar/README.md b/manual/core/shaded_jar/README.md index a6dfac9053e..8e183c0efb5 100644 --- a/manual/core/shaded_jar/README.md +++ b/manual/core/shaded_jar/README.md @@ -29,7 +29,7 @@ dependency to `java-driver-core` by: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core-shaded ${driver.version} @@ -40,18 +40,18 @@ you need to remove its dependency to the non-shaded JAR: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core-shaded ${driver.version} - com.datastax.oss + org.apache.cassandra java-driver-query-builder ${driver.version} - com.datastax.oss + org.apache.cassandra java-driver-core @@ -70,7 +70,7 @@ Notes: ```xml - com.datastax.oss + org.apache.cassandra java-driver-core ${driver.version} diff --git a/manual/mapper/README.md b/manual/mapper/README.md index 2c64897243f..27005b671ad 100644 --- a/manual/mapper/README.md +++ b/manual/mapper/README.md @@ -22,8 +22,8 @@ under the License. The mapper generates the boilerplate to execute queries and convert the results into application-level objects. -It is published as two artifacts: `com.datastax.oss:java-driver-mapper-processor` and -`com.datastax.oss:java-driver-mapper-runtime`. See [Integration](config/) for detailed instructions +It is published as two artifacts: `org.apache.cassandra:java-driver-mapper-processor` and +`org.apache.cassandra:java-driver-mapper-runtime`. See [Integration](config/) for detailed instructions for different build tools. ### Quick start diff --git a/manual/mapper/config/README.md b/manual/mapper/config/README.md index 8adc0e63b33..1e4f9981306 100644 --- a/manual/mapper/config/README.md +++ b/manual/mapper/config/README.md @@ -40,7 +40,7 @@ configuration (make sure you use version 3.5 or higher): - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime ${java-driver.version} @@ -56,7 +56,7 @@ configuration (make sure you use version 3.5 or higher): 1.8 - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor ${java-driver.version} @@ -80,13 +80,13 @@ as a regular dependency in the "provided" scope: ```xml - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor ${java-driver.version} provided - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime ${java-driver.version} diff --git a/manual/mapper/config/kotlin/README.md b/manual/mapper/config/kotlin/README.md index 07dcf20f4bf..a78bf04fb79 100644 --- a/manual/mapper/config/kotlin/README.md +++ b/manual/mapper/config/kotlin/README.md @@ -98,7 +98,7 @@ before compilation: - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor ${java-driver.version} diff --git a/manual/query_builder/README.md b/manual/query_builder/README.md index c17cd30d161..d1932b329e7 100644 --- a/manual/query_builder/README.md +++ b/manual/query_builder/README.md @@ -31,7 +31,7 @@ To use it in your application, add the following dependency: ```xml - com.datastax.oss + org.apache.cassandra java-driver-query-builder ${driver.version} diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index f845bf85a07..9c13fd8b9c8 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -40,7 +40,7 @@ - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime @@ -92,7 +92,7 @@ test - com.datastax.oss + org.apache.cassandra java-driver-core test test-jar @@ -108,6 +108,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 8967581e05a..beddd6dcaf9 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -89,7 +89,7 @@ test - com.datastax.oss + org.apache.cassandra java-driver-core test test-jar @@ -105,6 +105,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index c202e9113d5..8796edcf149 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT ../../ @@ -46,7 +46,7 @@ micrometer-core - com.datastax.oss + org.apache.cassandra java-driver-core @@ -95,7 +95,7 @@ test - com.datastax.oss + org.apache.cassandra java-driver-core test test-jar @@ -111,6 +111,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index f0045c35974..7f9bed419a7 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT ../../ @@ -46,7 +46,7 @@ microprofile-metrics-api - com.datastax.oss + org.apache.cassandra java-driver-core @@ -100,7 +100,7 @@ test - com.datastax.oss + org.apache.cassandra java-driver-core test test-jar @@ -116,6 +116,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index a5085050930..b9d119c1ad7 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -41,19 +41,19 @@ - com.datastax.oss + org.apache.cassandra java-driver-core - com.datastax.oss + org.apache.cassandra java-driver-query-builder - com.datastax.oss + org.apache.cassandra java-driver-mapper-processor - com.datastax.oss + org.apache.cassandra java-driver-mapper-runtime @@ -104,7 +104,7 @@ provided - com.datastax.oss + org.apache.cassandra java-driver-test-infra test diff --git a/pom.xml b/pom.xml index aac375139b5..3f707a93dc8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ apache 23 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT pom @@ -43,6 +43,7 @@ test-infra integration-tests osgi-tests + distribution-source distribution distribution-tests examples @@ -52,6 +53,7 @@ UTF-8 UTF-8 1.4.1 + 2.1.12 4.1.18 4.1.94.Final @@ -61,7 +63,9 @@ manual/core/integration/README.md --> 3.5.6 + 1.7.26 + 1.0.3 20230227 2.13.4 @@ -95,7 +99,7 @@ - com.datastax.oss + org.apache.cassandra java-driver-core ${project.version} test-jar @@ -139,6 +143,7 @@ com.github.jnr jnr-posix + 3.1.15 @@ -567,6 +572,10 @@ + + + com.datastax.oss:${project.artifactId}:RELEASE + @@ -759,10 +768,8 @@ limitations under the License.]]> jar-no-fork - - NOTICE.txt - + LICENSE_binary NOTICE_binary.txt @@ -793,28 +800,6 @@ limitations under the License.]]> - - attach-javadocs - - jar - - -

    - - - - -]]>
    - - --allow-script-in-comments - - - check-api-leaks diff --git a/query-builder/pom.xml b/query-builder/pom.xml index d35fd834748..9d649a30649 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -41,7 +41,7 @@ - com.datastax.oss + org.apache.cassandra java-driver-core @@ -74,7 +74,7 @@ test - com.datastax.oss + org.apache.cassandra java-driver-core test test-jar @@ -90,6 +90,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 3b20ad2f4f1..02354e09564 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -21,7 +21,7 @@ 4.0.0 - com.datastax.oss + org.apache.cassandra java-driver-parent 4.17.1-SNAPSHOT @@ -41,7 +41,7 @@ - com.datastax.oss + org.apache.cassandra java-driver-core ${project.parent.version} @@ -85,6 +85,7 @@ LICENSE NOTICE_binary.txt + NOTICE.txt META-INF From 105d378fce16804a8af4c26cf732340a0c63b3c9 Mon Sep 17 00:00:00 2001 From: mck Date: Thu, 7 Dec 2023 23:36:48 +0100 Subject: [PATCH 290/395] [maven-release-plugin] prepare release 4.18.0 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 973171c5c5d..74189e14d65 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-bom pom @@ -33,42 +33,42 @@ org.apache.cassandra java-driver-core - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-core-shaded - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-mapper-processor - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-mapper-runtime - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-query-builder - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-test-infra - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-metrics-micrometer - 4.17.1-SNAPSHOT + 4.18.0 org.apache.cassandra java-driver-metrics-microprofile - 4.17.1-SNAPSHOT + 4.18.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 55250d59d6e..75858b611a8 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index ebe7a286b21..fc71515d61b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index d4db09c7091..fa54a25376e 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index fd5378afc25..9d168679c6a 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 706157d9a98..55b9ace5233 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index c971c0355ae..e5e48d59557 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.17.1-SNAPSHOT + 4.18.0 java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 5e12c2f9ae2..356eb8d0571 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 9c13fd8b9c8..f2699cb4cb4 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index beddd6dcaf9..c8b035c30d0 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 8796edcf149..56ddabd5af0 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 7f9bed419a7..fda46cdfac3 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index b9d119c1ad7..0906c6f72f2 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 3f707a93dc8..072749ce7e0 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1022,7 +1022,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.18.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 9d649a30649..9c40ad6d277 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 02354e09564..fe7a3f35b3f 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.17.1-SNAPSHOT + 4.18.0 java-driver-test-infra bundle From 7637a5b2438c2758215e8f6f469a63780c6af75d Mon Sep 17 00:00:00 2001 From: mck Date: Thu, 7 Dec 2023 23:36:54 +0100 Subject: [PATCH 291/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 74189e14d65..72e00c48355 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-bom pom @@ -33,42 +33,42 @@ org.apache.cassandra java-driver-core - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-core-shaded - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-mapper-processor - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-mapper-runtime - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-query-builder - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-test-infra - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-metrics-micrometer - 4.18.0 + 4.18.1-SNAPSHOT org.apache.cassandra java-driver-metrics-microprofile - 4.18.0 + 4.18.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 75858b611a8..c2768c3a642 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index fc71515d61b..c54c6b8c642 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index fa54a25376e..8c4f695afdd 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index 9d168679c6a..099bddba900 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 55b9ace5233..8933d3f5f3a 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index e5e48d59557..7e2d7f1b6d0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.18.0 + 4.18.1-SNAPSHOT java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 356eb8d0571..5c684e90b2a 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index f2699cb4cb4..768327591d6 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index c8b035c30d0..95ead75ddd8 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 56ddabd5af0..1405ae0b6c2 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index fda46cdfac3..6ba084396d1 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 0906c6f72f2..859a69400b9 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 072749ce7e0..350d0518496 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1022,7 +1022,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.18.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 9c40ad6d277..f1828b62462 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index fe7a3f35b3f..9089d4d1019 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.0 + 4.18.1-SNAPSHOT java-driver-test-infra bundle From 346cab5b3e8a5f1888ba2633fa530c5934009ba0 Mon Sep 17 00:00:00 2001 From: mck Date: Fri, 8 Dec 2023 00:16:34 +0100 Subject: [PATCH 292/395] Remove distributionManagement, the apache parent defines this for us --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 350d0518496..221e1f69a86 100644 --- a/pom.xml +++ b/pom.xml @@ -1004,12 +1004,6 @@ limitations under the License.]]> - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - Apache 2 From 8352d4c733da70461dc5cb7763a98d4d0c960925 Mon Sep 17 00:00:00 2001 From: mck Date: Fri, 8 Dec 2023 10:08:03 +0100 Subject: [PATCH 293/395] Remove fossa dependency analysis github action ASF does not have a subscription for fossa --- .github/workflows/dep-lic-scan.yaml | 39 ----------------------------- 1 file changed, 39 deletions(-) delete mode 100644 .github/workflows/dep-lic-scan.yaml diff --git a/.github/workflows/dep-lic-scan.yaml b/.github/workflows/dep-lic-scan.yaml deleted file mode 100644 index 54fabe2dc8f..00000000000 --- a/.github/workflows/dep-lic-scan.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -name: Dependency and License Scan -on: - push: - branches: - - '4.x' - - '3.x' - paths-ignore: - - 'manual/**' - - 'faq/**' - - 'upgrade_guide/**' - - 'changelog/**' -jobs: - scan-repo: - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v2 - - name: Install Fossa CLI - run: | - curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash -s -- -b . - - name: Scan for dependencies and licenses - run: | - FOSSA_API_KEY=${{ secrets.FOSSA_PUSH_ONLY_API_KEY }} ./fossa analyze From 8d5849cb38995b312f29314d18256c0c3e94cf07 Mon Sep 17 00:00:00 2001 From: mck Date: Fri, 8 Dec 2023 19:48:41 +0100 Subject: [PATCH 294/395] Remove ASL header from test resource files (that was breaking integration tests) patch by Mick Semb Wever; reviewed by Wei Deng for CASSANDRA-18970 --- .../src/test/resources/DescribeIT/dse/4.8.cql | 18 ------------------ .../src/test/resources/DescribeIT/dse/5.0.cql | 18 ------------------ .../src/test/resources/DescribeIT/dse/5.1.cql | 18 ------------------ .../src/test/resources/DescribeIT/dse/6.8.cql | 18 ------------------ .../src/test/resources/DescribeIT/oss/2.1.cql | 18 ------------------ .../src/test/resources/DescribeIT/oss/2.2.cql | 18 ------------------ .../src/test/resources/DescribeIT/oss/3.0.cql | 18 ------------------ .../src/test/resources/DescribeIT/oss/3.11.cql | 18 ------------------ .../src/test/resources/DescribeIT/oss/4.0.cql | 18 ------------------ 9 files changed, 162 deletions(-) diff --git a/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql b/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql index 35eee187776..ea6ca93bcbf 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/4.8.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql b/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql index 077c9dd1399..2572df52e24 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/5.0.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql b/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql index 077c9dd1399..2572df52e24 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/5.1.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql b/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql index 76871de4e1f..bdeb4737748 100644 --- a/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql +++ b/integration-tests/src/test/resources/DescribeIT/dse/6.8.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql b/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql index 35eee187776..ea6ca93bcbf 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/2.1.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql b/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql index e35703b30cc..a4035ffa90e 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/2.2.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql b/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql index 077c9dd1399..2572df52e24 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/3.0.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql b/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql index 077c9dd1399..2572df52e24 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/3.11.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; diff --git a/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql b/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql index a78bed4b816..abc70728206 100644 --- a/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql +++ b/integration-tests/src/test/resources/DescribeIT/oss/4.0.cql @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; From 8e73232102d6275b4f13de9d089d3a9b224c9727 Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Thu, 18 Jan 2024 14:20:44 -0500 Subject: [PATCH 295/395] CASSANDRA-19180: Support reloading keystore in cassandra-java-driver --- .../api/core/config/DefaultDriverOption.java | 6 + .../api/core/config/TypedDriverOption.java | 6 + .../core/ssl/DefaultSslEngineFactory.java | 35 ++- .../core/ssl/ReloadingKeyManagerFactory.java | 257 +++++++++++++++++ core/src/main/resources/reference.conf | 7 + .../ssl/ReloadingKeyManagerFactoryTest.java | 272 ++++++++++++++++++ .../ReloadingKeyManagerFactoryTest/README.md | 39 +++ .../certs/client-alternate.keystore | Bin 0 -> 2467 bytes .../certs/client-original.keystore | Bin 0 -> 2457 bytes .../certs/client.truststore | Bin 0 -> 1002 bytes .../certs/server.keystore | Bin 0 -> 2407 bytes .../certs/server.truststore | Bin 0 -> 1890 bytes manual/core/ssl/README.md | 10 +- upgrade_guide/README.md | 11 + 14 files changed, 627 insertions(+), 16 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java create mode 100644 core/src/test/resources/ReloadingKeyManagerFactoryTest/README.md create mode 100644 core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client-alternate.keystore create mode 100644 core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client-original.keystore create mode 100644 core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client.truststore create mode 100644 core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/server.keystore create mode 100644 core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/server.truststore diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 4c0668570b2..c10a8237c43 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -255,6 +255,12 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: {@link String} */ SSL_KEYSTORE_PASSWORD("advanced.ssl-engine-factory.keystore-password"), + /** + * The duration between attempts to reload the keystore. + * + *

    Value-type: {@link java.time.Duration} + */ + SSL_KEYSTORE_RELOAD_INTERVAL("advanced.ssl-engine-factory.keystore-reload-interval"), /** * The location of the truststore file. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index ec36079730f..88c012fa351 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -235,6 +235,12 @@ public String toString() { /** The keystore password. */ public static final TypedDriverOption SSL_KEYSTORE_PASSWORD = new TypedDriverOption<>(DefaultDriverOption.SSL_KEYSTORE_PASSWORD, GenericType.STRING); + + /** The duration between attempts to reload the keystore. */ + public static final TypedDriverOption SSL_KEYSTORE_RELOAD_INTERVAL = + new TypedDriverOption<>( + DefaultDriverOption.SSL_KEYSTORE_RELOAD_INTERVAL, GenericType.DURATION); + /** The location of the truststore file. */ public static final TypedDriverOption SSL_TRUSTSTORE_PATH = new TypedDriverOption<>(DefaultDriverOption.SSL_TRUSTSTORE_PATH, GenericType.STRING); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java index 085b36dc539..55a6e9c7da8 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java @@ -27,11 +27,12 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyStore; import java.security.SecureRandom; +import java.time.Duration; import java.util.List; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; @@ -54,6 +55,7 @@ * truststore-password = password123 * keystore-path = /path/to/client.keystore * keystore-password = password123 + * keystore-reload-interval = 30 minutes * } * } * @@ -66,6 +68,7 @@ public class DefaultSslEngineFactory implements SslEngineFactory { private final SSLContext sslContext; private final String[] cipherSuites; private final boolean requireHostnameValidation; + private ReloadingKeyManagerFactory kmf; /** Builds a new instance from the driver configuration. */ public DefaultSslEngineFactory(DriverContext driverContext) { @@ -132,20 +135,8 @@ protected SSLContext buildContext(DriverExecutionProfile config) throws Exceptio } // initialize keystore if configured. - KeyManagerFactory kmf = null; if (config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PATH)) { - try (InputStream ksf = - Files.newInputStream( - Paths.get(config.getString(DefaultDriverOption.SSL_KEYSTORE_PATH)))) { - KeyStore ks = KeyStore.getInstance("JKS"); - char[] password = - config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) - ? config.getString(DefaultDriverOption.SSL_KEYSTORE_PASSWORD).toCharArray() - : null; - ks.load(ksf, password); - kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, password); - } + kmf = buildReloadingKeyManagerFactory(config); } context.init( @@ -159,8 +150,22 @@ protected SSLContext buildContext(DriverExecutionProfile config) throws Exceptio } } + private ReloadingKeyManagerFactory buildReloadingKeyManagerFactory( + DriverExecutionProfile config) { + Path keystorePath = Paths.get(config.getString(DefaultDriverOption.SSL_KEYSTORE_PATH)); + String password = + config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) + ? config.getString(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) + : null; + Duration reloadInterval = + config.isDefined(DefaultDriverOption.SSL_KEYSTORE_RELOAD_INTERVAL) + ? config.getDuration(DefaultDriverOption.SSL_KEYSTORE_RELOAD_INTERVAL) + : Duration.ZERO; + return ReloadingKeyManagerFactory.create(keystorePath, password, reloadInterval); + } + @Override public void close() throws Exception { - // nothing to do + kmf.close(); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java new file mode 100644 index 00000000000..9aaee701114 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.ssl; + +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.util.Arrays; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedKeyManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReloadingKeyManagerFactory extends KeyManagerFactory implements AutoCloseable { + private static final Logger logger = LoggerFactory.getLogger(ReloadingKeyManagerFactory.class); + private static final String KEYSTORE_TYPE = "JKS"; + private Path keystorePath; + private String keystorePassword; + private ScheduledExecutorService executor; + private final Spi spi; + + // We're using a single thread executor so this shouldn't need to be volatile, since all updates + // to lastDigest should come from the same thread + private volatile byte[] lastDigest; + + /** + * Create a new {@link ReloadingKeyManagerFactory} with the given keystore file and password, + * reloading from the file's content at the given interval. This function will do an initial + * reload before returning, to confirm that the file exists and is readable. + * + * @param keystorePath the keystore file to reload + * @param keystorePassword the keystore password + * @param reloadInterval the duration between reload attempts. Set to {@link + * java.time.Duration#ZERO} to disable scheduled reloading. + * @return + */ + public static ReloadingKeyManagerFactory create( + Path keystorePath, String keystorePassword, Duration reloadInterval) { + KeyManagerFactory kmf; + try { + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + KeyStore ks; + try (InputStream ksf = Files.newInputStream(keystorePath)) { + ks = KeyStore.getInstance(KEYSTORE_TYPE); + ks.load(ksf, keystorePassword.toCharArray()); + } catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + try { + kmf.init(ks, keystorePassword.toCharArray()); + } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) { + throw new RuntimeException(e); + } + + ReloadingKeyManagerFactory reloadingKeyManagerFactory = new ReloadingKeyManagerFactory(kmf); + reloadingKeyManagerFactory.start(keystorePath, keystorePassword, reloadInterval); + return reloadingKeyManagerFactory; + } + + @VisibleForTesting + protected ReloadingKeyManagerFactory(KeyManagerFactory initial) { + this( + new Spi((X509ExtendedKeyManager) initial.getKeyManagers()[0]), + initial.getProvider(), + initial.getAlgorithm()); + } + + private ReloadingKeyManagerFactory(Spi spi, Provider provider, String algorithm) { + super(spi, provider, algorithm); + this.spi = spi; + } + + private void start(Path keystorePath, String keystorePassword, Duration reloadInterval) { + this.keystorePath = keystorePath; + this.keystorePassword = keystorePassword; + this.executor = + Executors.newScheduledThreadPool( + 1, + runnable -> { + Thread t = Executors.defaultThreadFactory().newThread(runnable); + t.setDaemon(true); + return t; + }); + + // Ensure that reload is called once synchronously, to make sure the file exists etc. + reload(); + + if (!reloadInterval.isZero()) + this.executor.scheduleWithFixedDelay( + this::reload, + reloadInterval.toMillis(), + reloadInterval.toMillis(), + TimeUnit.MILLISECONDS); + } + + @VisibleForTesting + void reload() { + try { + reload0(); + } catch (Exception e) { + logger.warn("Failed to reload", e); + } + } + + private synchronized void reload0() + throws NoSuchAlgorithmException, IOException, KeyStoreException, CertificateException, + UnrecoverableKeyException { + logger.debug("Checking KeyStore file {} for updates", keystorePath); + + final byte[] keyStoreBytes = Files.readAllBytes(keystorePath); + final byte[] newDigest = digest(keyStoreBytes); + if (lastDigest != null && Arrays.equals(lastDigest, digest(keyStoreBytes))) { + logger.debug("KeyStore file content has not changed; skipping update"); + return; + } + + final KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); + try (InputStream inputStream = new ByteArrayInputStream(keyStoreBytes)) { + keyStore.load(inputStream, keystorePassword.toCharArray()); + } + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(keyStore, keystorePassword.toCharArray()); + logger.info("Detected updates to KeyStore file {}", keystorePath); + + this.spi.keyManager.set((X509ExtendedKeyManager) kmf.getKeyManagers()[0]); + this.lastDigest = newDigest; + } + + @Override + public void close() throws Exception { + if (executor != null) { + executor.shutdown(); + } + } + + private static byte[] digest(byte[] payload) throws NoSuchAlgorithmException { + final MessageDigest digest = MessageDigest.getInstance("SHA-256"); + return digest.digest(payload); + } + + private static class Spi extends KeyManagerFactorySpi { + DelegatingKeyManager keyManager; + + Spi(X509ExtendedKeyManager initial) { + this.keyManager = new DelegatingKeyManager(initial); + } + + @Override + protected void engineInit(KeyStore ks, char[] password) { + throw new UnsupportedOperationException(); + } + + @Override + protected void engineInit(ManagerFactoryParameters spec) { + throw new UnsupportedOperationException(); + } + + @Override + protected KeyManager[] engineGetKeyManagers() { + return new KeyManager[] {keyManager}; + } + } + + private static class DelegatingKeyManager extends X509ExtendedKeyManager { + AtomicReference delegate; + + DelegatingKeyManager(X509ExtendedKeyManager initial) { + delegate = new AtomicReference<>(initial); + } + + void set(X509ExtendedKeyManager keyManager) { + delegate.set(keyManager); + } + + @Override + public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { + return delegate.get().chooseEngineClientAlias(keyType, issuers, engine); + } + + @Override + public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { + return delegate.get().chooseEngineServerAlias(keyType, issuers, engine); + } + + @Override + public String[] getClientAliases(String keyType, Principal[] issuers) { + return delegate.get().getClientAliases(keyType, issuers); + } + + @Override + public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { + return delegate.get().chooseClientAlias(keyType, issuers, socket); + } + + @Override + public String[] getServerAliases(String keyType, Principal[] issuers) { + return delegate.get().getServerAliases(keyType, issuers); + } + + @Override + public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { + return delegate.get().chooseServerAlias(keyType, issuers, socket); + } + + @Override + public X509Certificate[] getCertificateChain(String alias) { + return delegate.get().getCertificateChain(alias); + } + + @Override + public PrivateKey getPrivateKey(String alias) { + return delegate.get().getPrivateKey(alias); + } + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 75bed97e498..d1ac22e553b 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -790,6 +790,13 @@ datastax-java-driver { // truststore-password = password123 // keystore-path = /path/to/client.keystore // keystore-password = password123 + + # The duration between attempts to reload the keystore from the contents of the file specified + # by `keystore-path`. This is mainly relevant in environments where certificates have short + # lifetimes and applications are restarted infrequently, since an expired client certificate + # will prevent new connections from being established until the application is restarted. If + # not set, defaults to not reload the keystore. + // keystore-reload-interval = 30 minutes } # The generator that assigns a microsecond timestamp to each request. diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java new file mode 100644 index 00000000000..d291924b800 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.ssl; + +import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReloadingKeyManagerFactoryTest { + private static final Logger logger = + LoggerFactory.getLogger(ReloadingKeyManagerFactoryTest.class); + + static final Path CERT_BASE = + Paths.get( + ReloadingKeyManagerFactoryTest.class + .getResource( + String.format("/%s/certs/", ReloadingKeyManagerFactoryTest.class.getSimpleName())) + .getPath()); + static final Path SERVER_KEYSTORE_PATH = CERT_BASE.resolve("server.keystore"); + static final Path SERVER_TRUSTSTORE_PATH = CERT_BASE.resolve("server.truststore"); + + static final Path ORIGINAL_CLIENT_KEYSTORE_PATH = CERT_BASE.resolve("client-original.keystore"); + static final Path ALTERNATE_CLIENT_KEYSTORE_PATH = CERT_BASE.resolve("client-alternate.keystore"); + static final BigInteger ORIGINAL_CLIENT_KEYSTORE_CERT_SERIAL = + convertSerial("7372a966"); // 1936894310 + static final BigInteger ALTERNATE_CLIENT_KEYSTORE_CERT_SERIAL = + convertSerial("e50bf31"); // 240172849 + + // File at this path will change content + static final Path TMP_CLIENT_KEYSTORE_PATH; + + static { + try { + TMP_CLIENT_KEYSTORE_PATH = + Files.createTempFile(ReloadingKeyManagerFactoryTest.class.getSimpleName(), null); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static final Path CLIENT_TRUSTSTORE_PATH = CERT_BASE.resolve("client.truststore"); + static final String CERTSTORE_PASSWORD = "changeit"; + static final Duration NO_SCHEDULED_RELOAD = Duration.ofMillis(0); + + private static TrustManagerFactory buildTrustManagerFactory() { + TrustManagerFactory tmf; + try (InputStream tsf = Files.newInputStream(CLIENT_TRUSTSTORE_PATH)) { + KeyStore ts = KeyStore.getInstance("JKS"); + char[] password = CERTSTORE_PASSWORD.toCharArray(); + ts.load(tsf, password); + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ts); + } catch (Exception e) { + throw new RuntimeException(e); + } + return tmf; + } + + private static SSLContext buildServerSslContext() { + try { + SSLContext context = SSLContext.getInstance("SSL"); + + TrustManagerFactory tmf; + try (InputStream tsf = Files.newInputStream(SERVER_TRUSTSTORE_PATH)) { + KeyStore ts = KeyStore.getInstance("JKS"); + char[] password = CERTSTORE_PASSWORD.toCharArray(); + ts.load(tsf, password); + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ts); + } + + KeyManagerFactory kmf; + try (InputStream ksf = Files.newInputStream(SERVER_KEYSTORE_PATH)) { + KeyStore ks = KeyStore.getInstance("JKS"); + char[] password = CERTSTORE_PASSWORD.toCharArray(); + ks.load(ksf, password); + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, password); + } + + context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); + return context; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + public void client_certificates_should_reload() throws Exception { + Files.copy( + ORIGINAL_CLIENT_KEYSTORE_PATH, TMP_CLIENT_KEYSTORE_PATH, REPLACE_EXISTING, COPY_ATTRIBUTES); + + final BlockingQueue> peerCertificates = + new LinkedBlockingQueue<>(1); + + // Create a listening socket. Make sure there's no backlog so each accept is in order. + SSLContext serverSslContext = buildServerSslContext(); + final SSLServerSocket server = + (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket(); + server.bind(new InetSocketAddress(0), 1); + server.setUseClientMode(false); + server.setNeedClientAuth(true); + Thread serverThread = + new Thread( + () -> { + while (true) { + try { + logger.info("Server accepting client"); + final SSLSocket conn = (SSLSocket) server.accept(); + logger.info("Server accepted client {}", conn); + conn.addHandshakeCompletedListener( + event -> { + boolean offer; + try { + // Transfer certificates to client thread once handshake is complete, so + // it can safely close + // the socket + offer = + peerCertificates.offer( + Optional.of((X509Certificate[]) event.getPeerCertificates())); + } catch (SSLPeerUnverifiedException e) { + offer = peerCertificates.offer(Optional.empty()); + } + Assert.assertTrue(offer); + }); + logger.info("Server starting handshake"); + // Without this, client handshake blocks + conn.startHandshake(); + } catch (IOException e) { + // Not sure why I sometimes see ~thousands of these locally + if (e instanceof SocketException && e.getMessage().contains("Socket closed")) + return; + logger.info("Server accept error", e); + } + } + }); + serverThread.setName(String.format("%s-serverThread", this.getClass().getSimpleName())); + serverThread.setDaemon(true); + serverThread.start(); + + final ReloadingKeyManagerFactory kmf = + ReloadingKeyManagerFactory.create( + TMP_CLIENT_KEYSTORE_PATH, CERTSTORE_PASSWORD, NO_SCHEDULED_RELOAD); + // Need a tmf that tells the server to send its certs + final TrustManagerFactory tmf = buildTrustManagerFactory(); + + // Check original client certificate + testClientCertificates( + kmf, + tmf, + server.getLocalSocketAddress(), + () -> { + try { + return peerCertificates.poll(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }, + certs -> { + Assert.assertEquals(1, certs.length); + X509Certificate cert = certs[0]; + Assert.assertEquals(ORIGINAL_CLIENT_KEYSTORE_CERT_SERIAL, cert.getSerialNumber()); + }); + + // Update keystore content + logger.info("Updating keystore file with new content"); + Files.copy( + ALTERNATE_CLIENT_KEYSTORE_PATH, + TMP_CLIENT_KEYSTORE_PATH, + REPLACE_EXISTING, + COPY_ATTRIBUTES); + kmf.reload(); + + // Check that alternate client certificate was applied + testClientCertificates( + kmf, + tmf, + server.getLocalSocketAddress(), + () -> { + try { + return peerCertificates.poll(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }, + certs -> { + Assert.assertEquals(1, certs.length); + X509Certificate cert = certs[0]; + Assert.assertEquals(ALTERNATE_CLIENT_KEYSTORE_CERT_SERIAL, cert.getSerialNumber()); + }); + + kmf.close(); + server.close(); + } + + private static void testClientCertificates( + KeyManagerFactory kmf, + TrustManagerFactory tmf, + SocketAddress serverAddress, + Supplier> certsSupplier, + Consumer certsConsumer) + throws NoSuchAlgorithmException, KeyManagementException, IOException { + SSLContext clientSslContext = SSLContext.getInstance("TLS"); + clientSslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + final SSLSocket client = (SSLSocket) clientSslContext.getSocketFactory().createSocket(); + logger.info("Client connecting"); + client.connect(serverAddress); + logger.info("Client doing handshake"); + client.startHandshake(); + + final Optional lastCertificate = certsSupplier.get(); + logger.info("Client got its certificate back from the server; closing socket"); + client.close(); + Assert.assertNotNull(lastCertificate); + Assert.assertTrue(lastCertificate.isPresent()); + logger.info("Client got its certificate back from server: {}", lastCertificate); + + certsConsumer.accept(lastCertificate.get()); + } + + private static BigInteger convertSerial(String hex) { + final BigInteger serial = new BigInteger(Integer.valueOf(hex, 16).toString()); + logger.info("Serial hex {} is {}", hex, serial); + return serial; + } +} diff --git a/core/src/test/resources/ReloadingKeyManagerFactoryTest/README.md b/core/src/test/resources/ReloadingKeyManagerFactoryTest/README.md new file mode 100644 index 00000000000..9ff9b622e5b --- /dev/null +++ b/core/src/test/resources/ReloadingKeyManagerFactoryTest/README.md @@ -0,0 +1,39 @@ +# How to create cert stores for ReloadingKeyManagerFactoryTest + +Need the following cert stores: +- `server.keystore` +- `client-original.keystore` +- `client-alternate.keystore` +- `server.truststore`: trusts `client-original.keystore` and `client-alternate.keystore` +- `client.truststore`: trusts `server.keystore` + +We shouldn't need any signing requests or chains of trust, since truststores are just including certs directly. + +First create the three keystores: +``` +$ keytool -genkeypair -keyalg RSA -alias server -keystore server.keystore -dname "CN=server" -storepass changeit -keypass changeit +$ keytool -genkeypair -keyalg RSA -alias client-original -keystore client-original.keystore -dname "CN=client-original" -storepass changeit -keypass changeit +$ keytool -genkeypair -keyalg RSA -alias client-alternate -keystore client-alternate.keystore -dname "CN=client-alternate" -storepass changeit -keypass changeit +``` + +Note that we need to use `-keyalg RSA` because keytool's default keyalg is DSA, which TLS 1.3 doesn't support. If DSA is +used, the handshake will fail due to the server not being able to find any authentication schemes compatible with its +x509 certificate ("Unavailable authentication scheme"). + +Then export all the certs: +``` +$ keytool -exportcert -keystore server.keystore -alias server -file server.cert -storepass changeit +$ keytool -exportcert -keystore client-original.keystore -alias client-original -file client-original.cert -storepass changeit +$ keytool -exportcert -keystore client-alternate.keystore -alias client-alternate -file client-alternate.cert -storepass changeit +``` + +Then create the server.truststore that trusts the two client certs: +``` +$ keytool -import -file client-original.cert -alias client-original -keystore server.truststore -storepass changeit +$ keytool -import -file client-alternate.cert -alias client-alternate -keystore server.truststore -storepass changeit +``` + +Then create the client.truststore that trusts the server cert: +``` +$ keytool -import -file server.cert -alias server -keystore client.truststore -storepass changeit +``` diff --git a/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client-alternate.keystore b/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client-alternate.keystore new file mode 100644 index 0000000000000000000000000000000000000000..91cee636a0baab4d6e8b706c76da6bffd8398f37 GIT binary patch literal 2467 zcmY+Ec|6pK8^>qN3{8_AWE>&JwIR$TN$z_vtXZ)}Nu%63a;C=hbw!RwWSlc{Ws$S6 z?)zw#9248H$k9kO3L)WVf3M$f_qBgKujl!^pXc-Z`N05i8W$LX0pJeYaK(6B{5CI` z2TTXx=1>4`a)b>q04)4pE0`}7fO#EZx1)05M*Pop;y9R#4nX%X0CXFpz(_!+E1^f*j_q18d2Sn?o!MLvP>&51fDW$t2UVlHvQ9@L9oBPQ8A4sTlWF&YRT3u*E0+WN?r!T&q}?d|KEf^LS?aLVfMGdgs>) zdDeG(T&lkR>AznZ7kDPQmt{{~r8qf%C@nBTBdgEv+0{x833;>;&$$=wbH;@m?OAE~ z_lZ{Z2Gf{`(y{enkkglPGu5l%9!q(aI-Bm3uj28?q6UKfMha;49c4w0Q9~5^aYS^Z!Pz8jD(=dY?@B=e?!tkO zX2_`>5>KSdKikfskn;0b5OYgJUj4TYn}wNQ#;uD;R6mPpp?iKW+Ub(057Tv|Zgk-I z3J9ldZ?`==HU=N>@AbZ#^n=n3a8FvRCT(*GlP?42t_}3+@*!0?kW3{#RT|n_O4!S^ z>L<~h3Y7Fb>tEyt+&iADmEjvkz!U0ZQYkA?E95)8TgA1L4+x=}7FCAm&06FWsm-dTCS z3C!o|GYVee4{W~qg1MWrZA4@K>EXHqtA>WEB&cE6$6N_u=tjD<6>OQ0w6_g-$4|Y z!ffsmsSo5p{?4Bt47zm`Np^Q^xXa;H92~ULr@mGSmU;sF<(u%R9i%=AR$Lb<$ub?o zY&h%rr(I+DGdUrkvk-@$2Iq|(?LO2LY)yZW(np&~hmNNA0`*d6p+Rj-^HzR zg_Jdhk9x`;7Qv<)$2-&)J0zb%ONU2OGD+ItZk7D5v|BXSKlLfcMLD%73N7v`Oun`6UCnKV=c9LPO|A}*qF%!Jp_mF;W|MxHS zipQrcwGekW>i}(@byZP83q`4xz{ZdiUkr>|~P7r|2`1L_+j%C>Jn_=tSx->)hdrBZ@0BQ!QhdOOkZ7lt$_E-5icT!0N_Ckw z^~ByKk!lHAk(x2OxWA7bSZG$O-(T1~l;lxNy5fty zj8XkND&c}y>C;l68=zYtPmn9f7Ze0i29b_b(2)u_(xks84Ei4f3M&W|xa{fUDuva+ zV9#l2T+mRzh|$0Rkk-GCc(~~Rr0NKjbAdre?a4nI@V`=*`>)hR6>_mdop6;eEn6^^ zHXr-C`hTPUH+7=`h=(%PNAIePZRStSje^Mw^LgS<=-A-IEiC<@s4vMYmfFK3*oS6~ISaf^7ZcrrhN`2JM- zev+3IAaAI6c=`RA;%E2G{6~!i{KkLL9WAmE32ILpGGFdOMWa?IL8(AMXEi@rM-6hx zD>`)k+ulL#iu~f4frGb=j6%MrS8?{uqK+}D313GOIW@C%5&n5mUY^1!jX_9lwft0M znYN{V>sdej3C$!yX9YRg5b@WA_c97_^9{27I8tc(AC!|=QDhraIb_oNg!XOADd$gZ z^nnmUV}mNQ;F|9i@!ObA$Zj z{6!%d5LPC&Mx}atTNGMW*$rKB4jyOe(cFNn4dx0PoU6kx7vOj&?jA?YPp711-D!Q7 zh|~NSX)+%%^MVQPFWGbUn}GcBNlBr-(*y5QGr-BJ*b3b#iqq78CMJw?>$G~`w53;Q z!gvucIyYy&mP99{bL{FW7KKvK2p+m@3J zF>r2}(hm@>Q!o%zPy~f#DSpsZ)k-d0n@SIhTL{zjhYFs5wZbXUDbZeHHiXN*8`~c? M&hzAgfaB@^0fMoC8UO$Q literal 0 HcmV?d00001 diff --git a/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client-original.keystore b/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client-original.keystore new file mode 100644 index 0000000000000000000000000000000000000000..74e31f7bc6f1ab222cf2c8ac5feb2324d1f01fdf GIT binary patch literal 2457 zcmY+EX*d)L7sqGJjAbkr5r&Z^ySZkDJF;uYmUXTrhLFaRZ3x+l24fo)vQr~lVT>)y zWQ&`mOEHm%L`4}(l##9LeV_Ne_qiX=bI$qw&pBVt^Zbz{o;(g92ub3x<>XN%TaelO zKrSGa#A5^|@#r04Z6pa2_b&+&1SUcJkMPB#@Z#kC-xePf$U!B6_mCto8>zwx{XafB zE(sQiJyu#?hE}x;Zt9+oJV^9#!tTg%fB*ybU=nyJt|{279;mNR@WY$Nh1VBYwZB4q z)vNJTDLf5-5?yZU2}#LPa#)km>Pc1rx4Fm9NHzb_yre-&<^B}C;D5^Yl5Oq zPg~(r7!&;^XWpmjpgiWfW(V$CjpbUUlk-$cL#X&Hxvx?j@i8DSHii38c~1BD5H+fY z$#CO10`N#1T1?6CRz53eU-97eLR-2UKnVZcpEHlkd^y@pvbq8mc3|VwKU&5cW^=nf zBF?RleCf9ynn00_^XA+$`l__nr4mS%qDPF^t_wQQfKx1>VpqUJF0(&}>B|+nr(@}P zkGWqs8Cn%x)JGq_66|=c(z$fOT%fBaIKM@Nk`00)-;N~dFdTLB!i9L>MAnJ>uY}Z1 z433YD(CH=HcJKJ~Pwm)f8%xvgiiZC=FoluLch{+!{P?2Lv?fElEfLkIa7C+pv$mb% z@z!w-28P1q*KySfEztD!%4%YfR}yN1V)x%WLSN`UqhMw}Q|?BXOKmNyVK1vx=6?KO zgOj@1oZiK^(o`!_2j3#w&+&=k>o?r0hfu+^%fdPhQI&jz=q=p^Wr0eyU7OOPqyJ$- zM#4_uy5v_cE3Z!x4Qj!DU3V2!i(Xz68S$z{M+!>dp)G6)rwqy070Zo11Uq6*tr7EW zWR|y&Q%Zli7`OhJ<2@x&qfTEaA(E^2HYX}pfb(qi&1!~k@57b1D~-2yIe$_g%M*?( zrB>}r+?399xdSFxtXg^R{z3>oLGrHu{d)C|Bes)&hubYkTQLzeSgCgZOz6l}d7F+Z z!LtNs`p@K-H`*%lv10>=FmEG;zzI{w`;RCm?W)F}PitE2ZZ{dE*~o&jgVJY0YKED+ z@xW5|Cn?PDBh%U{`Kc;*F8%>qyG93+&b66)P$c_` z0RJHz`=Q_A-Z>@tl$)y(x6wpXiWeliYbibQ{0)y^qlmN<`1Pc|_fjekY$o6mE}-p^ zAZxiSv4FnKU`^O=+PCkU?o9QD|*#3`Se?s3d_}{~qGvq>?~YN2r_w2slc`|0uwJc`oOFJl8HAW>o$` zgK;g8Bdyr;+9x4${m_3sH<1MLN-hjgO5KX57hO|!v3B~XmRZ(trMsy?$KPclb+$C( z(AAMn%Oa|6iTs8t=zol}O#7yI{?Ecq9+f7y4cz^{>&y@-f(lDYFUAL&<>aQ^;NQGy zl3q=%I*sa5R|dKzSjs}GDc$^P?+$JaFlQ7;jlG9L^tg`QI_T(4SsDSC7>u!@Jz=Ms zKXFEqzLw;V3xB3mkSj3WIL$)?6P{oewGD%`ubkdnG70>%0awbH>x8w;tMlC7*y4tK2Q)9 z4a^XDn8=OtR*ZPo=5YA)VJ)tQmNr?d0$&oPu}Z`QbzP>&0ljdDsH`z|CV<#xum8o* zXL@=pJ_e&gSJmNP2Z1-)f~#XrBF-t#`n2p9$2X>|sx$B-beQ!yLt09BZp+E8)bOx1 z+~xL*hR>UY-&hFWU1$r!e#BN{)wXY|8sTWfDmDlw-3>o@5sNmMc7dcsx8sJJW6 z*@3gxIQagW(SP~%VxT<4U>93(d&m4qFEc(PKs)XPaeVX5h2A@?{`W(J1mjqQK=z7U z;bi(@U5(jQ3hx@e{e5WpB2k8skUaHJ45@Ei83^sfao*da`6w{eqm^D*b~7<{1CzJZ z^LRhp(I=mIVPtOPx7}m;MU|s=nOEwprlp4+Upo&N54AX7+`3+u?>MElT@{^o*-g3X z;;#44#N#pvqFJOJbWc~bI-uX*{kc^<&EmnSLv}^p6@f%OhYyVo=#`wzcdnS!M%P({ zX8)aSUfcQF#i0Z$R)%ZS;`PgN`_@Mnx%lhC5$9gjpUmhV=L_g#VCt1Jz`7;puYN-s zB4v?0oDeku5C;qb0E>kFtX=4tCoCI=1qcLsrT_o{ literal 0 HcmV?d00001 diff --git a/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client.truststore b/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/client.truststore new file mode 100644 index 0000000000000000000000000000000000000000..3ce9a720dbc7557774ebbfbae2975235cfc52e46 GIT binary patch literal 1002 zcmV2`Yw2hW8Bt2LUiC1_~;MNQUV75 z8*8{D>rwp3j1%KTjZuVQ0s{cUP=JC1FrCLfv|Un~ufMqg!U2hEV#UbjV}nkvFlQfT zws%zX^-+$Sav!Xsm&~zLgw(N++mklJptmni0Rd*-42bRCxb#@tBkj1vJL2}Aa=vBC zPMQtbU(SfTvZUg5FrGs^!)BInqQn-V3mMPE>}8wYgV%;IL=Doa$bq*zeba|fhmr)? z{WT@X3G>&d^g3rY(d5aI5(f{}<3lUb2H{J3blG0qi^|N$X^v_Z2pUJvE)*qjm_z?h$x`Hv=IZIyBR9UJF?_KKH53{`;22J8C$gMyNS`7;2EE>X%=a@JIp|6v;!T zY;ymI?&;~1Z#4z=p%*1c$Bdb*6=c!+anhyT~Bbzz0m z_T}hw@W2;-Z>~!h?<)CRno)GNEK^>E<1jMm(BoHpZX}YC63RfgymuL$A>CPT14vHj1ohI0Pzii-mXDj|cvW60od7&MgQ|M=%~BpCiE z;EkLZ4;%5>y+OunWCmmk(MayYhI)mv6 zPQ4~K1*bj`RgbTL_>hv$Sh%;2Rb_%*VqR(zqe-TP|YJMAoGHB-b!c%=c ze(Od0212~nI#ej7BRB&JhQIk!s?ELnvSH5q`bC|Dhp*Cm`d0=z<}I|ZnD}XV86|bd z%QRlh1eb=$jG?I!bqfwlJ42C|%s%ps9{?+s!-%>%>wnm8G#-WS(ZXJ<@($?OUYlMu zpX(32Z!5lbESMj%;x@yv8K62i*e6ZzK`NCJuIBhvX`u^Jh1`Zd?f5)bQ7jb-_?oo7 zc5+Am4oT|aVMa5CE646n>jC4+;pXm)FZ@{!o>wi@SMAIht`*2+>wBH*7`Z2kTpzav zk3~EII`>{M`=uy#dP~2Gt(kSP+;pE>jRp5K^a)7@_x6S?RYO^LA1-!BWKkQ!ouu}Q{MHNp&Z2RG>1!*oDXq%oDhG; z8v@FxP5iW#rtKZQnbKXqaW&mtRHio;U%A$d`O?6UxjpfINFA~_8d2h6t)0P{^Er^2cx;GxP3321=tPI!2$=sg>+BX(XnLKY2*_au_IXLI$-tmXla zcln~;$JZlNaFPcO>2-SdUEV!#jgIIXkg#Csw(=jIib}A@W0%;@iCi~}Mz|`t^s2QK zf<5Y$VqJquw0tBy1zvovIp5noKYlRR=hD%oY9I5!BmVqTEQ z=dt$zj$UeKO|VwWUfQb?F?@egF365BQ$1=4nBv|&JIqaCG1(M;N+Oxh%JW2Hs`&S7 zfmxw!{5(15tTvPI9Z#EsM823-f79Pg#ATkXe0#v!Qg`Hmj}_)q?2RLNGTWbjRd;xe zP9bk8YsP67rk!i;x*MSvM{YNXQ)o|Y-YZ(E_>j@#WP70p+U(e!_@t7aet3;2e^$Hc zjsUQEe6lGIB|NAp;gM1J%UyTFRgR?~68d_!NR*?!+TGgxggUxCnuyF(3v_fId=C!=Zk%KYs>EXqnj-=W!|NWYY04~vh>aX&6=+HH-s#pS_yBB z6%rntQ8K_F|5haou5?nA3lIUg0tg30{natz|AYcca4?@^V8|7ek_JXeSwllz?XSX+ z*>eA0VuzNH*^+*u1P~DLbHx0U0RLrJ=wF7Nbm?oAULYOKWN&Dzcr<+%3%mXDzlJ4| z*$hOl3XRj95W|~)EE8!YGfM$kduN4Qn=YIiPXatQY}pC>&DH?HYtdAD@S~UsnFsWO zr)P^$%i)fqZAV{|p9LUkbRq#&EHO7C0my01{y02H`rI6k2im2Dor)Biy! zmugcQDoJ^*AYp8*IuuengO9zbD>F0c34CCFxI6!dHY34vq$e0_=5HyfGEuioKUM52 zQ~M~^{UArogqrE@#OX`;_^lIa2{kZ!=mifHOmZ(5l{0qTD@?Ju<%NfL(_ojAHE-;W zWLxzo7Y5Q1nYn={y)m1I6brk8f5)&5nxQt>@vnAMV zS0>C=qorZ?Ocn8*yg}3+qgl-!idDD=KNqFRwnSfTFs0W>Su+RSPvyTGJ*eP>U0}E2 zUd(Ug7hygN2wgn3-?%z;bK5X2-QWgpcg2h#D8coD{n<8>tu2zNkMava`T7YSjDTU$ z(}LEM$O%nTg6aOV?UO)V&ISQ3;`FGHBf6<#lQsIBd(`o+Q5>4x>6`tz>)7S^BAmJh9y5p&h<*DSy5s~;t8=< zR#V8GzPzlLE;Wi}gBI#}#aop(EEe+nu4MH4E&?OnilWT3#A~Jr8x+@|<9Dw*6@pQ7 zaf+R(xNR+;HpNOugkAo~P}fA-==>K|CN;=tYA>;%J`^YEI`b_jkDuKgb$tK$Sm9&B z0HDI^vbs8SH(lbKpTPpaW8*#uF(R=TPsMY29`1EBY(|DZflTAqW}w3xAC#kvsW!ps zm%$llg@{IU;uBp7(I+Q z1_p)5o@4_FK>%Pl&pd$|>s7ZHh%-Hzg^h8Zm58wi!y`cUL7^SRjK#Odlc~S&q_HPu LD}&g8$tC{*$&6Q$ literal 0 HcmV?d00001 diff --git a/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/server.truststore b/core/src/test/resources/ReloadingKeyManagerFactoryTest/certs/server.truststore new file mode 100644 index 0000000000000000000000000000000000000000..c9b06b5fbe1c2a81cfdcb7319bb82acbb0f6b4a0 GIT binary patch literal 1890 zcmV-o2c7sZf(Kp#0Ru3C2NwnjDuzgg_YDCD0ic2h2n2!$1TcaJ05F0E{00dshDe6@ z4FLxRpn?YNFoFi@0s#Opf(GIS2`Yw2hW8Bt2LUiC1_~;MNQUntF0&nl&gP8eutUG)C z)w>s(%-}4h_Gb1JtX(Gt7Lf@UC}iJX!76zfiIVH0c~njU_FTR+|0xpktwPDK`^Y9v zC5e446hb8OZ#U75j;Ms?U|uJJ;Ee>{0HK4!Z~CZ{>MP)R$nHJ8b^`v&p*PR534D#` zUX=-?!((kjc;`_o$6t3Q8Vm!@C1CabTumt4?w~^ir$fdubO0%R$@dTK@Hp~`1LsH$ ztnm<6t_iJ)*rx{1Z8$SlU#C_zKD!z+Hg5}=&!4Ad|CLESP~?q%$ZGwZiD0Z+d)JfG z{h#&*pKYW3`CuXL0oSVz-W`PbfNk0ccywE}7`4vJiNBuK!M=um?6L>23_8fv$3Xkf zla7@l0l`1gRepm3i51mk9d2a16lX)NWpbN4Nb~*UlTqHm@>p#j()|tMaG{!EK?txB zz9TXuosh|w=K7qc#CVE=bZkix_tumaFKcxM$PC9NV%fbGEf+KbT*^uz5=105W|(Gz zh1WSXjvo@eD3v^to!L5ki(e-mkiE`5xl~T2WPugTRw%T2ev{!*lYLn)`A_@qfY%1B zTfV1dpKPoyX>GX*-L)BMKNCgSIqdP;;pr1k>qN<6L6Y>N4k$Q11k5RSivFQSO~BVJ zc@jUS2tpjyl+t?636-1+=#xyVuQGI&C3jziYebkuEB%={ht9Zx7*(fy6Jlk-E!|Vk zx8C6hY3&W{elehl-nRQnklm4qmxyWM@)BS7_N*p43FLryqfhgYi6tz@qvNXwF4!^7 zqo8wN&kRPfY$$<`^%L{QuaL1Rq?#)xz-HOAiWg_(q090rB_K=e+sz)6(z+ghLOGO{ zMCk?=+l_7=Z>;vt${=nyv>CdN=1b*ZO8N@4w>g8DINf3{H{$aE4n>Z6x??J#u{T&o z%54l3cU!1JGMS5EC9e3a1Z8Y&Wp@t>lrOHcs37ug7T>pDgWMczgBy_~}LR>q0Y1Pl{9%j7O)q`KwU6Ksh zRdxKfk~-^lky#Z70A6rIeXi5CEBvr9@(ymtO%n0pEDfBK$I-g_eCFut@fHJT&~?tW ztaY3)I_gBKpC})fn3FTMdRZ=7eIz-MkNNr+V(M^b0c~Lwp zCupPHv*t-fLt_mv3as*+x+yvQH0sqjX~Z);uyx$a7ZvCkHpnuqmo{W*bFF7tFDZeW z_i~-$^{(ho^1Io^|J7>^gaBQtB{o37w+wztlzW{qg7m(d*}JjQ!hq*;4?S|medoRl zEqSS3CV58g+Aerc>21P}Efcs`T{qP?C+bV>W+L~~S$k#BSdXGOjCix%{+>yiZYhs} zYlCX#u_bUbj0RqExB>PJ$*|0HFA<8Y-)Cwrpmt6vysGvweeUqv`qwWNXi)Sj z!1SW!%WDc|3}%u8`*V~tAzXv2RP)L#Y}Gg3ciTdabi9l{SV$)t<4KkPPi&FDR-{OP zTsp#f;>qOE1u6|Ner4vS0|B^Jvf`P*5z0kJ?KHdPVKoLha>0|* zhWhKFT6?9;Xs5l|qcA=&AutIB1uG5%0vZJX1Qg`kli9U7#PfFfuLGPqc&FXlm~;db ctoVTJaCWa4Yfw+L!h=^Pt>>Pu0s{etpskvUfB*mh literal 0 HcmV?d00001 diff --git a/manual/core/ssl/README.md b/manual/core/ssl/README.md index b8aa9b89192..913c7bc6c9a 100644 --- a/manual/core/ssl/README.md +++ b/manual/core/ssl/README.md @@ -94,11 +94,13 @@ If you're using a CA, sign the client certificate with it (see the blog post lin this page). Then the nodes' truststores only need to contain the CA's certificate (which should already be the case if you've followed the steps for inter-node encryption). +`DefaultSslEngineFactory` supports client keystore reloading; see property +`advanced.ssl-engine-factory.keystore-reload-interval`. ### Driver configuration By default, the driver's SSL support is based on the JDK's built-in implementation: JSSE (Java -Secure Socket Extension),. +Secure Socket Extension). To enable it, you need to define an engine factory in the [configuration](../configuration/). @@ -126,6 +128,12 @@ datastax-java-driver { // truststore-password = password123 // keystore-path = /path/to/client.keystore // keystore-password = password123 + + # The duration between attempts to reload the keystore from the contents of the file specified + # by `keystore-path`. This is mainly relevant in environments where certificates have short + # lifetimes and applications are restarted infrequently, since an expired client certificate + # will prevent new connections from being established until the application is restarted. + // keystore-reload-interval = 30 minutes } } ``` diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index e79e8f8cc6d..c6df74ffc2a 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -19,6 +19,17 @@ under the License. ## Upgrade guide +### NEW VERSION PLACEHOLDER + +#### Keystore reloading in DefaultSslEngineFactory + +`DefaultSslEngineFactory` now includes an optional keystore reloading interval, for detecting changes in the local +client keystore file. This is relevant in environments with mTLS enabled and short-lived client certificates, especially +when an application restart might not always happen between a new keystore becoming available and the previous +keystore certificate expiring. + +This feature is disabled by default for compatibility. To enable, see `keystore-reload-interval` in `reference.conf`. + ### 4.17.0 #### Beta support for Java17 From c7719aed14705b735571ecbfbda23d3b8506eb11 Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Tue, 23 Jan 2024 16:09:35 -0500 Subject: [PATCH 296/395] PR feedback: avoid extra exception wrapping, provide thread naming, improve error messages, etc. --- .../api/core/config/DefaultDriverOption.java | 12 ++--- .../core/ssl/DefaultSslEngineFactory.java | 4 +- .../core/ssl/ReloadingKeyManagerFactory.java | 44 +++++++++---------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index c10a8237c43..afe16e96886 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -255,12 +255,6 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: {@link String} */ SSL_KEYSTORE_PASSWORD("advanced.ssl-engine-factory.keystore-password"), - /** - * The duration between attempts to reload the keystore. - * - *

    Value-type: {@link java.time.Duration} - */ - SSL_KEYSTORE_RELOAD_INTERVAL("advanced.ssl-engine-factory.keystore-reload-interval"), /** * The location of the truststore file. * @@ -982,6 +976,12 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: boolean */ METRICS_GENERATE_AGGREGABLE_HISTOGRAMS("advanced.metrics.histograms.generate-aggregable"), + /** + * The duration between attempts to reload the keystore. + * + *

    Value-type: {@link java.time.Duration} + */ + SSL_KEYSTORE_RELOAD_INTERVAL("advanced.ssl-engine-factory.keystore-reload-interval"), ; private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java index 55a6e9c7da8..adf23f8e89a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java @@ -150,8 +150,8 @@ protected SSLContext buildContext(DriverExecutionProfile config) throws Exceptio } } - private ReloadingKeyManagerFactory buildReloadingKeyManagerFactory( - DriverExecutionProfile config) { + private ReloadingKeyManagerFactory buildReloadingKeyManagerFactory(DriverExecutionProfile config) + throws Exception { Path keystorePath = Paths.get(config.getString(DefaultDriverOption.SSL_KEYSTORE_PATH)); String password = config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java index 9aaee701114..540ddfd79fa 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java @@ -73,26 +73,17 @@ public class ReloadingKeyManagerFactory extends KeyManagerFactory implements Aut * @return */ public static ReloadingKeyManagerFactory create( - Path keystorePath, String keystorePassword, Duration reloadInterval) { - KeyManagerFactory kmf; - try { - kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } + Path keystorePath, String keystorePassword, Duration reloadInterval) + throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, + CertificateException, IOException { + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyStore ks; try (InputStream ksf = Files.newInputStream(keystorePath)) { ks = KeyStore.getInstance(KEYSTORE_TYPE); ks.load(ksf, keystorePassword.toCharArray()); - } catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - try { - kmf.init(ks, keystorePassword.toCharArray()); - } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) { - throw new RuntimeException(e); } + kmf.init(ks, keystorePassword.toCharArray()); ReloadingKeyManagerFactory reloadingKeyManagerFactory = new ReloadingKeyManagerFactory(kmf); reloadingKeyManagerFactory.start(keystorePath, keystorePassword, reloadInterval); @@ -115,24 +106,26 @@ private ReloadingKeyManagerFactory(Spi spi, Provider provider, String algorithm) private void start(Path keystorePath, String keystorePassword, Duration reloadInterval) { this.keystorePath = keystorePath; this.keystorePassword = keystorePassword; - this.executor = - Executors.newScheduledThreadPool( - 1, - runnable -> { - Thread t = Executors.defaultThreadFactory().newThread(runnable); - t.setDaemon(true); - return t; - }); // Ensure that reload is called once synchronously, to make sure the file exists etc. reload(); - if (!reloadInterval.isZero()) + if (!reloadInterval.isZero()) { + this.executor = + Executors.newScheduledThreadPool( + 1, + runnable -> { + Thread t = Executors.defaultThreadFactory().newThread(runnable); + t.setName(String.format("%s-%%d", this.getClass().getSimpleName())); + t.setDaemon(true); + return t; + }); this.executor.scheduleWithFixedDelay( this::reload, reloadInterval.toMillis(), reloadInterval.toMillis(), TimeUnit.MILLISECONDS); + } } @VisibleForTesting @@ -140,7 +133,10 @@ void reload() { try { reload0(); } catch (Exception e) { - logger.warn("Failed to reload", e); + String msg = + "Failed to reload KeyStore. If this continues to happen, your client may use stale identity" + + "certificates and fail to re-establish connections to Cassandra hosts."; + logger.warn(msg, e); } } From ea2e475185b5863ef6eed347f57286d6a3bfd8a9 Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Fri, 2 Feb 2024 14:56:22 -0500 Subject: [PATCH 297/395] Address PR feedback: reload-interval to use Optional internally and null in config, rather than using sentinel Duration.ZERO --- .../core/ssl/DefaultSslEngineFactory.java | 14 ++++----- .../core/ssl/ReloadingKeyManagerFactory.java | 29 +++++++++++++------ .../ssl/ReloadingKeyManagerFactoryTest.java | 4 +-- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java index adf23f8e89a..bb95dc738c7 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java @@ -33,6 +33,7 @@ import java.security.SecureRandom; import java.time.Duration; import java.util.List; +import java.util.Optional; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; @@ -153,14 +154,11 @@ protected SSLContext buildContext(DriverExecutionProfile config) throws Exceptio private ReloadingKeyManagerFactory buildReloadingKeyManagerFactory(DriverExecutionProfile config) throws Exception { Path keystorePath = Paths.get(config.getString(DefaultDriverOption.SSL_KEYSTORE_PATH)); - String password = - config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) - ? config.getString(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) - : null; - Duration reloadInterval = - config.isDefined(DefaultDriverOption.SSL_KEYSTORE_RELOAD_INTERVAL) - ? config.getDuration(DefaultDriverOption.SSL_KEYSTORE_RELOAD_INTERVAL) - : Duration.ZERO; + String password = config.getString(DefaultDriverOption.SSL_KEYSTORE_PASSWORD, null); + Optional reloadInterval = + Optional.ofNullable( + config.getDuration(DefaultDriverOption.SSL_KEYSTORE_RELOAD_INTERVAL, null)); + return ReloadingKeyManagerFactory.create(keystorePath, password, reloadInterval); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java index 540ddfd79fa..8a9e11bb2e9 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactory.java @@ -36,6 +36,7 @@ import java.security.cert.X509Certificate; import java.time.Duration; import java.util.Arrays; +import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -68,12 +69,12 @@ public class ReloadingKeyManagerFactory extends KeyManagerFactory implements Aut * * @param keystorePath the keystore file to reload * @param keystorePassword the keystore password - * @param reloadInterval the duration between reload attempts. Set to {@link - * java.time.Duration#ZERO} to disable scheduled reloading. + * @param reloadInterval the duration between reload attempts. Set to {@link Optional#empty()} to + * disable scheduled reloading. * @return */ - public static ReloadingKeyManagerFactory create( - Path keystorePath, String keystorePassword, Duration reloadInterval) + static ReloadingKeyManagerFactory create( + Path keystorePath, String keystorePassword, Optional reloadInterval) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); @@ -103,14 +104,24 @@ private ReloadingKeyManagerFactory(Spi spi, Provider provider, String algorithm) this.spi = spi; } - private void start(Path keystorePath, String keystorePassword, Duration reloadInterval) { + private void start( + Path keystorePath, String keystorePassword, Optional reloadInterval) { this.keystorePath = keystorePath; this.keystorePassword = keystorePassword; // Ensure that reload is called once synchronously, to make sure the file exists etc. reload(); - if (!reloadInterval.isZero()) { + if (!reloadInterval.isPresent() || reloadInterval.get().isZero()) { + final String msg = + "KeyStore reloading is disabled. If your Cassandra cluster requires client certificates, " + + "client application restarts are infrequent, and client certificates have short lifetimes, then your client " + + "may fail to re-establish connections to Cassandra hosts. To enable KeyStore reloading, see " + + "`advanced.ssl-engine-factory.keystore-reload-interval` in reference.conf."; + logger.info(msg); + } else { + logger.info("KeyStore reloading is enabled with interval {}", reloadInterval.get()); + this.executor = Executors.newScheduledThreadPool( 1, @@ -122,8 +133,8 @@ private void start(Path keystorePath, String keystorePassword, Duration reloadIn }); this.executor.scheduleWithFixedDelay( this::reload, - reloadInterval.toMillis(), - reloadInterval.toMillis(), + reloadInterval.get().toMillis(), + reloadInterval.get().toMillis(), TimeUnit.MILLISECONDS); } } @@ -135,7 +146,7 @@ void reload() { } catch (Exception e) { String msg = "Failed to reload KeyStore. If this continues to happen, your client may use stale identity" - + "certificates and fail to re-establish connections to Cassandra hosts."; + + " certificates and fail to re-establish connections to Cassandra hosts."; logger.warn(msg, e); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java index d291924b800..d07b45c21df 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/ssl/ReloadingKeyManagerFactoryTest.java @@ -34,7 +34,6 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; -import java.time.Duration; import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -86,7 +85,6 @@ public class ReloadingKeyManagerFactoryTest { static final Path CLIENT_TRUSTSTORE_PATH = CERT_BASE.resolve("client.truststore"); static final String CERTSTORE_PASSWORD = "changeit"; - static final Duration NO_SCHEDULED_RELOAD = Duration.ofMillis(0); private static TrustManagerFactory buildTrustManagerFactory() { TrustManagerFactory tmf; @@ -186,7 +184,7 @@ public void client_certificates_should_reload() throws Exception { final ReloadingKeyManagerFactory kmf = ReloadingKeyManagerFactory.create( - TMP_CLIENT_KEYSTORE_PATH, CERTSTORE_PASSWORD, NO_SCHEDULED_RELOAD); + TMP_CLIENT_KEYSTORE_PATH, CERTSTORE_PASSWORD, Optional.empty()); // Need a tmf that tells the server to send its certs final TrustManagerFactory tmf = buildTrustManagerFactory(); From 7e2c6579af564be6d1b161ec4159ecf517c190b4 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 6 Feb 2024 15:18:59 -0600 Subject: [PATCH 298/395] CASSANDRA-19352: Support native_transport_(address|port) + native_transport_port_ssl for DSE 6.8 (4.x edition) patch by absurdfarce; reviewed by absurdfarce and adutra for CASSANDRA-19352 --- .../core/metadata/DefaultTopologyMonitor.java | 76 ++++++-- .../metadata/DefaultTopologyMonitorTest.java | 180 ++++++++++++++++-- 2 files changed, 223 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java index 87008b05cec..f3dc988cfbc 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitor.java @@ -34,6 +34,7 @@ import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; import com.datastax.oss.protocol.internal.ProtocolConstants; import com.datastax.oss.protocol.internal.response.Error; import edu.umd.cs.findbugs.annotations.NonNull; @@ -69,6 +70,10 @@ public class DefaultTopologyMonitor implements TopologyMonitor { // Assume topology queries never need paging private static final int INFINITE_PAGE_SIZE = -1; + // A few system.peers columns which get special handling below + private static final String NATIVE_PORT = "native_port"; + private static final String NATIVE_TRANSPORT_PORT = "native_transport_port"; + private final String logPrefix; private final InternalDriverContext context; private final ControlConnection controlConnection; @@ -494,28 +499,65 @@ private void savePort(DriverChannel channel) { @Nullable protected InetSocketAddress getBroadcastRpcAddress( @NonNull AdminRow row, @NonNull EndPoint localEndPoint) { - // in system.peers or system.local - InetAddress broadcastRpcInetAddress = row.getInetAddress("rpc_address"); + + InetAddress broadcastRpcInetAddress = null; + Iterator addrCandidates = + Iterators.forArray( + // in system.peers_v2 (Cassandra >= 4.0) + "native_address", + // DSE 6.8 introduced native_transport_address and native_transport_port for the + // listen address. + "native_transport_address", + // in system.peers or system.local + "rpc_address"); + + while (broadcastRpcInetAddress == null && addrCandidates.hasNext()) + broadcastRpcInetAddress = row.getInetAddress(addrCandidates.next()); + // This could only happen if system tables are corrupted, but handle gracefully if (broadcastRpcInetAddress == null) { - // in system.peers_v2 (Cassandra >= 4.0) - broadcastRpcInetAddress = row.getInetAddress("native_address"); - if (broadcastRpcInetAddress == null) { - // This could only happen if system tables are corrupted, but handle gracefully - return null; + LOG.warn( + "[{}] Unable to determine broadcast RPC IP address, returning null. " + + "This is likely due to a misconfiguration or invalid system tables. " + + "Please validate the contents of system.local and/or {}.", + logPrefix, + getPeerTableName()); + return null; + } + + Integer broadcastRpcPort = null; + Iterator portCandidates = + Iterators.forArray( + // in system.peers_v2 (Cassandra >= 4.0) + NATIVE_PORT, + // DSE 6.8 introduced native_transport_address and native_transport_port for the + // listen address. + NATIVE_TRANSPORT_PORT, + // system.local for Cassandra >= 4.0 + "rpc_port"); + + while ((broadcastRpcPort == null || broadcastRpcPort == 0) && portCandidates.hasNext()) { + + String colName = portCandidates.next(); + broadcastRpcPort = row.getInteger(colName); + // Support override for SSL port (if enabled) in DSE + if (NATIVE_TRANSPORT_PORT.equals(colName) && context.getSslEngineFactory().isPresent()) { + + String sslColName = colName + "_ssl"; + broadcastRpcPort = row.getInteger(sslColName); } } - // system.local for Cassandra >= 4.0 - Integer broadcastRpcPort = row.getInteger("rpc_port"); + // use the default port if no port information was found in the row; + // note that in rare situations, the default port might not be known, in which case we + // report zero, as advertised in the javadocs of Node and NodeInfo. if (broadcastRpcPort == null || broadcastRpcPort == 0) { - // system.peers_v2 - broadcastRpcPort = row.getInteger("native_port"); - if (broadcastRpcPort == null || broadcastRpcPort == 0) { - // use the default port if no port information was found in the row; - // note that in rare situations, the default port might not be known, in which case we - // report zero, as advertised in the javadocs of Node and NodeInfo. - broadcastRpcPort = port == -1 ? 0 : port; - } + + LOG.warn( + "[{}] Unable to determine broadcast RPC port. " + + "Trying to fall back to port used by the control connection.", + logPrefix); + broadcastRpcPort = port == -1 ? 0 : port; } + InetSocketAddress broadcastRpcAddress = new InetSocketAddress(broadcastRpcInetAddress, broadcastRpcPort); if (row.contains("peer") && broadcastRpcAddress.equals(localEndPoint.resolve())) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitorTest.java index cc275eb1624..dd40f233518 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/DefaultTopologyMonitorTest.java @@ -38,6 +38,7 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.ssl.SslEngineFactory; import com.datastax.oss.driver.internal.core.addresstranslation.PassThroughAddressTranslator; import com.datastax.oss.driver.internal.core.adminrequest.AdminResult; import com.datastax.oss.driver.internal.core.adminrequest.AdminRow; @@ -50,9 +51,11 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import com.datastax.oss.driver.shaded.guava.common.collect.Maps; import com.datastax.oss.protocol.internal.Message; import com.datastax.oss.protocol.internal.ProtocolConstants; import com.datastax.oss.protocol.internal.response.Error; +import com.google.common.collect.Streams; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; @@ -95,6 +98,8 @@ public class DefaultTopologyMonitorTest { @Mock private Appender appender; @Captor private ArgumentCaptor loggingEventCaptor; + @Mock private SslEngineFactory sslEngineFactory; + private DefaultNode node1; private DefaultNode node2; @@ -414,18 +419,6 @@ public void should_skip_invalid_peers_row_v2(String columnToCheck) { + "This is likely a gossip or snitch issue, this node will be ignored."); } - @DataProvider - public static Object[][] columnsToCheckV1() { - return new Object[][] {{"rpc_address"}, {"host_id"}, {"data_center"}, {"rack"}, {"tokens"}}; - } - - @DataProvider - public static Object[][] columnsToCheckV2() { - return new Object[][] { - {"native_address"}, {"native_port"}, {"host_id"}, {"data_center"}, {"rack"}, {"tokens"} - }; - } - @Test public void should_stop_executing_queries_once_closed() { // Given @@ -443,9 +436,9 @@ public void should_stop_executing_queries_once_closed() { public void should_warn_when_control_host_found_in_system_peers() { // Given AdminRow local = mockLocalRow(1, node1.getHostId()); - AdminRow peer3 = mockPeersRow(3, UUID.randomUUID()); - AdminRow peer2 = mockPeersRow(2, node2.getHostId()); AdminRow peer1 = mockPeersRow(1, node2.getHostId()); // invalid + AdminRow peer2 = mockPeersRow(2, node2.getHostId()); + AdminRow peer3 = mockPeersRow(3, UUID.randomUUID()); topologyMonitor.stubQueries( new StubbedQuery("SELECT * FROM system.local", mockResult(local)), new StubbedQuery("SELECT * FROM system.peers_v2", Collections.emptyMap(), null, true), @@ -462,7 +455,7 @@ public void should_warn_when_control_host_found_in_system_peers() { .hasSize(3) .extractingResultOf("getEndPoint") .containsOnlyOnce(node1.getEndPoint())); - assertLog( + assertLogContains( Level.WARN, "[null] Control node /127.0.0.1:9042 has an entry for itself in system.peers: " + "this entry will be ignored. This is likely due to a misconfiguration; " @@ -492,7 +485,7 @@ public void should_warn_when_control_host_found_in_system_peers_v2() { .hasSize(3) .extractingResultOf("getEndPoint") .containsOnlyOnce(node1.getEndPoint())); - assertLog( + assertLogContains( Level.WARN, "[null] Control node /127.0.0.1:9042 has an entry for itself in system.peers_v2: " + "this entry will be ignored. This is likely due to a misconfiguration; " @@ -500,6 +493,116 @@ public void should_warn_when_control_host_found_in_system_peers_v2() { + "all nodes in your cluster."); } + // Confirm the base case of extracting peer info from peers_v2, no SSL involved + @Test + public void should_get_peer_address_info_peers_v2() { + // Given + AdminRow local = mockLocalRow(1, node1.getHostId()); + AdminRow peer2 = mockPeersV2Row(3, node2.getHostId()); + AdminRow peer1 = mockPeersV2Row(2, node1.getHostId()); + topologyMonitor.isSchemaV2 = true; + topologyMonitor.stubQueries( + new StubbedQuery("SELECT * FROM system.local", mockResult(local)), + new StubbedQuery("SELECT * FROM system.peers_v2", mockResult(peer2, peer1))); + when(context.getSslEngineFactory()).thenReturn(Optional.empty()); + + // When + CompletionStage> futureInfos = topologyMonitor.refreshNodeList(); + + // Then + assertThatStage(futureInfos) + .isSuccess( + infos -> { + Iterator iterator = infos.iterator(); + // First NodeInfo is for local, skip past that + iterator.next(); + NodeInfo peer2nodeInfo = iterator.next(); + assertThat(peer2nodeInfo.getEndPoint().resolve()) + .isEqualTo(new InetSocketAddress("127.0.0.3", 9042)); + NodeInfo peer1nodeInfo = iterator.next(); + assertThat(peer1nodeInfo.getEndPoint().resolve()) + .isEqualTo(new InetSocketAddress("127.0.0.2", 9042)); + }); + } + + // Confirm the base case of extracting peer info from DSE peers table, no SSL involved + @Test + public void should_get_peer_address_info_peers_dse() { + // Given + AdminRow local = mockLocalRow(1, node1.getHostId()); + AdminRow peer2 = mockPeersRowDse(3, node2.getHostId()); + AdminRow peer1 = mockPeersRowDse(2, node1.getHostId()); + topologyMonitor.isSchemaV2 = true; + topologyMonitor.stubQueries( + new StubbedQuery("SELECT * FROM system.local", mockResult(local)), + new StubbedQuery("SELECT * FROM system.peers_v2", Maps.newHashMap(), null, true), + new StubbedQuery("SELECT * FROM system.peers", mockResult(peer2, peer1))); + when(context.getSslEngineFactory()).thenReturn(Optional.empty()); + + // When + CompletionStage> futureInfos = topologyMonitor.refreshNodeList(); + + // Then + assertThatStage(futureInfos) + .isSuccess( + infos -> { + Iterator iterator = infos.iterator(); + // First NodeInfo is for local, skip past that + iterator.next(); + NodeInfo peer2nodeInfo = iterator.next(); + assertThat(peer2nodeInfo.getEndPoint().resolve()) + .isEqualTo(new InetSocketAddress("127.0.0.3", 9042)); + NodeInfo peer1nodeInfo = iterator.next(); + assertThat(peer1nodeInfo.getEndPoint().resolve()) + .isEqualTo(new InetSocketAddress("127.0.0.2", 9042)); + }); + } + + // Confirm the base case of extracting peer info from DSE peers table, this time with SSL + @Test + public void should_get_peer_address_info_peers_dse_with_ssl() { + // Given + AdminRow local = mockLocalRow(1, node1.getHostId()); + AdminRow peer2 = mockPeersRowDseWithSsl(3, node2.getHostId()); + AdminRow peer1 = mockPeersRowDseWithSsl(2, node1.getHostId()); + topologyMonitor.isSchemaV2 = true; + topologyMonitor.stubQueries( + new StubbedQuery("SELECT * FROM system.local", mockResult(local)), + new StubbedQuery("SELECT * FROM system.peers_v2", Maps.newHashMap(), null, true), + new StubbedQuery("SELECT * FROM system.peers", mockResult(peer2, peer1))); + when(context.getSslEngineFactory()).thenReturn(Optional.of(sslEngineFactory)); + + // When + CompletionStage> futureInfos = topologyMonitor.refreshNodeList(); + + // Then + assertThatStage(futureInfos) + .isSuccess( + infos -> { + Iterator iterator = infos.iterator(); + // First NodeInfo is for local, skip past that + iterator.next(); + NodeInfo peer2nodeInfo = iterator.next(); + assertThat(peer2nodeInfo.getEndPoint().resolve()) + .isEqualTo(new InetSocketAddress("127.0.0.3", 9043)); + NodeInfo peer1nodeInfo = iterator.next(); + assertThat(peer1nodeInfo.getEndPoint().resolve()) + .isEqualTo(new InetSocketAddress("127.0.0.2", 9043)); + }); + } + + @DataProvider + public static Object[][] columnsToCheckV1() { + return new Object[][] {{"rpc_address"}, {"host_id"}, {"data_center"}, {"rack"}, {"tokens"}}; + } + + @DataProvider + public static Object[][] columnsToCheckV2() { + return new Object[][] { + {"native_address"}, {"native_port"}, {"host_id"}, {"data_center"}, {"rack"}, {"tokens"} + }; + } + /** Mocks the query execution logic. */ private static class TestTopologyMonitor extends DefaultTopologyMonitor { @@ -641,6 +744,43 @@ private AdminRow mockPeersV2Row(int i, UUID hostId) { } } + // Mock row for DSE ~6.8 + private AdminRow mockPeersRowDse(int i, UUID hostId) { + try { + AdminRow row = mock(AdminRow.class); + when(row.contains("peer")).thenReturn(true); + when(row.isNull("data_center")).thenReturn(false); + when(row.getString("data_center")).thenReturn("dc" + i); + when(row.getString("dse_version")).thenReturn("6.8.30"); + when(row.contains("graph")).thenReturn(true); + when(row.isNull("host_id")).thenReturn(hostId == null); + when(row.getUuid("host_id")).thenReturn(hostId); + when(row.getInetAddress("peer")).thenReturn(InetAddress.getByName("127.0.0." + i)); + when(row.isNull("rack")).thenReturn(false); + when(row.getString("rack")).thenReturn("rack" + i); + when(row.isNull("native_transport_address")).thenReturn(false); + when(row.getInetAddress("native_transport_address")) + .thenReturn(InetAddress.getByName("127.0.0." + i)); + when(row.isNull("native_transport_port")).thenReturn(false); + when(row.getInteger("native_transport_port")).thenReturn(9042); + when(row.isNull("tokens")).thenReturn(false); + when(row.getSetOfString("tokens")).thenReturn(ImmutableSet.of("token" + i)); + when(row.isNull("rpc_address")).thenReturn(false); + + return row; + } catch (UnknownHostException e) { + fail("unexpected", e); + return null; + } + } + + private AdminRow mockPeersRowDseWithSsl(int i, UUID hostId) { + AdminRow row = mockPeersRowDse(i, hostId); + when(row.isNull("native_transport_port_ssl")).thenReturn(false); + when(row.getInteger("native_transport_port_ssl")).thenReturn(9043); + return row; + } + private AdminResult mockResult(AdminRow... rows) { AdminResult result = mock(AdminResult.class); when(result.iterator()).thenReturn(Iterators.forArray(rows)); @@ -654,4 +794,12 @@ private void assertLog(Level level, String message) { assertThat(logs).hasSize(1); assertThat(logs.iterator().next().getFormattedMessage()).contains(message); } + + private void assertLogContains(Level level, String message) { + verify(appender, atLeast(1)).doAppend(loggingEventCaptor.capture()); + Iterable logs = + filter(loggingEventCaptor.getAllValues()).with("level", level).get(); + assertThat( + Streams.stream(logs).map(ILoggingEvent::getFormattedMessage).anyMatch(message::contains)); + } } From 4c7133c72e136d23dbcea795e0041df764568931 Mon Sep 17 00:00:00 2001 From: Andy Tolbert <6889771+tolbertam@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:21:02 -0600 Subject: [PATCH 299/395] Replace uses of AttributeKey.newInstance The java driver uses netty channel attributes to decorate a connection's channel with the cluster name (returned from the system.local table) and the map from the OPTIONS response, both of which are obtained on connection initialization. There's an issue here that I wouldn't expect to see in practice in that the AttributeKey's used are created using AttributeKey.newInstance, which throws an exception if an AttributeKey of that name is defined anywhere else in evaluated code. This change attempts to resolve this issue by changing AttributeKey initialiation in DriverChannel from newInstance to valueOf, which avoids throwing an exception if an AttributeKey of the same name was previously instantiated. patch by Andy Tolbert; reviewed by Bret McGuire, Alexandre Dutra, Abe Ratnofsky for CASSANDRA-19290 --- .../oss/driver/internal/core/channel/DriverChannel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/DriverChannel.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/DriverChannel.java index 50932bed8c8..e40aa6f3097 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/DriverChannel.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/DriverChannel.java @@ -49,9 +49,9 @@ @ThreadSafe public class DriverChannel { - static final AttributeKey CLUSTER_NAME_KEY = AttributeKey.newInstance("cluster_name"); + static final AttributeKey CLUSTER_NAME_KEY = AttributeKey.valueOf("cluster_name"); static final AttributeKey>> OPTIONS_KEY = - AttributeKey.newInstance("options"); + AttributeKey.valueOf("options"); @SuppressWarnings("RedundantStringConstructorCall") static final Object GRACEFUL_CLOSE_MESSAGE = new String("GRACEFUL_CLOSE_MESSAGE"); From 40a9a49d50fac6abed2a5bb2cc2627e4085a399b Mon Sep 17 00:00:00 2001 From: Ekaterina Dimitrova Date: Mon, 29 Jan 2024 14:07:59 -0500 Subject: [PATCH 300/395] Fix data corruption in VectorCodec when using heap buffers patch by Ekaterina Dimitrova; reviewed by Alexandre Dutra and Bret McGuire for CASSANDRA-19333 --- .../internal/core/type/codec/VectorCodec.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java index 1b663a29d9e..2c4d2200b13 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java @@ -127,17 +127,19 @@ Elements should at least precede themselves with their size (along the lines of cqlType.getDimensions(), bytes.remaining())); } + ByteBuffer slice = bytes.slice(); List rv = new ArrayList(cqlType.getDimensions()); for (int i = 0; i < cqlType.getDimensions(); ++i) { - ByteBuffer slice = bytes.slice(); - slice.limit(elementSize); + // Set the limit for the current element + int originalPosition = slice.position(); + slice.limit(originalPosition + elementSize); rv.add(this.subtypeCodec.decode(slice, protocolVersion)); - bytes.position(bytes.position() + elementSize); + // Move to the start of the next element + slice.position(originalPosition + elementSize); + // Reset the limit to the end of the buffer + slice.limit(slice.capacity()); } - /* Restore the input ByteBuffer to its original state */ - bytes.rewind(); - return CqlVector.newInstance(rv); } From 98e25040f5e69db1092ccafb6665d8e92779cc46 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 28 Mar 2024 15:37:22 -0500 Subject: [PATCH 301/395] CASSANDRA-19504: Improve state management for Java versions in Jenkinsfile patch by Bret McGuire; reviewed by Bret McGuire for CASSANDRA-19504 --- Jenkinsfile | 19 ++++++++++--------- pom.xml | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c8247769631..8d2b74c5b08 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -61,12 +61,6 @@ def initializeEnvironment() { . ${JABBA_SHELL} jabba which 1.8''', returnStdout: true).trim() - env.TEST_JAVA_HOME = sh(label: 'Get TEST_JAVA_HOME',script: '''#!/bin/bash -le - . ${JABBA_SHELL} - jabba which ${JABBA_VERSION}''', returnStdout: true).trim() - env.TEST_JAVA_VERSION = sh(label: 'Get TEST_JAVA_VERSION',script: '''#!/bin/bash -le - echo "${JABBA_VERSION##*.}"''', returnStdout: true).trim() - sh label: 'Download Apache CassandraⓇ or DataStax Enterprise',script: '''#!/bin/bash -le . ${JABBA_SHELL} jabba use 1.8 @@ -115,7 +109,12 @@ def buildDriver(jabbaVersion) { } def executeTests() { - sh label: 'Execute tests', script: '''#!/bin/bash -le + def testJavaHome = sh(label: 'Get TEST_JAVA_HOME',script: '''#!/bin/bash -le + . ${JABBA_SHELL} + jabba which ${JABBA_VERSION}''', returnStdout: true).trim() + def testJavaVersion = (JABBA_VERSION =~ /.*\.(\d+)/)[0][1] + + def executeTestScript = '''#!/bin/bash -le # Load CCM environment variables set -o allexport . ${HOME}/environment.txt @@ -137,8 +136,8 @@ def executeTests() { printenv | sort mvn -B -V ${INTEGRATION_TESTS_FILTER_ARGUMENT} -T 1 verify \ - -Ptest-jdk-${TEST_JAVA_VERSION} \ - -DtestJavaHome=${TEST_JAVA_HOME} \ + -Ptest-jdk-'''+testJavaVersion+''' \ + -DtestJavaHome='''+testJavaHome+''' \ -DfailIfNoTests=false \ -Dmaven.test.failure.ignore=true \ -Dmaven.javadoc.skip=${SKIP_JAVADOCS} \ @@ -149,6 +148,8 @@ def executeTests() { ${ISOLATED_ITS_ARGUMENT} \ ${PARALLELIZABLE_ITS_ARGUMENT} ''' + echo "Invoking Maven with parameters test-jdk-${testJavaVersion} and testJavaHome = ${testJavaHome}" + sh label: 'Execute tests', script: executeTestScript } def executeCodeCoverage() { diff --git a/pom.xml b/pom.xml index 221e1f69a86..7decc96633a 100644 --- a/pom.xml +++ b/pom.xml @@ -728,6 +728,7 @@ limitations under the License.]]> maven-surefire-plugin + ${testing.jvm}/bin/java ${project.basedir}/src/test/resources/logback-test.xml From 4aa5abe701e529fd9be0c9b55214dad6f85f0649 Mon Sep 17 00:00:00 2001 From: Emelia <105240296+emeliawilkinson24@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:22:47 -0500 Subject: [PATCH 302/395] Update README.md Typo carried over from old docs, needed closing parenthesis. --- manual/cloud/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manual/cloud/README.md b/manual/cloud/README.md index 48197c49425..9116b03dac3 100644 --- a/manual/cloud/README.md +++ b/manual/cloud/README.md @@ -28,10 +28,10 @@ driver is configured in an application and that you will need to obtain a *secur 1. [Download][Download Maven] and [install][Install Maven] Maven. 2. Create an Astra database on [AWS/Azure/GCP][Create an Astra database - AWS/Azure/GCP]; alternatively, have a team member provide access to their - Astra database (instructions for [AWS/Azure/GCP][Access an Astra database - AWS/Azure/GCP] to + Astra database (see instructions for [AWS/Azure/GCP][Access an Astra database - AWS/Azure/GCP]) to obtain database connection details. -3. Download the secure connect bundle (instructions for - [AWS/Azure/GCP][Download the secure connect bundle - AWS/Azure/GCP], that contains connection +3. Download the secure connect bundle (see instructions for + [AWS/Azure/GCP][Download the secure connect bundle - AWS/Azure/GCP]) that contains connection information such as contact points and certificates. ### Procedure From 9c41aab6fd0a55d977a9844610d230b1e69868d7 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 8 Apr 2024 11:00:46 -0500 Subject: [PATCH 303/395] Update link to JIRA to ASF instance. Also include information about populating the component field. Patch by Bret McGuire; reviewed by Bret McGuire, Alexandre Dutra --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e8fe862f49..c53c8f2db29 100644 --- a/README.md +++ b/README.md @@ -74,13 +74,13 @@ See the [Cassandra error handling done right blog](https://www.datastax.com/blog * [Manual](manual/) * [API docs] -* Bug tracking: [JIRA] +* Bug tracking: [JIRA]. Make sure to select the "Client/java-driver" component when filing new tickets! * [Mailing list] * [Changelog] * [FAQ] [API docs]: https://docs.datastax.com/en/drivers/java/4.17 -[JIRA]: https://datastax-oss.atlassian.net/browse/JAVA +[JIRA]: https://issues.apache.org/jira/issues/?jql=project%20%3D%20CASSANDRA%20AND%20component%20%3D%20%22Client%2Fjava-driver%22%20ORDER%20BY%20key%20DESC [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [Changelog]: changelog/ [FAQ]: faq/ From 6c48329199862215abc22170769fd1a165e80a15 Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Thu, 14 Mar 2024 16:55:59 -0700 Subject: [PATCH 304/395] CASSANDRA-19468 Don't swallow exception during metadata refresh If an exception was thrown while getting new metadata as part of schema refresh it died on the admin executor instead of being propagated to the CompletableFuture argument. Instead, catch those exceptions and hand them off to the CompletableFuture. patch by Ammar Khaku; reviewed by Chris Lohfink, Bret McGuire for CASSANDRA-19468 --- .../core/metadata/MetadataManager.java | 53 ++++++++++--------- .../core/metadata/MetadataManagerTest.java | 23 ++++++++ 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java index 28e8b18f127..c9abfb7a625 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java @@ -437,30 +437,35 @@ private void startSchemaRequest(CompletableFuture refreshFu if (agreementError != null) { refreshFuture.completeExceptionally(agreementError); } else { - schemaQueriesFactory - .newInstance() - .execute() - .thenApplyAsync(this::parseAndApplySchemaRows, adminExecutor) - .whenComplete( - (newMetadata, metadataError) -> { - if (metadataError != null) { - refreshFuture.completeExceptionally(metadataError); - } else { - refreshFuture.complete( - new RefreshSchemaResult(newMetadata, schemaInAgreement)); - } - - firstSchemaRefreshFuture.complete(null); - - currentSchemaRefresh = null; - // If another refresh was enqueued during this one, run it now - if (queuedSchemaRefresh != null) { - CompletableFuture tmp = - this.queuedSchemaRefresh; - this.queuedSchemaRefresh = null; - startSchemaRequest(tmp); - } - }); + try { + schemaQueriesFactory + .newInstance() + .execute() + .thenApplyAsync(this::parseAndApplySchemaRows, adminExecutor) + .whenComplete( + (newMetadata, metadataError) -> { + if (metadataError != null) { + refreshFuture.completeExceptionally(metadataError); + } else { + refreshFuture.complete( + new RefreshSchemaResult(newMetadata, schemaInAgreement)); + } + + firstSchemaRefreshFuture.complete(null); + + currentSchemaRefresh = null; + // If another refresh was enqueued during this one, run it now + if (queuedSchemaRefresh != null) { + CompletableFuture tmp = + this.queuedSchemaRefresh; + this.queuedSchemaRefresh = null; + startSchemaRequest(tmp); + } + }); + } catch (Throwable t) { + LOG.debug("[{}] Exception getting new metadata", logPrefix, t); + refreshFuture.completeExceptionally(t); + } } }); } else if (queuedSchemaRefresh == null) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java index 460f99abd85..375209d9fcf 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java @@ -20,6 +20,7 @@ import static com.datastax.oss.driver.Assertions.assertThat; import static com.datastax.oss.driver.Assertions.assertThatStage; import static org.awaitility.Awaitility.await; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; @@ -33,6 +34,7 @@ import com.datastax.oss.driver.internal.core.context.EventBus; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.context.NettyOptions; +import com.datastax.oss.driver.internal.core.control.ControlConnection; import com.datastax.oss.driver.internal.core.metadata.schema.parsing.SchemaParserFactory; import com.datastax.oss.driver.internal.core.metadata.schema.queries.SchemaQueriesFactory; import com.datastax.oss.driver.internal.core.metrics.MetricsFactory; @@ -64,6 +66,7 @@ public class MetadataManagerTest { @Mock private InternalDriverContext context; @Mock private NettyOptions nettyOptions; + @Mock private ControlConnection controlConnection; @Mock private TopologyMonitor topologyMonitor; @Mock private DriverConfig config; @Mock private DriverExecutionProfile defaultProfile; @@ -85,6 +88,7 @@ public void setup() { when(context.getNettyOptions()).thenReturn(nettyOptions); when(context.getTopologyMonitor()).thenReturn(topologyMonitor); + when(context.getControlConnection()).thenReturn(controlConnection); when(defaultProfile.getDuration(DefaultDriverOption.METADATA_SCHEMA_WINDOW)) .thenReturn(Duration.ZERO); @@ -286,6 +290,25 @@ public void should_remove_node() { assertThat(refresh.broadcastRpcAddressToRemove).isEqualTo(broadcastRpcAddress2); } + @Test + public void refreshSchema_should_work() { + // Given + IllegalStateException expectedException = new IllegalStateException("Error we're testing"); + when(schemaQueriesFactory.newInstance()).thenThrow(expectedException); + when(topologyMonitor.refreshNodeList()).thenReturn(CompletableFuture.completedFuture(ImmutableList.of(mock(NodeInfo.class)))); + when(topologyMonitor.checkSchemaAgreement()).thenReturn(CompletableFuture.completedFuture(Boolean.TRUE)); + when(controlConnection.init(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(CompletableFuture.completedFuture(null)); + metadataManager.refreshNodes(); // required internal state setup for this + waitForPendingAdminTasks(() -> metadataManager.refreshes.size() == 1); // sanity check + + // When + CompletionStage result = metadataManager.refreshSchema("foo", true, true); + + // Then + waitForPendingAdminTasks(() -> result.toCompletableFuture().isDone()); + assertThatStage(result).isFailed(t -> assertThat(t).isEqualTo(expectedException)); + } + private static class TestMetadataManager extends MetadataManager { private List refreshes = new CopyOnWriteArrayList<>(); From 388a46b9c10b5653c71ac8840bcda0c91b59bce4 Mon Sep 17 00:00:00 2001 From: janehe Date: Fri, 12 Apr 2024 13:20:33 -0700 Subject: [PATCH 305/395] patch by Jane He; reviewed by Alexandre Dutra and Bret McGuire for CASSANDRA-19457 --- .../core/metrics/AbstractMetricUpdater.java | 2 -- .../core/metrics/DropwizardMetricUpdater.java | 2 +- .../internal/core/metrics/MetricUpdater.java | 2 ++ .../core/metrics/NoopNodeMetricUpdater.java | 5 +++++ .../core/metrics/NoopSessionMetricUpdater.java | 3 +++ .../internal/core/session/DefaultSession.java | 15 +++++++++++++++ .../driver/core/metrics/DropwizardMetricsIT.java | 6 ++++++ .../oss/driver/core/metrics/MetricsITBase.java | 10 ++++++++-- .../metrics/micrometer/MicrometerMetricsIT.java | 6 ++++++ .../microprofile/MicroProfileMetricsIT.java | 6 ++++++ .../micrometer/MicrometerMetricUpdater.java | 2 +- .../microprofile/MicroProfileMetricUpdater.java | 2 +- 12 files changed, 54 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java index fcfe56b605e..5e2392a2e7f 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java @@ -180,6 +180,4 @@ protected Timeout newTimeout() { expireAfter.toNanos(), TimeUnit.NANOSECONDS); } - - protected abstract void clearMetrics(); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java index 8590917be21..9377fb3a17e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/DropwizardMetricUpdater.java @@ -91,7 +91,7 @@ public void updateTimer( } @Override - protected void clearMetrics() { + public void clearMetrics() { for (MetricT metric : metrics.keySet()) { MetricId id = getMetricId(metric); registry.remove(id.getName()); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java index c4b432f3c50..c07d1b136af 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/MetricUpdater.java @@ -46,4 +46,6 @@ default void markMeter(MetricT metric, @Nullable String profileName) { void updateTimer(MetricT metric, @Nullable String profileName, long duration, TimeUnit unit); boolean isEnabled(MetricT metric, @Nullable String profileName); + + void clearMetrics(); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopNodeMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopNodeMetricUpdater.java index 45f0797c7b5..8d216990331 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopNodeMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopNodeMetricUpdater.java @@ -53,4 +53,9 @@ public boolean isEnabled(NodeMetric metric, String profileName) { // since methods don't do anything, return false return false; } + + @Override + public void clearMetrics() { + // nothing to do + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopSessionMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopSessionMetricUpdater.java index 1666261590c..7099a8ddcac 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopSessionMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/NoopSessionMetricUpdater.java @@ -53,4 +53,7 @@ public boolean isEnabled(SessionMetric metric, String profileName) { // since methods don't do anything, return false return false; } + + @Override + public void clearMetrics() {} } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java index af9dc183f7e..cb1271c9cba 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java @@ -34,6 +34,7 @@ import com.datastax.oss.driver.internal.core.channel.DriverChannel; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.context.LifecycleListener; +import com.datastax.oss.driver.internal.core.metadata.DefaultNode; import com.datastax.oss.driver.internal.core.metadata.MetadataManager; import com.datastax.oss.driver.internal.core.metadata.MetadataManager.RefreshSchemaResult; import com.datastax.oss.driver.internal.core.metadata.NodeStateEvent; @@ -546,6 +547,13 @@ private void close() { closePolicies(); + // clear metrics to prevent memory leak + for (Node n : metadataManager.getMetadata().getNodes().values()) { + ((DefaultNode) n).getMetricUpdater().clearMetrics(); + } + + DefaultSession.this.metricUpdater.clearMetrics(); + List> childrenCloseStages = new ArrayList<>(); for (AsyncAutoCloseable closeable : internalComponentsToClose()) { childrenCloseStages.add(closeable.closeAsync()); @@ -565,6 +573,13 @@ private void forceClose() { logPrefix, (closeWasCalled ? "" : "not ")); + // clear metrics to prevent memory leak + for (Node n : metadataManager.getMetadata().getNodes().values()) { + ((DefaultNode) n).getMetricUpdater().clearMetrics(); + } + + DefaultSession.this.metricUpdater.clearMetrics(); + if (closeWasCalled) { // onChildrenClosed has already been scheduled for (AsyncAutoCloseable closeable : internalComponentsToClose()) { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java index 6cbe443f2a6..e0184516e21 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/DropwizardMetricsIT.java @@ -198,6 +198,12 @@ protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) { } } + @Override + protected void assertMetricsNotPresent(Object registry) { + MetricRegistry dropwizardRegistry = (MetricRegistry) registry; + assertThat(dropwizardRegistry.getMetrics()).isEmpty(); + } + @Override protected void assertNodeMetricsEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java index 7fac3f98f52..e6121217619 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metrics/MetricsITBase.java @@ -83,8 +83,10 @@ public void resetSimulacron() { @Test @UseDataProvider("descriptorsAndPrefixes") - public void should_expose_metrics_if_enabled(Class metricIdGenerator, String prefix) { + public void should_expose_metrics_if_enabled_and_clear_metrics_if_closed( + Class metricIdGenerator, String prefix) { + Object registry = newMetricRegistry(); Assume.assumeFalse( "Cannot use metric tags with Dropwizard", metricIdGenerator.getSimpleName().contains("Tagging") @@ -101,12 +103,14 @@ public void should_expose_metrics_if_enabled(Class metricIdGenerator, String CqlSession.builder() .addContactEndPoints(simulacron().getContactPoints()) .withConfigLoader(loader) - .withMetricRegistry(newMetricRegistry()) + .withMetricRegistry(registry) .build()) { session.prepare("irrelevant"); queryAllNodes(session); assertMetricsPresent(session); + } finally { + assertMetricsNotPresent(registry); } } @@ -262,4 +266,6 @@ private DefaultNode findNode(CqlSession session, int id) { return (DefaultNode) session.getMetadata().findNode(address1).orElseThrow(IllegalStateException::new); } + + protected abstract void assertMetricsNotPresent(Object registry); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java index 5fe64719327..c38df1e2026 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/micrometer/MicrometerMetricsIT.java @@ -186,6 +186,12 @@ protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) { } } + @Override + protected void assertMetricsNotPresent(Object registry) { + MeterRegistry micrometerRegistry = (MeterRegistry) registry; + assertThat(micrometerRegistry.getMeters()).isEmpty(); + } + @Override protected void assertNodeMetricsEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java index 1294be3deae..aa04c058a49 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/metrics/microprofile/MicroProfileMetricsIT.java @@ -188,6 +188,12 @@ protected void assertNodeMetricsNotEvicted(CqlSession session, Node node) { } } + @Override + protected void assertMetricsNotPresent(Object registry) { + MetricRegistry metricRegistry = (MetricRegistry) registry; + assertThat(metricRegistry.getMetrics()).isEmpty(); + } + @Override protected void assertNodeMetricsEvicted(CqlSession session, Node node) { InternalDriverContext context = (InternalDriverContext) session.getContext(); diff --git a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java index 7a4a27991e3..b9507c8b7cf 100644 --- a/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java +++ b/metrics/micrometer/src/main/java/com/datastax/oss/driver/internal/metrics/micrometer/MicrometerMetricUpdater.java @@ -83,7 +83,7 @@ public void updateTimer( } @Override - protected void clearMetrics() { + public void clearMetrics() { for (Meter metric : metrics.values()) { registry.remove(metric); } diff --git a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java index a46e82ee624..df44fd69c51 100644 --- a/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java +++ b/metrics/microprofile/src/main/java/com/datastax/oss/driver/internal/metrics/microprofile/MicroProfileMetricUpdater.java @@ -83,7 +83,7 @@ public void updateTimer( } @Override - protected void clearMetrics() { + public void clearMetrics() { for (MetricT metric : metrics.keySet()) { MetricId id = getMetricId(metric); Tag[] tags = MicroProfileTags.toMicroProfileTags(id.getTags()); From c8b17ac38b48ca580b4862571cdfd7b7633a5793 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 19 Feb 2024 23:07:18 -0600 Subject: [PATCH 306/395] Changelog updates to reflect work that went out in 4.18.0 Patch by Bret McGuire; reviewed by Bret McGuire, Alexandre Dutra for PR 1914 --- changelog/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 8ff2913b72d..7807ef15f95 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -21,6 +21,16 @@ under the License. +### 4.18.0 + +- [improvement] PR 1689: Add support for publishing percentile time series for the histogram metrics (nparaddi-walmart) +- [improvement] JAVA-3104: Do not eagerly pre-allocate array when deserializing CqlVector +- [improvement] JAVA-3111: upgrade jackson-databind to 2.13.4.2 to address gradle dependency issue +- [improvement] PR 1617: Improve ByteBufPrimitiveCodec readBytes (chibenwa) +- [improvement] JAVA-3095: Fix CREATE keyword in vector search example in upgrade guide +- [improvement] JAVA-3100: Update jackson-databind to 2.13.4.1 and jackson-jaxrs-json-provider to 2.13.4 to address recent CVEs +- [improvement] JAVA-3089: Forbid wildcard imports + ### 4.17.0 - [improvement] JAVA-3070: Make CqlVector and CqlDuration serializable From 3c08f8efa24cddb33b807a5e1f8f16824632a611 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Wed, 17 Apr 2024 01:34:40 -0500 Subject: [PATCH 307/395] Fixes to get past code formatting issues patch by Bret McGuire; reviewed by Bret McGuire for PR 1928 --- .../core/metadata/MetadataManager.java | 46 +++++++++---------- .../core/metadata/MetadataManagerTest.java | 12 +++-- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java index c9abfb7a625..efb04bde5e1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/MetadataManager.java @@ -439,29 +439,29 @@ private void startSchemaRequest(CompletableFuture refreshFu } else { try { schemaQueriesFactory - .newInstance() - .execute() - .thenApplyAsync(this::parseAndApplySchemaRows, adminExecutor) - .whenComplete( - (newMetadata, metadataError) -> { - if (metadataError != null) { - refreshFuture.completeExceptionally(metadataError); - } else { - refreshFuture.complete( - new RefreshSchemaResult(newMetadata, schemaInAgreement)); - } - - firstSchemaRefreshFuture.complete(null); - - currentSchemaRefresh = null; - // If another refresh was enqueued during this one, run it now - if (queuedSchemaRefresh != null) { - CompletableFuture tmp = - this.queuedSchemaRefresh; - this.queuedSchemaRefresh = null; - startSchemaRequest(tmp); - } - }); + .newInstance() + .execute() + .thenApplyAsync(this::parseAndApplySchemaRows, adminExecutor) + .whenComplete( + (newMetadata, metadataError) -> { + if (metadataError != null) { + refreshFuture.completeExceptionally(metadataError); + } else { + refreshFuture.complete( + new RefreshSchemaResult(newMetadata, schemaInAgreement)); + } + + firstSchemaRefreshFuture.complete(null); + + currentSchemaRefresh = null; + // If another refresh was enqueued during this one, run it now + if (queuedSchemaRefresh != null) { + CompletableFuture tmp = + this.queuedSchemaRefresh; + this.queuedSchemaRefresh = null; + startSchemaRequest(tmp); + } + }); } catch (Throwable t) { LOG.debug("[{}] Exception getting new metadata", logPrefix, t); refreshFuture.completeExceptionally(t); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java index 375209d9fcf..f9a909400f9 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/MetadataManagerTest.java @@ -295,14 +295,18 @@ public void refreshSchema_should_work() { // Given IllegalStateException expectedException = new IllegalStateException("Error we're testing"); when(schemaQueriesFactory.newInstance()).thenThrow(expectedException); - when(topologyMonitor.refreshNodeList()).thenReturn(CompletableFuture.completedFuture(ImmutableList.of(mock(NodeInfo.class)))); - when(topologyMonitor.checkSchemaAgreement()).thenReturn(CompletableFuture.completedFuture(Boolean.TRUE)); - when(controlConnection.init(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(CompletableFuture.completedFuture(null)); + when(topologyMonitor.refreshNodeList()) + .thenReturn(CompletableFuture.completedFuture(ImmutableList.of(mock(NodeInfo.class)))); + when(topologyMonitor.checkSchemaAgreement()) + .thenReturn(CompletableFuture.completedFuture(Boolean.TRUE)); + when(controlConnection.init(anyBoolean(), anyBoolean(), anyBoolean())) + .thenReturn(CompletableFuture.completedFuture(null)); metadataManager.refreshNodes(); // required internal state setup for this waitForPendingAdminTasks(() -> metadataManager.refreshes.size() == 1); // sanity check // When - CompletionStage result = metadataManager.refreshSchema("foo", true, true); + CompletionStage result = + metadataManager.refreshSchema("foo", true, true); // Then waitForPendingAdminTasks(() -> result.toCompletableFuture().isDone()); From 07265b4a6830a47752bf31eb4f631b9917863da2 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Tue, 23 Apr 2024 00:38:48 -0500 Subject: [PATCH 308/395] Initial fix to unit tests patch by Bret McGuire; reviewed by Bret McGuire for PR 1930 --- .../driver/internal/core/session/DefaultSession.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java index cb1271c9cba..6f063ae9a50 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java @@ -39,6 +39,7 @@ import com.datastax.oss.driver.internal.core.metadata.MetadataManager.RefreshSchemaResult; import com.datastax.oss.driver.internal.core.metadata.NodeStateEvent; import com.datastax.oss.driver.internal.core.metadata.NodeStateManager; +import com.datastax.oss.driver.internal.core.metrics.NodeMetricUpdater; import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; import com.datastax.oss.driver.internal.core.pool.ChannelPool; import com.datastax.oss.driver.internal.core.util.Loggers; @@ -549,10 +550,11 @@ private void close() { // clear metrics to prevent memory leak for (Node n : metadataManager.getMetadata().getNodes().values()) { - ((DefaultNode) n).getMetricUpdater().clearMetrics(); + NodeMetricUpdater updater = ((DefaultNode) n).getMetricUpdater(); + if (updater != null) updater.clearMetrics(); } - DefaultSession.this.metricUpdater.clearMetrics(); + if (metricUpdater != null) metricUpdater.clearMetrics(); List> childrenCloseStages = new ArrayList<>(); for (AsyncAutoCloseable closeable : internalComponentsToClose()) { @@ -575,10 +577,11 @@ private void forceClose() { // clear metrics to prevent memory leak for (Node n : metadataManager.getMetadata().getNodes().values()) { - ((DefaultNode) n).getMetricUpdater().clearMetrics(); + NodeMetricUpdater updater = ((DefaultNode) n).getMetricUpdater(); + if (updater != null) updater.clearMetrics(); } - DefaultSession.this.metricUpdater.clearMetrics(); + if (metricUpdater != null) metricUpdater.clearMetrics(); if (closeWasCalled) { // onChildrenClosed has already been scheduled From 1492d6ced9d54bdd68deb043a0bfe232eaa2a8fc Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Fri, 29 Mar 2024 00:46:46 -0500 Subject: [PATCH 309/395] CASSANDRA-19292: Enable Jenkins to test against Cassandra 4.1.x patch by Bret McGuire; reviewed by Bret McGuire, Alexandre Dutra for CASSANDRA-19292 --- Jenkinsfile | 20 ++++-- .../datastax/oss/driver/api/core/Version.java | 1 + .../oss/driver/core/metadata/SchemaIT.java | 13 ++++ .../driver/api/testinfra/ccm/CcmBridge.java | 61 ++++++++++++++++++- 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8d2b74c5b08..0bfa4ca7f4a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -256,8 +256,10 @@ pipeline { choices: ['2.1', // Legacy Apache CassandraⓇ '2.2', // Legacy Apache CassandraⓇ '3.0', // Previous Apache CassandraⓇ - '3.11', // Current Apache CassandraⓇ - '4.0', // Development Apache CassandraⓇ + '3.11', // Previous Apache CassandraⓇ + '4.0', // Previous Apache CassandraⓇ + '4.1', // Current Apache CassandraⓇ + '5.0', // Development Apache CassandraⓇ 'dse-4.8.16', // Previous EOSL DataStax Enterprise 'dse-5.0.15', // Long Term Support DataStax Enterprise 'dse-5.1.35', // Legacy DataStax Enterprise @@ -291,7 +293,11 @@ pipeline {

    - + + + + + @@ -445,7 +451,7 @@ pipeline { axis { name 'SERVER_VERSION' values '3.11', // Latest stable Apache CassandraⓇ - '4.0', // Development Apache CassandraⓇ + '4.1', // Development Apache CassandraⓇ 'dse-6.8.30' // Current DataStax Enterprise } axis { @@ -554,8 +560,10 @@ pipeline { name 'SERVER_VERSION' values '2.1', // Legacy Apache CassandraⓇ '3.0', // Previous Apache CassandraⓇ - '3.11', // Current Apache CassandraⓇ - '4.0', // Development Apache CassandraⓇ + '3.11', // Previous Apache CassandraⓇ + '4.0', // Previous Apache CassandraⓇ + '4.1', // Current Apache CassandraⓇ + '5.0', // Development Apache CassandraⓇ 'dse-4.8.16', // Previous EOSL DataStax Enterprise 'dse-5.0.15', // Last EOSL DataStax Enterprise 'dse-5.1.35', // Legacy DataStax Enterprise diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/Version.java b/core/src/main/java/com/datastax/oss/driver/api/core/Version.java index cc4931fe2fa..3f12c54faf7 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/Version.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/Version.java @@ -52,6 +52,7 @@ public class Version implements Comparable, Serializable { @NonNull public static final Version V2_2_0 = Objects.requireNonNull(parse("2.2.0")); @NonNull public static final Version V3_0_0 = Objects.requireNonNull(parse("3.0.0")); @NonNull public static final Version V4_0_0 = Objects.requireNonNull(parse("4.0.0")); + @NonNull public static final Version V4_1_0 = Objects.requireNonNull(parse("4.1.0")); @NonNull public static final Version V5_0_0 = Objects.requireNonNull(parse("5.0.0")); @NonNull public static final Version V6_7_0 = Objects.requireNonNull(parse("6.7.0")); @NonNull public static final Version V6_8_0 = Objects.requireNonNull(parse("6.8.0")); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index caa96a647be..6495b451df7 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -265,6 +265,19 @@ public void should_get_virtual_metadata() { + " total bigint,\n" + " unit text,\n" + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" + + "); */", + // Cassandra 4.1 + "/* VIRTUAL TABLE system_views.sstable_tasks (\n" + + " keyspace_name text,\n" + + " table_name text,\n" + + " task_id timeuuid,\n" + + " completion_ratio double,\n" + + " kind text,\n" + + " progress bigint,\n" + + " sstables int,\n" + + " total bigint,\n" + + " unit text,\n" + + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" + "); */"); // ColumnMetadata is as expected ColumnMetadata cm = tm.getColumn("progress").get(); diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java index 5f845243bf8..98739e7715d 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java @@ -236,12 +236,33 @@ public void create() { Arrays.stream(nodes).mapToObj(n -> "" + n).collect(Collectors.joining(":")), createOptions.stream().collect(Collectors.joining(" "))); + Version cassandraVersion = getCassandraVersion(); for (Map.Entry conf : cassandraConfiguration.entrySet()) { - execute("updateconf", String.format("%s:%s", conf.getKey(), conf.getValue())); + String originalKey = conf.getKey(); + Object originalValue = conf.getValue(); + execute( + "updateconf", + String.join( + ":", + getConfigKey(originalKey, originalValue, cassandraVersion), + getConfigValue(originalKey, originalValue, cassandraVersion))); } - if (getCassandraVersion().compareTo(Version.V2_2_0) >= 0) { - execute("updateconf", "enable_user_defined_functions:true"); + + // If we're dealing with anything more recent than 2.2 explicitly enable UDF... but run it + // through our conversion process to make + // sure more recent versions don't have a problem. + if (cassandraVersion.compareTo(Version.V2_2_0) >= 0) { + String originalKey = "enable_user_defined_functions"; + Object originalValue = "true"; + execute( + "updateconf", + String.join( + ":", + getConfigKey(originalKey, originalValue, cassandraVersion), + getConfigValue(originalKey, originalValue, cassandraVersion))); } + + // Note that we aren't performing any substitution on DSE key/value props (at least for now) if (DSE_ENABLEMENT) { for (Map.Entry conf : dseConfiguration.entrySet()) { execute("updatedseconf", String.format("%s:%s", conf.getKey(), conf.getValue())); @@ -463,6 +484,40 @@ private Optional overrideJvmVersionForDseWorkloads() { return Optional.empty(); } + private static String IN_MS_STR = "_in_ms"; + private static int IN_MS_STR_LENGTH = IN_MS_STR.length(); + private static String ENABLE_STR = "enable_"; + private static int ENABLE_STR_LENGTH = ENABLE_STR.length(); + private static String IN_KB_STR = "_in_kb"; + private static int IN_KB_STR_LENGTH = IN_KB_STR.length(); + + @SuppressWarnings("unused") + private String getConfigKey(String originalKey, Object originalValue, Version cassandraVersion) { + + // At least for now we won't support substitutions on nested keys. This requires an extra + // traversal of the string + // but we'll live with that for now + if (originalKey.contains(".")) return originalKey; + if (cassandraVersion.compareTo(Version.V4_1_0) < 0) return originalKey; + if (originalKey.endsWith(IN_MS_STR)) + return originalKey.substring(0, originalKey.length() - IN_MS_STR_LENGTH); + if (originalKey.startsWith(ENABLE_STR)) + return originalKey.substring(ENABLE_STR_LENGTH) + "_enabled"; + if (originalKey.endsWith(IN_KB_STR)) + return originalKey.substring(0, originalKey.length() - IN_KB_STR_LENGTH); + return originalKey; + } + + private String getConfigValue( + String originalKey, Object originalValue, Version cassandraVersion) { + + String originalValueStr = originalValue.toString(); + if (cassandraVersion.compareTo(Version.V4_1_0) < 0) return originalValueStr; + if (originalKey.endsWith(IN_MS_STR)) return originalValueStr + "ms"; + if (originalKey.endsWith(IN_KB_STR)) return originalValueStr + "KiB"; + return originalValueStr; + } + public static Builder builder() { return new Builder(); } From b9760b473b6e6e30f5da5f743e37e02150e13e39 Mon Sep 17 00:00:00 2001 From: Nitin Chhabra Date: Thu, 30 Nov 2023 12:38:23 -0800 Subject: [PATCH 310/395] JAVA-3142: Ability to specify ordering of remote local dc's via new configuration for graceful automatic failovers patch by Nitin Chhabra; reviewed by Alexandre Dutra, Andy Tolbert, and Bret McGuire for JAVA-3142 --- .../api/core/config/DefaultDriverOption.java | 8 +- .../driver/api/core/config/OptionsMap.java | 2 + .../api/core/config/TypedDriverOption.java | 10 + .../BasicLoadBalancingPolicy.java | 84 ++++++-- core/src/main/resources/reference.conf | 5 + ...BalancingPolicyPreferredRemoteDcsTest.java | 184 ++++++++++++++++++ 6 files changed, 271 insertions(+), 22 deletions(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyPreferredRemoteDcsTest.java diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index afe16e96886..11f2702c3cf 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -982,7 +982,13 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: {@link java.time.Duration} */ SSL_KEYSTORE_RELOAD_INTERVAL("advanced.ssl-engine-factory.keystore-reload-interval"), - ; + /** + * Ordered preference list of remote dcs optionally supplied for automatic failover. + * + *

    Value type: {@link java.util.List List}<{@link String}> + */ + LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS( + "advanced.load-balancing-policy.dc-failover.preferred-remote-dcs"); private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java index 8906e1dd349..98faf3e590c 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/OptionsMap.java @@ -381,6 +381,8 @@ protected static void fillWithDriverDefaults(OptionsMap map) { map.put(TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC, 0); map.put(TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, false); map.put(TypedDriverOption.METRICS_GENERATE_AGGREGABLE_HISTOGRAMS, true); + map.put( + TypedDriverOption.LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS, ImmutableList.of("")); } @Immutable diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index 88c012fa351..ca60b67f0ba 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -892,6 +892,16 @@ public String toString() { DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, GenericType.BOOLEAN); + /** + * Ordered preference list of remote dcs optionally supplied for automatic failover and included + * in query plan. This feature is enabled only when max-nodes-per-remote-dc is greater than 0. + */ + public static final TypedDriverOption> + LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS = + new TypedDriverOption<>( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS, + GenericType.listOf(String.class)); + private static Iterable> introspectBuiltInValues() { try { ImmutableList.Builder> result = ImmutableList.builder(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java index b1adec3f143..587ef4183bd 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java @@ -45,10 +45,14 @@ import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import com.datastax.oss.driver.shaded.guava.common.base.Predicates; +import com.datastax.oss.driver.shaded.guava.common.collect.Lists; +import com.datastax.oss.driver.shaded.guava.common.collect.Sets; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -117,6 +121,7 @@ public class BasicLoadBalancingPolicy implements LoadBalancingPolicy { private volatile NodeDistanceEvaluator nodeDistanceEvaluator; private volatile String localDc; private volatile NodeSet liveNodes; + private final LinkedHashSet preferredRemoteDcs; public BasicLoadBalancingPolicy(@NonNull DriverContext context, @NonNull String profileName) { this.context = (InternalDriverContext) context; @@ -131,6 +136,11 @@ public BasicLoadBalancingPolicy(@NonNull DriverContext context, @NonNull String this.context .getConsistencyLevelRegistry() .nameToLevel(profile.getString(DefaultDriverOption.REQUEST_CONSISTENCY)); + + preferredRemoteDcs = + new LinkedHashSet<>( + profile.getStringList( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS)); } /** @@ -320,27 +330,59 @@ protected Queue maybeAddDcFailover(@Nullable Request request, @NonNull Que return local; } } - QueryPlan remote = - new LazyQueryPlan() { - - @Override - protected Object[] computeNodes() { - Object[] remoteNodes = - liveNodes.dcs().stream() - .filter(Predicates.not(Predicates.equalTo(localDc))) - .flatMap(dc -> liveNodes.dc(dc).stream().limit(maxNodesPerRemoteDc)) - .toArray(); - - int remoteNodesLength = remoteNodes.length; - if (remoteNodesLength == 0) { - return EMPTY_NODES; - } - shuffleHead(remoteNodes, remoteNodesLength); - return remoteNodes; - } - }; - - return new CompositeQueryPlan(local, remote); + if (preferredRemoteDcs.isEmpty()) { + return new CompositeQueryPlan(local, buildRemoteQueryPlanAll()); + } + return new CompositeQueryPlan(local, buildRemoteQueryPlanPreferred()); + } + + private QueryPlan buildRemoteQueryPlanAll() { + + return new LazyQueryPlan() { + @Override + protected Object[] computeNodes() { + + Object[] remoteNodes = + liveNodes.dcs().stream() + .filter(Predicates.not(Predicates.equalTo(localDc))) + .flatMap(dc -> liveNodes.dc(dc).stream().limit(maxNodesPerRemoteDc)) + .toArray(); + if (remoteNodes.length == 0) { + return EMPTY_NODES; + } + shuffleHead(remoteNodes, remoteNodes.length); + return remoteNodes; + } + }; + } + + private QueryPlan buildRemoteQueryPlanPreferred() { + + Set dcs = liveNodes.dcs(); + List orderedDcs = Lists.newArrayListWithCapacity(dcs.size()); + orderedDcs.addAll(preferredRemoteDcs); + orderedDcs.addAll(Sets.difference(dcs, preferredRemoteDcs)); + + QueryPlan[] queryPlans = + orderedDcs.stream() + .filter(Predicates.not(Predicates.equalTo(localDc))) + .map( + (dc) -> { + return new LazyQueryPlan() { + @Override + protected Object[] computeNodes() { + Object[] rv = liveNodes.dc(dc).stream().limit(maxNodesPerRemoteDc).toArray(); + if (rv.length == 0) { + return EMPTY_NODES; + } + shuffleHead(rv, rv.length); + return rv; + } + }; + }) + .toArray(QueryPlan[]::new); + + return new CompositeQueryPlan(queryPlans); } /** Exposed as a protected method so that it can be accessed by tests */ diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index d1ac22e553b..7a56a18e9f1 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -574,6 +574,11 @@ datastax-java-driver { # Modifiable at runtime: no # Overridable in a profile: yes allow-for-local-consistency-levels = false + # Ordered preference list of remote dc's (in order) optionally supplied for automatic failover. While building a query plan, the driver uses the DC's supplied in order together with max-nodes-per-remote-dc + # Required: no + # Modifiable at runtime: no + # Overridable in a profile: no + preferred-remote-dcs = [""] } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyPreferredRemoteDcsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyPreferredRemoteDcsTest.java new file mode 100644 index 00000000000..cefdfd31189 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicyPreferredRemoteDcsTest.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.loadbalancing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.internal.core.metadata.DefaultNode; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import java.util.Map; +import java.util.UUID; +import org.junit.Test; +import org.mockito.Mock; + +public class BasicLoadBalancingPolicyPreferredRemoteDcsTest + extends BasicLoadBalancingPolicyDcFailoverTest { + @Mock protected DefaultNode node10; + @Mock protected DefaultNode node11; + @Mock protected DefaultNode node12; + @Mock protected DefaultNode node13; + @Mock protected DefaultNode node14; + + @Override + @Test + public void should_prioritize_single_replica() { + when(request.getRoutingKeyspace()).thenReturn(KEYSPACE); + when(request.getRoutingKey()).thenReturn(ROUTING_KEY); + when(tokenMap.getReplicas(KEYSPACE, ROUTING_KEY)).thenReturn(ImmutableSet.of(node3)); + + // node3 always first, round-robin on the rest + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node3, node1, node2, node4, node5, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node3, node2, node4, node5, node1, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node3, node4, node5, node1, node2, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node3, node5, node1, node2, node4, node9, node10, node6, node7, node12, node13); + + // Should not shuffle replicas since there is only one + verify(policy, never()).shuffleHead(any(), eq(1)); + // But should shuffle remote nodes + verify(policy, times(12)).shuffleHead(any(), eq(2)); + } + + @Override + @Test + public void should_prioritize_and_shuffle_replicas() { + when(request.getRoutingKeyspace()).thenReturn(KEYSPACE); + when(request.getRoutingKey()).thenReturn(ROUTING_KEY); + when(tokenMap.getReplicas(KEYSPACE, ROUTING_KEY)) + .thenReturn(ImmutableSet.of(node1, node2, node3, node6, node9)); + + // node 6 and 9 being in a remote DC, they don't get a boost for being a replica + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node1, node2, node3, node4, node5, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node1, node2, node3, node5, node4, node9, node10, node6, node7, node12, node13); + + // should shuffle replicas + verify(policy, times(2)).shuffleHead(any(), eq(3)); + // should shuffle remote nodes + verify(policy, times(6)).shuffleHead(any(), eq(2)); + // No power of two choices with only two replicas + verify(session, never()).getPools(); + } + + @Override + protected void assertRoundRobinQueryPlans() { + for (int i = 0; i < 3; i++) { + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node1, node2, node3, node4, node5, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node2, node3, node4, node5, node1, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node3, node4, node5, node1, node2, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node4, node5, node1, node2, node3, node9, node10, node6, node7, node12, node13); + assertThat(policy.newQueryPlan(request, session)) + .containsExactly( + node5, node1, node2, node3, node4, node9, node10, node6, node7, node12, node13); + } + + verify(policy, atLeast(15)).shuffleHead(any(), eq(2)); + } + + @Override + protected BasicLoadBalancingPolicy createAndInitPolicy() { + when(node4.getDatacenter()).thenReturn("dc1"); + when(node5.getDatacenter()).thenReturn("dc1"); + when(node6.getDatacenter()).thenReturn("dc2"); + when(node7.getDatacenter()).thenReturn("dc2"); + when(node8.getDatacenter()).thenReturn("dc2"); + when(node9.getDatacenter()).thenReturn("dc3"); + when(node10.getDatacenter()).thenReturn("dc3"); + when(node11.getDatacenter()).thenReturn("dc3"); + when(node12.getDatacenter()).thenReturn("dc4"); + when(node13.getDatacenter()).thenReturn("dc4"); + when(node14.getDatacenter()).thenReturn("dc4"); + + // Accept 2 nodes per remote DC + when(defaultProfile.getInt( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .thenReturn(2); + when(defaultProfile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS)) + .thenReturn(false); + + when(defaultProfile.getStringList( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS)) + .thenReturn(ImmutableList.of("dc3", "dc2")); + + // Use a subclass to disable shuffling, we just spy to make sure that the shuffling method was + // called (makes tests easier) + BasicLoadBalancingPolicy policy = + spy( + new BasicLoadBalancingPolicy(context, DriverExecutionProfile.DEFAULT_NAME) { + @Override + protected void shuffleHead(Object[] currentNodes, int headLength) { + // nothing (keep in same order) + } + }); + Map nodes = + ImmutableMap.builder() + .put(UUID.randomUUID(), node1) + .put(UUID.randomUUID(), node2) + .put(UUID.randomUUID(), node3) + .put(UUID.randomUUID(), node4) + .put(UUID.randomUUID(), node5) + .put(UUID.randomUUID(), node6) + .put(UUID.randomUUID(), node7) + .put(UUID.randomUUID(), node8) + .put(UUID.randomUUID(), node9) + .put(UUID.randomUUID(), node10) + .put(UUID.randomUUID(), node11) + .put(UUID.randomUUID(), node12) + .put(UUID.randomUUID(), node13) + .put(UUID.randomUUID(), node14) + .build(); + policy.init(nodes, distanceReporter); + assertThat(policy.getLiveNodes().dc("dc1")).containsExactly(node1, node2, node3, node4, node5); + assertThat(policy.getLiveNodes().dc("dc2")).containsExactly(node6, node7); // only 2 allowed + assertThat(policy.getLiveNodes().dc("dc3")).containsExactly(node9, node10); // only 2 allowed + assertThat(policy.getLiveNodes().dc("dc4")).containsExactly(node12, node13); // only 2 allowed + return policy; + } +} From 3a687377449f736ba1ed28bfcff824982b3138c4 Mon Sep 17 00:00:00 2001 From: janehe Date: Wed, 17 Apr 2024 14:59:59 -0700 Subject: [PATCH 311/395] CASSANDRA-19568: Use Jabba to specify Java 1.8 for building the driver patch by Jane He and Bret McGuire; reviewed by Bret McGuire for CASSANDRA-19568 --- Jenkinsfile | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0bfa4ca7f4a..69ee0a294c0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -98,14 +98,16 @@ ENVIRONMENT_EOF } def buildDriver(jabbaVersion) { - withEnv(["BUILD_JABBA_VERSION=${jabbaVersion}"]) { - sh label: 'Build driver', script: '''#!/bin/bash -le - . ${JABBA_SHELL} - jabba use ${BUILD_JABBA_VERSION} + def buildDriverScript = '''#!/bin/bash -le - mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true - ''' - } + . ${JABBA_SHELL} + jabba use '''+jabbaVersion+''' + + echo "Building with Java version '''+jabbaVersion+''' + + mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true + ''' + sh label: 'Build driver', script: buildDriverScript } def executeTests() { @@ -484,7 +486,7 @@ pipeline { } stage('Build-Driver') { steps { - buildDriver('default') + buildDriver('1.8') } } stage('Execute-Tests') { @@ -600,8 +602,7 @@ pipeline { } stage('Build-Driver') { steps { - // Jabba default should be a JDK8 for now - buildDriver('default') + buildDriver('1.8') } } stage('Execute-Tests') { From 4bc346885fd373906ed6106b76df6d494cb51b67 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Wed, 8 May 2024 21:37:02 -0500 Subject: [PATCH 312/395] ninja-fix CASSANDRA-19568: fixing mangled Groovy --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 69ee0a294c0..d38b7c63849 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -103,7 +103,7 @@ def buildDriver(jabbaVersion) { . ${JABBA_SHELL} jabba use '''+jabbaVersion+''' - echo "Building with Java version '''+jabbaVersion+''' + echo "Building with Java version '''+jabbaVersion+'''" mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true ''' From ac452336356c30b125524f31dfa82cf8a465d716 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 16 May 2024 20:55:25 -0500 Subject: [PATCH 313/395] ninja-fix updating repo for releases --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7decc96633a..b4102b3380f 100644 --- a/pom.xml +++ b/pom.xml @@ -755,7 +755,7 @@ limitations under the License.]]> true ossrh - https://oss.sonatype.org/ + https://repository.apache.org/ false true From 3151129f7043a1b222131989584b07288c404be8 Mon Sep 17 00:00:00 2001 From: Nitin Chhabra Date: Wed, 8 May 2024 16:54:43 -0700 Subject: [PATCH 314/395] JAVA-3142: Improving the documentation for remote local dc's feature patch by Nitin Chhabra; reviewed by Bret McGuire for JAVA-3142 --- core/src/main/resources/reference.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 7a56a18e9f1..7b1c43f8bea 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -574,7 +574,9 @@ datastax-java-driver { # Modifiable at runtime: no # Overridable in a profile: yes allow-for-local-consistency-levels = false + # Ordered preference list of remote dc's (in order) optionally supplied for automatic failover. While building a query plan, the driver uses the DC's supplied in order together with max-nodes-per-remote-dc + # Users are not required to specify all DCs, when listing preferences via this config # Required: no # Modifiable at runtime: no # Overridable in a profile: no From f60e75842fa99cbb728a716c0236a89caa19b39c Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Fri, 17 May 2024 12:27:53 -0500 Subject: [PATCH 315/395] ninja-fix changlog updates for 4.18.1 --- changelog/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 7807ef15f95..83ebb44239f 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -21,6 +21,16 @@ under the License. +### 4.18.1 + +- [improvement] JAVA-3142: Ability to specify ordering of remote local dc's via new configuration for graceful automatic failovers +- [bug] CASSANDRA-19457: Object reference in Micrometer metrics prevent GC from reclaiming Session instances +- [improvement] CASSANDRA-19468: Don't swallow exception during metadata refresh +- [bug] CASSANDRA-19333: Fix data corruption in VectorCodec when using heap buffers +- [improvement] CASSANDRA-19290: Replace uses of AttributeKey.newInstance +- [improvement] CASSANDRA-19352: Support native_transport_(address|port) + native_transport_port_ssl for DSE 6.8 (4.x edition) +- [improvement] CASSANDRA-19180: Support reloading keystore in cassandra-java-driver + ### 4.18.0 - [improvement] PR 1689: Add support for publishing percentile time series for the histogram metrics (nparaddi-walmart) From cbdde2878786fa6c4077a21352cbe738875f2106 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 20 May 2024 09:57:23 -0500 Subject: [PATCH 316/395] [maven-release-plugin] prepare release 4.18.1 --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 72e00c48355..87920ed984a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-bom pom @@ -33,42 +33,42 @@ org.apache.cassandra java-driver-core - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-core-shaded - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-mapper-processor - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-mapper-runtime - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-query-builder - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-test-infra - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-metrics-micrometer - 4.18.1-SNAPSHOT + 4.18.1 org.apache.cassandra java-driver-metrics-microprofile - 4.18.1-SNAPSHOT + 4.18.1 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index c2768c3a642..93a74696c1b 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index c54c6b8c642..59465763c71 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index 8c4f695afdd..dc0cdfd1a43 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index 099bddba900..11a0797b3cf 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 8933d3f5f3a..8bfbeecd8b0 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 7e2d7f1b6d0..0cf0c6389ec 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.18.1-SNAPSHOT + 4.18.1 java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 5c684e90b2a..f867bcce7db 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 768327591d6..47f816bdc0d 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 95ead75ddd8..ca3a27367c5 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 1405ae0b6c2..e0e4e3fe709 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 6ba084396d1..fcbc7e1a54f 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 859a69400b9..e48be59f1c1 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index b4102b3380f..14d5d9c84ff 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1017,7 +1017,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.18.1 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index f1828b62462..eaa974030d3 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 9089d4d1019..25a8ad2f147 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1-SNAPSHOT + 4.18.1 java-driver-test-infra bundle From db4c8075e11d6dc020552d711c2a2e96dc651ad4 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 20 May 2024 09:57:26 -0500 Subject: [PATCH 317/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 18 +++++++++--------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 87920ed984a..96b7a6ceb18 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-bom pom @@ -33,42 +33,42 @@ org.apache.cassandra java-driver-core - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-core-shaded - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-mapper-processor - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-mapper-runtime - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-query-builder - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-test-infra - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-metrics-micrometer - 4.18.1 + 4.18.2-SNAPSHOT org.apache.cassandra java-driver-metrics-microprofile - 4.18.1 + 4.18.2-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 93a74696c1b..6c139aab127 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 59465763c71..33688754f1b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index dc0cdfd1a43..ee5b52958c3 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index 11a0797b3cf..fafd8c4678b 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 8bfbeecd8b0..dfc406baf43 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 0cf0c6389ec..a76cc8d2bf1 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.18.1 + 4.18.2-SNAPSHOT java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index f867bcce7db..32cabdb34a7 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 47f816bdc0d..61906f41987 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index ca3a27367c5..28483ee93ff 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index e0e4e3fe709..8ab939cbb37 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index fcbc7e1a54f..521a67f9075 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index e48be59f1c1..5947aff1bc5 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 14d5d9c84ff..082daeb3566 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1017,7 +1017,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.18.1 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index eaa974030d3..bae0e0c6ca0 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 25a8ad2f147..262627e5536 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.1 + 4.18.2-SNAPSHOT java-driver-test-infra bundle From 432e107bc6a2dda19385b7c423d2768e3a879965 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Thu, 16 May 2024 14:13:05 +0200 Subject: [PATCH 318/395] CASSANDRA-19635: Run integration tests with C* 5.x patch by Lukasz Antoniak; reviewed by Andy Tolbert, and Bret McGuire for CASSANDRA-19635 --- integration-tests/pom.xml | 3 + .../core/auth/DseProxyAuthenticationIT.java | 60 ++++++++------- .../oss/driver/core/cql/AsyncResultSetIT.java | 18 +++-- .../oss/driver/core/cql/BatchStatementIT.java | 18 +++-- .../driver/core/cql/BoundStatementCcmIT.java | 73 ++++++++++--------- .../core/cql/ExecutionInfoWarningsIT.java | 17 +++-- .../oss/driver/core/cql/PagingStateIT.java | 14 ++-- .../driver/core/cql/PerRequestKeyspaceIT.java | 60 ++++++++------- .../core/cql/PreparedStatementCachingIT.java | 49 ++++++++++--- .../reactive/DefaultReactiveResultSetIT.java | 32 ++++---- .../oss/driver/core/metadata/DescribeIT.java | 23 +++--- .../oss/driver/core/metadata/SchemaIT.java | 14 ++++ .../type/codec/registry/CodecRegistryIT.java | 63 ++++++++-------- .../datastax/oss/driver/mapper/DeleteIT.java | 9 +-- .../oss/driver/mapper/DeleteReactiveIT.java | 18 +++-- .../driver/mapper/EntityPolymorphismIT.java | 38 ++++++---- .../oss/driver/mapper/ImmutableEntityIT.java | 14 +++- .../oss/driver/mapper/InventoryITBase.java | 8 +- .../oss/driver/mapper/NestedUdtIT.java | 48 ++++++------ .../mapper/SelectCustomWhereClauseIT.java | 14 +++- .../oss/driver/mapper/SelectReactiveIT.java | 14 +++- .../datastax/oss/driver/mapper/UpdateIT.java | 21 ++++-- .../osgi/support/CcmStagedReactor.java | 2 +- pom.xml | 11 +++ .../driver/api/testinfra/ccm/BaseCcmRule.java | 4 +- .../driver/api/testinfra/ccm/CcmBridge.java | 20 +++-- .../ccm/SchemaChangeSynchronizer.java | 42 +++++++++++ .../api/testinfra/session/SessionRule.java | 6 +- 28 files changed, 455 insertions(+), 258 deletions(-) create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/SchemaChangeSynchronizer.java diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 32cabdb34a7..d1b0a736bb0 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -242,6 +242,8 @@ 8 ${project.build.directory}/failsafe-reports/failsafe-summary-parallelized.xml ${skipParallelizableITs} + ${blockhound.argline} + ${testing.jvm}/bin/java @@ -253,6 +255,7 @@ com.datastax.oss.driver.categories.ParallelizableTests, com.datastax.oss.driver.categories.IsolatedTests ${project.build.directory}/failsafe-reports/failsafe-summary-serial.xml ${skipSerialITs} + ${blockhound.argline} ${testing.jvm}/bin/java diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java index 126a110da1a..a3f1c04afc0 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/DseProxyAuthenticationIT.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.cql.ResultSet; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.servererrors.UnauthorizedException; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; @@ -57,33 +58,38 @@ public static void addUsers() { @Before public void setupRoles() { - try (CqlSession session = ads.newKeyTabSession()) { - session.execute( - "CREATE ROLE IF NOT EXISTS alice WITH PASSWORD = 'fakePasswordForAlice' AND LOGIN = FALSE"); - session.execute( - "CREATE ROLE IF NOT EXISTS ben WITH PASSWORD = 'fakePasswordForBen' AND LOGIN = TRUE"); - session.execute("CREATE ROLE IF NOT EXISTS 'bob@DATASTAX.COM' WITH LOGIN = TRUE"); - session.execute( - "CREATE ROLE IF NOT EXISTS 'charlie@DATASTAX.COM' WITH PASSWORD = 'fakePasswordForCharlie' AND LOGIN = TRUE"); - session.execute( - "CREATE ROLE IF NOT EXISTS steve WITH PASSWORD = 'fakePasswordForSteve' AND LOGIN = TRUE"); - session.execute( - "CREATE KEYSPACE IF NOT EXISTS aliceks WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':'1'}"); - session.execute( - "CREATE TABLE IF NOT EXISTS aliceks.alicetable (key text PRIMARY KEY, value text)"); - session.execute("INSERT INTO aliceks.alicetable (key, value) VALUES ('hello', 'world')"); - session.execute("GRANT ALL ON KEYSPACE aliceks TO alice"); - session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'ben'"); - session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'bob@DATASTAX.COM'"); - session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'steve'"); - session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'charlie@DATASTAX.COM'"); - session.execute("GRANT PROXY.LOGIN ON ROLE 'alice' TO 'ben'"); - session.execute("GRANT PROXY.LOGIN ON ROLE 'alice' TO 'bob@DATASTAX.COM'"); - session.execute("GRANT PROXY.EXECUTE ON ROLE 'alice' TO 'steve'"); - session.execute("GRANT PROXY.EXECUTE ON ROLE 'alice' TO 'charlie@DATASTAX.COM'"); - // ben and bob are allowed to login as alice, but not execute as alice. - // charlie and steve are allowed to execute as alice, but not login as alice. - } + SchemaChangeSynchronizer.withLock( + () -> { + try (CqlSession session = ads.newKeyTabSession()) { + session.execute( + "CREATE ROLE IF NOT EXISTS alice WITH PASSWORD = 'fakePasswordForAlice' AND LOGIN = FALSE"); + session.execute( + "CREATE ROLE IF NOT EXISTS ben WITH PASSWORD = 'fakePasswordForBen' AND LOGIN = TRUE"); + session.execute("CREATE ROLE IF NOT EXISTS 'bob@DATASTAX.COM' WITH LOGIN = TRUE"); + session.execute( + "CREATE ROLE IF NOT EXISTS 'charlie@DATASTAX.COM' WITH PASSWORD = 'fakePasswordForCharlie' AND LOGIN = TRUE"); + session.execute( + "CREATE ROLE IF NOT EXISTS steve WITH PASSWORD = 'fakePasswordForSteve' AND LOGIN = TRUE"); + session.execute( + "CREATE KEYSPACE IF NOT EXISTS aliceks WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':'1'}"); + session.execute( + "CREATE TABLE IF NOT EXISTS aliceks.alicetable (key text PRIMARY KEY, value text)"); + session.execute( + "INSERT INTO aliceks.alicetable (key, value) VALUES ('hello', 'world')"); + session.execute("GRANT ALL ON KEYSPACE aliceks TO alice"); + session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'ben'"); + session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'bob@DATASTAX.COM'"); + session.execute("GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'steve'"); + session.execute( + "GRANT EXECUTE ON ALL AUTHENTICATION SCHEMES TO 'charlie@DATASTAX.COM'"); + session.execute("GRANT PROXY.LOGIN ON ROLE 'alice' TO 'ben'"); + session.execute("GRANT PROXY.LOGIN ON ROLE 'alice' TO 'bob@DATASTAX.COM'"); + session.execute("GRANT PROXY.EXECUTE ON ROLE 'alice' TO 'steve'"); + session.execute("GRANT PROXY.EXECUTE ON ROLE 'alice' TO 'charlie@DATASTAX.COM'"); + // ben and bob are allowed to login as alice, but not execute as alice. + // charlie and steve are allowed to execute as alice, but not login as alice. + } + }); } /** * Validates that a connection may be successfully made as user 'alice' using the credentials of a diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/AsyncResultSetIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/AsyncResultSetIT.java index 2d01043b46a..e109c28525e 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/AsyncResultSetIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/AsyncResultSetIT.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -67,13 +68,16 @@ public class AsyncResultSetIT { @BeforeClass public static void setupSchema() { // create table and load data across two partitions so we can test paging across tokens. - SESSION_RULE - .session() - .execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS test (k0 text, k1 int, v int, PRIMARY KEY(k0, k1))") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); + SchemaChangeSynchronizer.withLock( + () -> { + SESSION_RULE + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test (k0 text, k1 int, v int, PRIMARY KEY(k0, k1))") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + }); PreparedStatement prepared = SESSION_RULE.session().prepare("INSERT INTO test (k0, k1, v) VALUES (?, ?, ?)"); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java index 04e5798be5a..8b652638729 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BatchStatementIT.java @@ -34,6 +34,7 @@ import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -72,13 +73,16 @@ public void createTable() { "CREATE TABLE counter3 (k0 text PRIMARY KEY, c counter)", }; - for (String schemaStatement : schemaStatements) { - sessionRule - .session() - .execute( - SimpleStatement.newInstance(schemaStatement) - .setExecutionProfile(sessionRule.slowProfile())); - } + SchemaChangeSynchronizer.withLock( + () -> { + for (String schemaStatement : schemaStatements) { + sessionRule + .session() + .execute( + SimpleStatement.newInstance(schemaStatement) + .setExecutionProfile(sessionRule.slowProfile())); + } + }); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java index 79156fcce50..9e4b62cd230 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/BoundStatementCcmIT.java @@ -40,6 +40,7 @@ import com.datastax.oss.driver.api.core.metadata.token.Token; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -94,40 +95,44 @@ public class BoundStatementCcmIT { @Before public void setupSchema() { // table where every column forms the primary key. - sessionRule - .session() - .execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS test (k text, v int, PRIMARY KEY(k, v))") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); - for (int i = 0; i < 100; i++) { - sessionRule - .session() - .execute( - SimpleStatement.builder("INSERT INTO test (k, v) VALUES (?, ?)") - .addPositionalValues(KEY, i) - .build()); - } - - // table with simple primary key, single cell. - sessionRule - .session() - .execute( - SimpleStatement.builder("CREATE TABLE IF NOT EXISTS test2 (k text primary key, v0 int)") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); - - // table with composite partition key - sessionRule - .session() - .execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS test3 " - + "(pk1 int, pk2 int, v int, " - + "PRIMARY KEY ((pk1, pk2)))") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); + SchemaChangeSynchronizer.withLock( + () -> { + sessionRule + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test (k text, v int, PRIMARY KEY(k, v))") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + for (int i = 0; i < 100; i++) { + sessionRule + .session() + .execute( + SimpleStatement.builder("INSERT INTO test (k, v) VALUES (?, ?)") + .addPositionalValues(KEY, i) + .build()); + } + + // table with simple primary key, single cell. + sessionRule + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test2 (k text primary key, v0 int)") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + + // table with composite partition key + sessionRule + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test3 " + + "(pk1 int, pk2 int, v int, " + + "PRIMARY KEY ((pk1, pk2)))") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + }); } @Test diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java index 5907206d11a..edee9723a38 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/ExecutionInfoWarningsIT.java @@ -33,6 +33,7 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -88,12 +89,16 @@ public class ExecutionInfoWarningsIT { @Before public void createSchema() { // table with simple primary key, single cell. - sessionRule - .session() - .execute( - SimpleStatement.builder("CREATE TABLE IF NOT EXISTS test (k int primary key, v text)") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); + SchemaChangeSynchronizer.withLock( + () -> { + sessionRule + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test (k int primary key, v text)") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + }); for (int i = 0; i < 100; i++) { sessionRule .session() diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java index dcd801f19a4..6d33f35238a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PagingStateIT.java @@ -30,6 +30,7 @@ import com.datastax.oss.driver.api.core.type.codec.MappingCodec; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -55,11 +56,14 @@ public class PagingStateIT { @Before public void setupSchema() { CqlSession session = SESSION_RULE.session(); - session.execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS foo (k int, cc int, v int, PRIMARY KEY(k, cc))") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); + SchemaChangeSynchronizer.withLock( + () -> { + session.execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS foo (k int, cc int, v int, PRIMARY KEY(k, cc))") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + }); for (int i = 0; i < 20; i++) { session.execute( SimpleStatement.newInstance("INSERT INTO foo (k, cc, v) VALUES (1, ?, ?)", i, i)); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java index 2b418e76f75..9eb883144db 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PerRequestKeyspaceIT.java @@ -31,6 +31,7 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -67,13 +68,16 @@ public class PerRequestKeyspaceIT { @Before public void setupSchema() { - sessionRule - .session() - .execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS foo (k text, cc int, v int, PRIMARY KEY(k, cc))") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); + SchemaChangeSynchronizer.withLock( + () -> { + sessionRule + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS foo (k text, cc int, v int, PRIMARY KEY(k, cc))") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + }); } @Test @@ -220,27 +224,31 @@ public void should_prepare_statement_with_keyspace() { @BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0") public void should_reprepare_statement_with_keyspace_on_the_fly() { // Create a separate session because we don't want it to have a default keyspace - try (CqlSession session = SessionUtils.newSession(ccmRule)) { - executeDdl( - session, - String.format( - "CREATE TABLE IF NOT EXISTS %s.bar (k int primary key)", sessionRule.keyspace())); - PreparedStatement pst = - session.prepare( - SimpleStatement.newInstance("SELECT * FROM bar WHERE k=?") - .setKeyspace(sessionRule.keyspace())); + SchemaChangeSynchronizer.withLock( + () -> { + try (CqlSession session = SessionUtils.newSession(ccmRule)) { + executeDdl( + session, + String.format( + "CREATE TABLE IF NOT EXISTS %s.bar (k int primary key)", + sessionRule.keyspace())); + PreparedStatement pst = + session.prepare( + SimpleStatement.newInstance("SELECT * FROM bar WHERE k=?") + .setKeyspace(sessionRule.keyspace())); - // Drop and re-create the table to invalidate the prepared statement server side - executeDdl(session, String.format("DROP TABLE %s.bar", sessionRule.keyspace())); - executeDdl( - session, - String.format("CREATE TABLE %s.bar (k int primary key)", sessionRule.keyspace())); - assertThat(preparedStatementExistsOnServer(session, pst.getId())).isFalse(); + // Drop and re-create the table to invalidate the prepared statement server side + executeDdl(session, String.format("DROP TABLE %s.bar", sessionRule.keyspace())); + executeDdl( + session, + String.format("CREATE TABLE %s.bar (k int primary key)", sessionRule.keyspace())); + assertThat(preparedStatementExistsOnServer(session, pst.getId())).isFalse(); - // This will re-prepare on the fly - session.execute(pst.bind(0)); - assertThat(preparedStatementExistsOnServer(session, pst.getId())).isTrue(); - } + // This will re-prepare on the fly + session.execute(pst.bind(0)); + assertThat(preparedStatementExistsOnServer(session, pst.getId())).isTrue(); + } + }); } private void executeDdl(CqlSession session, String query) { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java index 92c6fd8a12e..05ac3bd0e92 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java @@ -30,6 +30,7 @@ import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; import com.datastax.oss.driver.api.core.session.SessionBuilder; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.IsolatedTests; @@ -305,12 +306,19 @@ private void invalidationTestInner( @Test public void should_invalidate_cache_entry_on_basic_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestBasic, ImmutableSet.of("test_type_2")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationResultSetTest(setupCacheEntryTestBasic, ImmutableSet.of("test_type_2")); + }); } @Test public void should_invalidate_cache_entry_on_basic_udt_change_variable_defs() { - invalidationVariableDefsTest(setupCacheEntryTestBasic, false, ImmutableSet.of("test_type_2")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationVariableDefsTest( + setupCacheEntryTestBasic, false, ImmutableSet.of("test_type_2")); + }); } Consumer setupCacheEntryTestCollection = @@ -325,13 +333,19 @@ public void should_invalidate_cache_entry_on_basic_udt_change_variable_defs() { @Test public void should_invalidate_cache_entry_on_collection_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestCollection, ImmutableSet.of("test_type_2")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationResultSetTest(setupCacheEntryTestCollection, ImmutableSet.of("test_type_2")); + }); } @Test public void should_invalidate_cache_entry_on_collection_udt_change_variable_defs() { - invalidationVariableDefsTest( - setupCacheEntryTestCollection, true, ImmutableSet.of("test_type_2")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationVariableDefsTest( + setupCacheEntryTestCollection, true, ImmutableSet.of("test_type_2")); + }); } Consumer setupCacheEntryTestTuple = @@ -346,12 +360,19 @@ public void should_invalidate_cache_entry_on_collection_udt_change_variable_defs @Test public void should_invalidate_cache_entry_on_tuple_udt_change_result_set() { - invalidationResultSetTest(setupCacheEntryTestTuple, ImmutableSet.of("test_type_2")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationResultSetTest(setupCacheEntryTestTuple, ImmutableSet.of("test_type_2")); + }); } @Test public void should_invalidate_cache_entry_on_tuple_udt_change_variable_defs() { - invalidationVariableDefsTest(setupCacheEntryTestTuple, false, ImmutableSet.of("test_type_2")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationVariableDefsTest( + setupCacheEntryTestTuple, false, ImmutableSet.of("test_type_2")); + }); } Consumer setupCacheEntryTestNested = @@ -366,14 +387,20 @@ public void should_invalidate_cache_entry_on_tuple_udt_change_variable_defs() { @Test public void should_invalidate_cache_entry_on_nested_udt_change_result_set() { - invalidationResultSetTest( - setupCacheEntryTestNested, ImmutableSet.of("test_type_2", "test_type_4")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationResultSetTest( + setupCacheEntryTestNested, ImmutableSet.of("test_type_2", "test_type_4")); + }); } @Test public void should_invalidate_cache_entry_on_nested_udt_change_variable_defs() { - invalidationVariableDefsTest( - setupCacheEntryTestNested, false, ImmutableSet.of("test_type_2", "test_type_4")); + SchemaChangeSynchronizer.withLock( + () -> { + invalidationVariableDefsTest( + setupCacheEntryTestNested, false, ImmutableSet.of("test_type_2", "test_type_4")); + }); } /* ========================= Infrastructure copied from PreparedStatementIT ========================= */ diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/reactive/DefaultReactiveResultSetIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/reactive/DefaultReactiveResultSetIT.java index cfb6a56fac2..c00cf064e51 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/reactive/DefaultReactiveResultSetIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/reactive/DefaultReactiveResultSetIT.java @@ -32,6 +32,7 @@ import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.cql.EmptyColumnDefinitions; @@ -64,20 +65,23 @@ public class DefaultReactiveResultSetIT { @BeforeClass public static void initialize() { CqlSession session = sessionRule.session(); - session.execute("DROP TABLE IF EXISTS test_reactive_read"); - session.execute("DROP TABLE IF EXISTS test_reactive_write"); - session.checkSchemaAgreement(); - session.execute( - SimpleStatement.builder( - "CREATE TABLE test_reactive_read (pk int, cc int, v int, PRIMARY KEY ((pk), cc))") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); - session.execute( - SimpleStatement.builder( - "CREATE TABLE test_reactive_write (pk int, cc int, v int, PRIMARY KEY ((pk), cc))") - .setExecutionProfile(sessionRule.slowProfile()) - .build()); - session.checkSchemaAgreement(); + SchemaChangeSynchronizer.withLock( + () -> { + session.execute("DROP TABLE IF EXISTS test_reactive_read"); + session.execute("DROP TABLE IF EXISTS test_reactive_write"); + session.checkSchemaAgreement(); + session.execute( + SimpleStatement.builder( + "CREATE TABLE test_reactive_read (pk int, cc int, v int, PRIMARY KEY ((pk), cc))") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + session.execute( + SimpleStatement.builder( + "CREATE TABLE test_reactive_write (pk int, cc int, v int, PRIMARY KEY ((pk), cc))") + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + session.checkSchemaAgreement(); + }); for (int i = 0; i < 1000; i++) { session.execute( SimpleStatement.builder("INSERT INTO test_reactive_read (pk, cc, v) VALUES (0, ?, ?)") diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java index d8239f31872..9fbf5e355eb 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java @@ -28,6 +28,7 @@ import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -224,15 +225,17 @@ private static String getScriptContents() { private static void setupDatabase() { List statements = STATEMENT_SPLITTER.splitToList(scriptContents); - - // Skip the first statement (CREATE KEYSPACE), we already have a keyspace - for (int i = 1; i < statements.size(); i++) { - String statement = statements.get(i); - try { - SESSION_RULE.session().execute(statement); - } catch (Exception e) { - fail("Error executing statement %s (%s)", statement, e); - } - } + SchemaChangeSynchronizer.withLock( + () -> { + // Skip the first statement (CREATE KEYSPACE), we already have a keyspace + for (int i = 1; i < statements.size(); i++) { + String statement = statements.get(i); + try { + SESSION_RULE.session().execute(statement); + } catch (Exception e) { + fail("Error executing statement %s (%s)", statement, e); + } + } + }); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index 6495b451df7..805b2d970cc 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -278,6 +278,20 @@ public void should_get_virtual_metadata() { + " total bigint,\n" + " unit text,\n" + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" + + "); */", + // Cassandra 5.0 + "/* VIRTUAL TABLE system_views.sstable_tasks (\n" + + " keyspace_name text,\n" + + " table_name text,\n" + + " task_id timeuuid,\n" + + " completion_ratio double,\n" + + " kind text,\n" + + " progress bigint,\n" + + " sstables int,\n" + + " target_directory text,\n" + + " total bigint,\n" + + " unit text,\n" + + " PRIMARY KEY (keyspace_name, table_name, task_id)\n" + "); */"); // ColumnMetadata is as expected ColumnMetadata cm = tm.getColumn("progress").get(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java index 2f9a0872b37..74472e8bab9 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/type/codec/registry/CodecRegistryIT.java @@ -38,6 +38,7 @@ import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -78,35 +79,39 @@ public class CodecRegistryIT { @BeforeClass public static void createSchema() { - // table with simple primary key, single cell. - SESSION_RULE - .session() - .execute( - SimpleStatement.builder("CREATE TABLE IF NOT EXISTS test (k text primary key, v int)") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); - // table with map value - SESSION_RULE - .session() - .execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS test2 (k0 text, k1 int, v map, primary key (k0, k1))") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); - // table with UDT - SESSION_RULE - .session() - .execute( - SimpleStatement.builder("CREATE TYPE IF NOT EXISTS coordinates (x int, y int)") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); - SESSION_RULE - .session() - .execute( - SimpleStatement.builder( - "CREATE TABLE IF NOT EXISTS test3 (k0 text, k1 int, v map>, primary key (k0, k1))") - .setExecutionProfile(SESSION_RULE.slowProfile()) - .build()); + SchemaChangeSynchronizer.withLock( + () -> { + // table with simple primary key, single cell. + SESSION_RULE + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test (k text primary key, v int)") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + // table with map value + SESSION_RULE + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test2 (k0 text, k1 int, v map, primary key (k0, k1))") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + // table with UDT + SESSION_RULE + .session() + .execute( + SimpleStatement.builder("CREATE TYPE IF NOT EXISTS coordinates (x int, y int)") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + SESSION_RULE + .session() + .execute( + SimpleStatement.builder( + "CREATE TABLE IF NOT EXISTS test3 (k0 text, k1 int, v map>, primary key (k0, k1))") + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + }); } // A simple codec that allows float values to be used for cassandra int column type. diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java index 8918e6020ec..0acdbeae53a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java @@ -38,11 +38,10 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; -import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -51,18 +50,18 @@ import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@Category(ParallelizableTests.class) +// Do not run LWT tests in parallel because they may interfere. Tests operate on the same row. @BackendRequirement( type = BackendType.CASSANDRA, minInclusive = "3.0", description = ">= in WHERE clause not supported in legacy versions") public class DeleteIT extends InventoryITBase { - private static final CcmRule CCM_RULE = CcmRule.getInstance(); + private static CustomCcmRule CCM_RULE = + CustomCcmRule.builder().withCassandraConfiguration("enable_sasi_indexes", "true").build(); private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java index 928fbd6fb8a..3a418c73653 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java @@ -24,6 +24,7 @@ import com.datastax.dse.driver.api.mapper.reactive.MappedReactiveResultSet; import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.mapper.annotations.Dao; import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; @@ -34,28 +35,35 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; -import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionRule; -import com.datastax.oss.driver.categories.ParallelizableTests; import io.reactivex.Flowable; import java.util.UUID; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -@Category(ParallelizableTests.class) +// Do not run LWT tests in parallel because they may interfere. Tests operate on the same row. public class DeleteReactiveIT extends InventoryITBase { - private static CcmRule ccmRule = CcmRule.getInstance(); + private static CustomCcmRule ccmRule = configureCcm(CustomCcmRule.builder()).build(); private static SessionRule sessionRule = SessionRule.builder(ccmRule).build(); @ClassRule public static TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); + private static CustomCcmRule.Builder configureCcm(CustomCcmRule.Builder builder) { + if (!CcmBridge.DSE_ENABLEMENT + && CcmBridge.VERSION.nextStable().compareTo(Version.V4_0_0) >= 0) { + builder.withCassandraConfiguration("enable_sasi_indexes", true); + } + return builder; + } + private static DseProductDao dao; @BeforeClass diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/EntityPolymorphismIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/EntityPolymorphismIT.java index 08b806af684..3e532e97c00 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/EntityPolymorphismIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/EntityPolymorphismIT.java @@ -47,6 +47,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Update; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; @@ -83,22 +84,27 @@ public class EntityPolymorphismIT { @BeforeClass public static void setup() { CqlSession session = SESSION_RULE.session(); - for (String query : - ImmutableList.of( - "CREATE TYPE point2d (\"X\" int, \"Y\" int)", - "CREATE TYPE point3d (\"X\" int, \"Y\" int, \"Z\" int)", - "CREATE TABLE circles (circle_id uuid PRIMARY KEY, center2d frozen, radius " - + "double, tags set)", - "CREATE TABLE rectangles (rect_id uuid PRIMARY KEY, bottom_left frozen, top_right frozen, tags set)", - "CREATE TABLE squares (square_id uuid PRIMARY KEY, bottom_left frozen, top_right frozen, tags set)", - "CREATE TABLE spheres (sphere_id uuid PRIMARY KEY, center3d frozen, radius " - + "double, tags set)", - "CREATE TABLE devices (device_id uuid PRIMARY KEY, name text)", - "CREATE TABLE tracked_devices (device_id uuid PRIMARY KEY, name text, location text)", - "CREATE TABLE simple_devices (id uuid PRIMARY KEY, in_use boolean)")) { - session.execute( - SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); - } + SchemaChangeSynchronizer.withLock( + () -> { + for (String query : + ImmutableList.of( + "CREATE TYPE point2d (\"X\" int, \"Y\" int)", + "CREATE TYPE point3d (\"X\" int, \"Y\" int, \"Z\" int)", + "CREATE TABLE circles (circle_id uuid PRIMARY KEY, center2d frozen, radius " + + "double, tags set)", + "CREATE TABLE rectangles (rect_id uuid PRIMARY KEY, bottom_left frozen, top_right frozen, tags set)", + "CREATE TABLE squares (square_id uuid PRIMARY KEY, bottom_left frozen, top_right frozen, tags set)", + "CREATE TABLE spheres (sphere_id uuid PRIMARY KEY, center3d frozen, radius " + + "double, tags set)", + "CREATE TABLE devices (device_id uuid PRIMARY KEY, name text)", + "CREATE TABLE tracked_devices (device_id uuid PRIMARY KEY, name text, location text)", + "CREATE TABLE simple_devices (id uuid PRIMARY KEY, in_use boolean)")) { + session.execute( + SimpleStatement.builder(query) + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + } + }); mapper = new EntityPolymorphismIT_TestMapperBuilder(session).build(); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java index 555b02c0283..bdfe92a23f9 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/ImmutableEntityIT.java @@ -42,6 +42,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import java.util.Objects; @@ -70,10 +71,15 @@ public class ImmutableEntityIT extends InventoryITBase { public static void setup() { CqlSession session = SESSION_RULE.session(); - for (String query : createStatements(CCM_RULE)) { - session.execute( - SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); - } + SchemaChangeSynchronizer.withLock( + () -> { + for (String query : createStatements(CCM_RULE)) { + session.execute( + SimpleStatement.builder(query) + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + } + }); UserDefinedType dimensions2d = session diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java index 75ceee1f2a5..2be025b3739 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java @@ -22,7 +22,7 @@ import com.datastax.oss.driver.api.mapper.annotations.ClusteringColumn; import com.datastax.oss.driver.api.mapper.annotations.Entity; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; -import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.BaseCcmRule; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import java.util.List; import java.util.Objects; @@ -58,7 +58,7 @@ public abstract class InventoryITBase { protected static ProductSale MP3_DOWNLOAD_SALE_1 = new ProductSale(MP3_DOWNLOAD.getId(), DATE_3, 7, Uuids.startOf(915192000), 0.99, 12); - protected static List createStatements(CcmRule ccmRule) { + protected static List createStatements(BaseCcmRule ccmRule) { ImmutableList.Builder builder = ImmutableList.builder() .add( @@ -92,13 +92,13 @@ protected static List createStatements(CcmRule ccmRule) { private static final Version MINIMUM_SASI_VERSION = Version.parse("3.4.0"); private static final Version BROKEN_SASI_VERSION = Version.parse("6.8.0"); - protected static boolean isSasiBroken(CcmRule ccmRule) { + protected static boolean isSasiBroken(BaseCcmRule ccmRule) { Optional dseVersion = ccmRule.getDseVersion(); // creating SASI indexes is broken in DSE 6.8.0 return dseVersion.isPresent() && dseVersion.get().compareTo(BROKEN_SASI_VERSION) == 0; } - protected static boolean supportsSASI(CcmRule ccmRule) { + protected static boolean supportsSASI(BaseCcmRule ccmRule) { return ccmRule.getCassandraVersion().compareTo(MINIMUM_SASI_VERSION) >= 0; } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java index 43d41a9c93b..d61b6f6e628 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/NestedUdtIT.java @@ -41,6 +41,7 @@ import com.datastax.oss.driver.api.mapper.annotations.SetEntity; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -119,27 +120,32 @@ public class NestedUdtIT { public static void setup() { CqlSession session = SESSION_RULE.session(); - for (String query : - ImmutableList.of( - "CREATE TYPE type1(s1 text, s2 text)", - "CREATE TYPE type2(i1 int, i2 int)", - "CREATE TYPE type1_partial(s1 text)", - "CREATE TYPE type2_partial(i1 int)", - "CREATE TABLE container(id uuid PRIMARY KEY, " - + "list frozen>, " - + "map1 frozen>>, " - + "map2 frozen>>>," - + "map3 frozen>>>" - + ")", - "CREATE TABLE container_partial(id uuid PRIMARY KEY, " - + "list frozen>, " - + "map1 frozen>>, " - + "map2 frozen>>>," - + "map3 frozen>>>" - + ")")) { - session.execute( - SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); - } + SchemaChangeSynchronizer.withLock( + () -> { + for (String query : + ImmutableList.of( + "CREATE TYPE type1(s1 text, s2 text)", + "CREATE TYPE type2(i1 int, i2 int)", + "CREATE TYPE type1_partial(s1 text)", + "CREATE TYPE type2_partial(i1 int)", + "CREATE TABLE container(id uuid PRIMARY KEY, " + + "list frozen>, " + + "map1 frozen>>, " + + "map2 frozen>>>," + + "map3 frozen>>>" + + ")", + "CREATE TABLE container_partial(id uuid PRIMARY KEY, " + + "list frozen>, " + + "map1 frozen>>, " + + "map2 frozen>>>," + + "map3 frozen>>>" + + ")")) { + session.execute( + SimpleStatement.builder(query) + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + } + }); UserDefinedType type1Partial = session diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java index e2a0f1e9987..3df1ccd21a7 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java @@ -35,6 +35,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Mapper; import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; @@ -72,10 +73,15 @@ public static void setup() { CqlSession session = SESSION_RULE.session(); - for (String query : createStatements(CCM_RULE)) { - session.execute( - SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); - } + SchemaChangeSynchronizer.withLock( + () -> { + for (String query : createStatements(CCM_RULE)) { + session.execute( + SimpleStatement.builder(query) + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + } + }); InventoryMapper inventoryMapper = new SelectCustomWhereClauseIT_InventoryMapperBuilder(session).build(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectReactiveIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectReactiveIT.java index 0ea07e552f7..79e4d2b33ea 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectReactiveIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectReactiveIT.java @@ -34,6 +34,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Select; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import io.reactivex.Flowable; @@ -61,10 +62,15 @@ public class SelectReactiveIT extends InventoryITBase { public static void setup() { CqlSession session = sessionRule.session(); - for (String query : createStatements(ccmRule)) { - session.execute( - SimpleStatement.builder(query).setExecutionProfile(sessionRule.slowProfile()).build()); - } + SchemaChangeSynchronizer.withLock( + () -> { + for (String query : createStatements(ccmRule)) { + session.execute( + SimpleStatement.builder(query) + .setExecutionProfile(sessionRule.slowProfile()) + .build()); + } + }); DseInventoryMapper inventoryMapper = new SelectReactiveIT_DseInventoryMapperBuilder(session).build(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java index 27b4d6e9d90..3fac733c900 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/UpdateIT.java @@ -37,6 +37,7 @@ import com.datastax.oss.driver.api.mapper.annotations.Update; import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; @@ -65,14 +66,18 @@ public class UpdateIT extends InventoryITBase { @BeforeClass public static void setup() { CqlSession session = SESSION_RULE.session(); - - for (String query : createStatements(CCM_RULE)) { - session.execute( - SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build()); - } - session.execute( - SimpleStatement.newInstance("CREATE TABLE only_p_k(id uuid PRIMARY KEY)") - .setExecutionProfile(SESSION_RULE.slowProfile())); + SchemaChangeSynchronizer.withLock( + () -> { + for (String query : createStatements(CCM_RULE)) { + session.execute( + SimpleStatement.builder(query) + .setExecutionProfile(SESSION_RULE.slowProfile()) + .build()); + } + session.execute( + SimpleStatement.newInstance("CREATE TABLE only_p_k(id uuid PRIMARY KEY)") + .setExecutionProfile(SESSION_RULE.slowProfile())); + }); inventoryMapper = new UpdateIT_InventoryMapperBuilder(session).build(); dao = inventoryMapper.productDao(SESSION_RULE.keyspace()); diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java index 8a520488e5c..8b140930870 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java @@ -81,7 +81,7 @@ public synchronized void afterSuite() { if (running) { LOGGER.info("Stopping CCM"); CCM_BRIDGE.stop(); - CCM_BRIDGE.remove(); + CCM_BRIDGE.close(); running = false; LOGGER.info("CCM stopped"); } diff --git a/pom.xml b/pom.xml index 082daeb3566..94311719e5f 100644 --- a/pom.xml +++ b/pom.xml @@ -991,6 +991,17 @@ limitations under the License.]]> [11,) + + + test-jdk-14 + + [14,) + + + + -XX:+AllowRedefinitionToAddDeleteMethods + + test-jdk-17 diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java index b8b684ee5b2..65210acd2a2 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java @@ -38,7 +38,7 @@ public abstract class BaseCcmRule extends CassandraResourceRule { new Thread( () -> { try { - ccmBridge.remove(); + ccmBridge.close(); } catch (Exception e) { // silently remove as may have already been removed. } @@ -53,7 +53,7 @@ protected void before() { @Override protected void after() { - ccmBridge.remove(); + ccmBridge.close(); } @Override diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java index 98739e7715d..995513e3919 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java @@ -197,9 +197,10 @@ public Version getCassandraVersion() { } private String getCcmVersionString(Version version) { - // for 4.0 pre-releases, the CCM version string needs to be "4.0-alpha1" or "4.0-alpha2" - // Version.toString() always adds a patch value, even if it's not specified when parsing. - if (version.getMajor() == 4 + // for 4.0 or 5.0 pre-releases, the CCM version string needs to be "4.0-alpha1", "4.0-alpha2" or + // "5.0-beta1" Version.toString() always adds a patch value, even if it's not specified when + // parsing. + if (version.getMajor() >= 4 && version.getMinor() == 0 && version.getPatch() == 0 && version.getPreReleaseLabels() != null) { @@ -292,8 +293,7 @@ public void reloadCore(int node, String keyspace, String table, boolean reindex) public void start() { if (started.compareAndSet(false, true)) { List cmdAndArgs = Lists.newArrayList("start", jvmArgs, "--wait-for-binary-proto"); - overrideJvmVersionForDseWorkloads() - .ifPresent(jvmVersion -> cmdAndArgs.add(String.format("--jvm_version=%d", jvmVersion))); + updateJvmVersion(cmdAndArgs); try { execute(cmdAndArgs.toArray(new String[0])); } catch (RuntimeException re) { @@ -324,9 +324,13 @@ public void resume(int n) { public void start(int n) { List cmdAndArgs = Lists.newArrayList("node" + n, "start"); + updateJvmVersion(cmdAndArgs); + execute(cmdAndArgs.toArray(new String[0])); + } + + private void updateJvmVersion(List cmdAndArgs) { overrideJvmVersionForDseWorkloads() .ifPresent(jvmVersion -> cmdAndArgs.add(String.format("--jvm_version=%d", jvmVersion))); - execute(cmdAndArgs.toArray(new String[0])); } public void stop(int n) { @@ -423,7 +427,9 @@ protected void processLine(String line, int logLevel) { @Override public void close() { - remove(); + if (created.compareAndSet(true, false)) { + remove(); + } } /** diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/SchemaChangeSynchronizer.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/SchemaChangeSynchronizer.java new file mode 100644 index 00000000000..093d1d3f9f9 --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/SchemaChangeSynchronizer.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.ccm; + +import java.util.concurrent.Semaphore; + +/** + * Running multiple parallel integration tests may fail due to query timeout when trying to apply + * several schema changes at once. Limit concurrently executed DDLs to 5. + */ +public class SchemaChangeSynchronizer { + private static final Semaphore lock = new Semaphore(5); + + public static void withLock(Runnable callback) { + try { + lock.acquire(); + try { + callback.run(); + } finally { + lock.release(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted wile waiting to obtain DDL lock", e); + } + } +} diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java index ce3903bcfcb..5396e5c6cc6 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; import com.datastax.oss.driver.api.testinfra.ccm.BaseCcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import java.util.Objects; import java.util.Optional; @@ -195,7 +196,10 @@ protected void after() { ScriptGraphStatement.SYNC); } if (keyspace != null) { - SessionUtils.dropKeyspace(session, keyspace, slowProfile); + SchemaChangeSynchronizer.withLock( + () -> { + SessionUtils.dropKeyspace(session, keyspace, slowProfile); + }); } session.close(); } From 811acb2fe77464f679a09226a03c1995694c51b4 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Tue, 4 Jun 2024 10:45:28 +0200 Subject: [PATCH 319/395] CASSANDRA-19635: Configure Jenkins to run integration tests with C* 5.x patch by Lukasz Antoniak; reviewed by Bret McGuire for CASSANDRA-19635 --- Jenkinsfile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d38b7c63849..4f1ef95d101 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -261,7 +261,7 @@ pipeline { '3.11', // Previous Apache CassandraⓇ '4.0', // Previous Apache CassandraⓇ '4.1', // Current Apache CassandraⓇ - '5.0', // Development Apache CassandraⓇ + '5.0-beta1', // Development Apache CassandraⓇ 'dse-4.8.16', // Previous EOSL DataStax Enterprise 'dse-5.0.15', // Long Term Support DataStax Enterprise 'dse-5.1.35', // Legacy DataStax Enterprise @@ -411,14 +411,14 @@ pipeline { triggers { // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) parameterizedCron(branchPatternCron().matcher(env.BRANCH_NAME).matches() ? """ - # Every weeknight (Monday - Friday) around 2:00 AM - ### JDK8 tests against 2.1, 3.0, DSE 4.8, DSE 5.0, DSE 5.1, dse-6.0.18 and DSE 6.7 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 - ### JDK11 tests against 3.11, 4.0 and DSE 6.8 - H 2 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 - # Every weekend (Sunday) around 12:00 PM noon - ### JDK14 tests against 3.11, 4.0 and DSE 6.8 - H 12 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.0 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.14 + # Every weekend (Saturday, Sunday) around 2:00 AM + ### JDK8 tests against 2.1, 3.0, 4.0, DSE 4.8, DSE 5.0, DSE 5.1, dse-6.0.18 and DSE 6.7 + H 2 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 4.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 + # Every weeknight (Monday - Friday) around 12:00 PM noon + ### JDK11 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 + ### JDK17 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 """ : "") } @@ -452,8 +452,8 @@ pipeline { axes { axis { name 'SERVER_VERSION' - values '3.11', // Latest stable Apache CassandraⓇ - '4.1', // Development Apache CassandraⓇ + values '3.11', // Latest stable Apache CassandraⓇ + '4.1', // Development Apache CassandraⓇ 'dse-6.8.30' // Current DataStax Enterprise } axis { @@ -565,7 +565,7 @@ pipeline { '3.11', // Previous Apache CassandraⓇ '4.0', // Previous Apache CassandraⓇ '4.1', // Current Apache CassandraⓇ - '5.0', // Development Apache CassandraⓇ + '5.0-beta1', // Development Apache CassandraⓇ 'dse-4.8.16', // Previous EOSL DataStax Enterprise 'dse-5.0.15', // Last EOSL DataStax Enterprise 'dse-5.1.35', // Legacy DataStax Enterprise From 85bb4065098b887d2dda26eb14423ce4fc687045 Mon Sep 17 00:00:00 2001 From: Brad Schoening Date: Tue, 4 Jun 2024 17:30:41 -0400 Subject: [PATCH 320/395] update badge URL to org.apache.cassandra/java-driver-core --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c53c8f2db29..2a30cb68c9a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ :warning: The java-driver has recently been donated by Datastax to The Apache Software Foundation and the Apache Cassandra project. Bear with us as we move assets and coordinates. -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.datastax.oss/java-driver-core) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.cassandra/java-driver-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.cassandra/java-driver-core) *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the From d0a1e44a4415c7a0489f8c35ee9ce49e20d7bc61 Mon Sep 17 00:00:00 2001 From: Benoit Tellier Date: Sun, 22 Jan 2023 13:58:19 +0700 Subject: [PATCH 321/395] Limit calls to Conversions.resolveExecutionProfile Those repeated calls account for a non-negligible portion of my application CPU (0.6%) and can definitly be a final field so that it gets resolved only once per CqlRequestHandler. patch by Benoit Tellier; reviewed by Andy Tolbert, and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1623 --- .../ContinuousRequestHandlerBase.java | 15 +++--- .../core/graph/GraphRequestHandler.java | 15 +++--- .../driver/internal/core/cql/Conversions.java | 38 +++++++++++-- .../internal/core/cql/CqlPrepareHandler.java | 11 ++-- .../internal/core/cql/CqlRequestHandler.java | 54 +++++++------------ 5 files changed, 75 insertions(+), 58 deletions(-) diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java index 44df3b3a03d..9a7be344721 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java @@ -648,12 +648,13 @@ public void operationComplete(@NonNull Future future) { } } else { LOG.trace("[{}] Request sent on {}", logPrefix, channel); - if (scheduleSpeculativeExecution && Conversions.resolveIdempotence(statement, context)) { + if (scheduleSpeculativeExecution + && Conversions.resolveIdempotence(statement, executionProfile)) { int nextExecution = executionIndex + 1; // Note that `node` is the first node of the execution, it might not be the "slow" one // if there were retries, but in practice retries are rare. long nextDelay = - Conversions.resolveSpeculativeExecutionPolicy(statement, context) + Conversions.resolveSpeculativeExecutionPolicy(context, executionProfile) .nextExecution(node, keyspace, statement, nextExecution); if (nextDelay >= 0) { scheduleSpeculativeExecution(nextExecution, nextDelay); @@ -787,12 +788,12 @@ public void onFailure(@NonNull Throwable error) { cancelTimeout(pageTimeout); LOG.trace(String.format("[%s] Request failure", logPrefix), error); RetryVerdict verdict; - if (!Conversions.resolveIdempotence(statement, context) + if (!Conversions.resolveIdempotence(statement, executionProfile) || error instanceof FrameTooLongException) { verdict = RetryVerdict.RETHROW; } else { try { - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); verdict = retryPolicy.onRequestAbortedVerdict(statement, error, retryCount); } catch (Throwable cause) { abort( @@ -945,7 +946,7 @@ private void processRecoverableError(@NonNull CoordinatorException error) { assert lock.isHeldByCurrentThread(); NodeMetricUpdater metricUpdater = ((DefaultNode) node).getMetricUpdater(); RetryVerdict verdict; - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); if (error instanceof ReadTimeoutException) { ReadTimeoutException readTimeout = (ReadTimeoutException) error; verdict = @@ -964,7 +965,7 @@ private void processRecoverableError(@NonNull CoordinatorException error) { DefaultNodeMetric.IGNORES_ON_READ_TIMEOUT); } else if (error instanceof WriteTimeoutException) { WriteTimeoutException writeTimeout = (WriteTimeoutException) error; - if (Conversions.resolveIdempotence(statement, context)) { + if (Conversions.resolveIdempotence(statement, executionProfile)) { verdict = retryPolicy.onWriteTimeoutVerdict( statement, @@ -999,7 +1000,7 @@ private void processRecoverableError(@NonNull CoordinatorException error) { DefaultNodeMetric.IGNORES_ON_UNAVAILABLE); } else { verdict = - Conversions.resolveIdempotence(statement, context) + Conversions.resolveIdempotence(statement, executionProfile) ? retryPolicy.onErrorResponseVerdict(statement, error, retryCount) : RetryVerdict.RETHROW; updateErrorMetrics( diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java index c2298458805..702da69b855 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java @@ -557,12 +557,13 @@ public void operationComplete(Future future) { cancel(); } else { inFlightCallbacks.add(this); - if (scheduleNextExecution && Conversions.resolveIdempotence(statement, context)) { + if (scheduleNextExecution + && Conversions.resolveIdempotence(statement, executionProfile)) { int nextExecution = execution + 1; long nextDelay; try { nextDelay = - Conversions.resolveSpeculativeExecutionPolicy(statement, context) + Conversions.resolveSpeculativeExecutionPolicy(context, executionProfile) .nextExecution(node, null, statement, nextExecution); } catch (Throwable cause) { // This is a bug in the policy, but not fatal since we have at least one other @@ -678,7 +679,7 @@ private void processErrorResponse(Error errorMessage) { trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); setFinalError(statement, error, node, execution); } else { - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); RetryVerdict verdict; if (error instanceof ReadTimeoutException) { ReadTimeoutException readTimeout = (ReadTimeoutException) error; @@ -699,7 +700,7 @@ private void processErrorResponse(Error errorMessage) { } else if (error instanceof WriteTimeoutException) { WriteTimeoutException writeTimeout = (WriteTimeoutException) error; verdict = - Conversions.resolveIdempotence(statement, context) + Conversions.resolveIdempotence(statement, executionProfile) ? retryPolicy.onWriteTimeoutVerdict( statement, writeTimeout.getConsistencyLevel(), @@ -731,7 +732,7 @@ private void processErrorResponse(Error errorMessage) { DefaultNodeMetric.IGNORES_ON_UNAVAILABLE); } else { verdict = - Conversions.resolveIdempotence(statement, context) + Conversions.resolveIdempotence(statement, executionProfile) ? retryPolicy.onErrorResponseVerdict(statement, error, retryCount) : RetryVerdict.RETHROW; updateErrorMetrics( @@ -810,12 +811,12 @@ public void onFailure(Throwable error) { } LOG.trace("[{}] Request failure, processing: {}", logPrefix, error); RetryVerdict verdict; - if (!Conversions.resolveIdempotence(statement, context) + if (!Conversions.resolveIdempotence(statement, executionProfile) || error instanceof FrameTooLongException) { verdict = RetryVerdict.RETHROW; } else { try { - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); verdict = retryPolicy.onRequestAbortedVerdict(statement, error, retryCount); } catch (Throwable cause) { setFinalError( diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java index 529664c6666..ff9384b3e24 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java @@ -535,29 +535,59 @@ public static CoordinatorException toThrowable( } } + /** Use {@link #resolveIdempotence(Request, DriverExecutionProfile)} instead. */ + @Deprecated public static boolean resolveIdempotence(Request request, InternalDriverContext context) { + return resolveIdempotence(request, resolveExecutionProfile(request, context)); + } + + public static boolean resolveIdempotence( + Request request, DriverExecutionProfile executionProfile) { Boolean requestIsIdempotent = request.isIdempotent(); - DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); return (requestIsIdempotent == null) ? executionProfile.getBoolean(DefaultDriverOption.REQUEST_DEFAULT_IDEMPOTENCE) : requestIsIdempotent; } + /** Use {@link #resolveRequestTimeout(Request, DriverExecutionProfile)} instead. */ + @Deprecated public static Duration resolveRequestTimeout(Request request, InternalDriverContext context) { - DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); - return request.getTimeout() != null - ? request.getTimeout() + return resolveRequestTimeout(request, resolveExecutionProfile(request, context)); + } + + public static Duration resolveRequestTimeout( + Request request, DriverExecutionProfile executionProfile) { + Duration timeout = request.getTimeout(); + return timeout != null + ? timeout : executionProfile.getDuration(DefaultDriverOption.REQUEST_TIMEOUT); } + /** Use {@link #resolveRetryPolicy(InternalDriverContext, DriverExecutionProfile)} instead. */ + @Deprecated public static RetryPolicy resolveRetryPolicy(Request request, InternalDriverContext context) { DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); return context.getRetryPolicy(executionProfile.getName()); } + public static RetryPolicy resolveRetryPolicy( + InternalDriverContext context, DriverExecutionProfile executionProfile) { + return context.getRetryPolicy(executionProfile.getName()); + } + + /** + * Use {@link #resolveSpeculativeExecutionPolicy(InternalDriverContext, DriverExecutionProfile)} + * instead. + */ + @Deprecated public static SpeculativeExecutionPolicy resolveSpeculativeExecutionPolicy( Request request, InternalDriverContext context) { DriverExecutionProfile executionProfile = resolveExecutionProfile(request, context); return context.getSpeculativeExecutionPolicy(executionProfile.getName()); } + + public static SpeculativeExecutionPolicy resolveSpeculativeExecutionPolicy( + InternalDriverContext context, DriverExecutionProfile executionProfile) { + return context.getSpeculativeExecutionPolicy(executionProfile.getName()); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java index 6faa8eee59f..8fe1adb20b1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java @@ -92,6 +92,7 @@ public class CqlPrepareHandler implements Throttled { private final Timeout scheduledTimeout; private final RequestThrottler throttler; private final Boolean prepareOnAllNodes; + private final DriverExecutionProfile executionProfile; private volatile InitialPrepareCallback initialCallback; // The errors on the nodes that were already tried (lazily initialized on the first error). @@ -111,7 +112,7 @@ protected CqlPrepareHandler( this.initialRequest = request; this.session = session; this.context = context; - DriverExecutionProfile executionProfile = Conversions.resolveExecutionProfile(request, context); + executionProfile = Conversions.resolveExecutionProfile(request, context); this.queryPlan = context .getLoadBalancingPolicyWrapper() @@ -131,7 +132,7 @@ protected CqlPrepareHandler( }); this.timer = context.getNettyOptions().getTimer(); - Duration timeout = Conversions.resolveRequestTimeout(request, context); + Duration timeout = Conversions.resolveRequestTimeout(request, executionProfile); this.scheduledTimeout = scheduleTimeout(timeout); this.prepareOnAllNodes = executionProfile.getBoolean(DefaultDriverOption.PREPARE_ON_ALL_NODES); @@ -292,7 +293,7 @@ private CompletionStage prepareOnOtherNode(PrepareRequest request, Node no false, toPrepareMessage(request), request.getCustomPayload(), - Conversions.resolveRequestTimeout(request, context), + Conversions.resolveRequestTimeout(request, executionProfile), throttler, session.getMetricUpdater(), logPrefix); @@ -419,7 +420,7 @@ private void processErrorResponse(Error errorMessage) { } else { // Because prepare requests are known to always be idempotent, we call the retry policy // directly, without checking the flag. - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(request, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); RetryVerdict verdict = retryPolicy.onErrorResponseVerdict(request, error, retryCount); processRetryVerdict(verdict, error); } @@ -457,7 +458,7 @@ public void onFailure(Throwable error) { LOG.trace("[{}] Request failure, processing: {}", logPrefix, error.toString()); RetryVerdict verdict; try { - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(request, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); verdict = retryPolicy.onRequestAbortedVerdict(request, error, retryCount); } catch (Throwable cause) { setFinalError( diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java index e7e334d57d8..a1c6b0e5466 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java @@ -126,6 +126,7 @@ public class CqlRequestHandler implements Throttled { private final RequestThrottler throttler; private final RequestTracker requestTracker; private final SessionMetricUpdater sessionMetricUpdater; + private final DriverExecutionProfile executionProfile; // The errors on the nodes that were already tried (lazily initialized on the first error). // We don't use a map because nodes can appear multiple times. @@ -167,7 +168,8 @@ protected CqlRequestHandler( this.sessionMetricUpdater = session.getMetricUpdater(); this.timer = context.getNettyOptions().getTimer(); - Duration timeout = Conversions.resolveRequestTimeout(statement, context); + this.executionProfile = Conversions.resolveExecutionProfile(initialStatement, context); + Duration timeout = Conversions.resolveRequestTimeout(statement, executionProfile); this.scheduledTimeout = scheduleTimeout(timeout); this.throttler = context.getRequestThrottler(); @@ -176,8 +178,6 @@ protected CqlRequestHandler( @Override public void onThrottleReady(boolean wasDelayed) { - DriverExecutionProfile executionProfile = - Conversions.resolveExecutionProfile(initialStatement, context); if (wasDelayed // avoid call to nanoTime() if metric is disabled: && sessionMetricUpdater.isEnabled( @@ -276,8 +276,6 @@ private void sendRequest( retryCount, scheduleNextExecution, logPrefix); - DriverExecutionProfile executionProfile = - Conversions.resolveExecutionProfile(statement, context); Message message = Conversions.toMessage(statement, executionProfile, context); channel .write(message, statement.isTracing(), statement.getCustomPayload(), nodeResponseCallback) @@ -336,37 +334,28 @@ private void setFinalResult( totalLatencyNanos = completionTimeNanos - startTimeNanos; long nodeLatencyNanos = completionTimeNanos - callback.nodeStartTimeNanos; requestTracker.onNodeSuccess( - callback.statement, - nodeLatencyNanos, - callback.executionProfile, - callback.node, - logPrefix); + callback.statement, nodeLatencyNanos, executionProfile, callback.node, logPrefix); requestTracker.onSuccess( - callback.statement, - totalLatencyNanos, - callback.executionProfile, - callback.node, - logPrefix); + callback.statement, totalLatencyNanos, executionProfile, callback.node, logPrefix); } if (sessionMetricUpdater.isEnabled( - DefaultSessionMetric.CQL_REQUESTS, callback.executionProfile.getName())) { + DefaultSessionMetric.CQL_REQUESTS, executionProfile.getName())) { if (completionTimeNanos == NANOTIME_NOT_MEASURED_YET) { completionTimeNanos = System.nanoTime(); totalLatencyNanos = completionTimeNanos - startTimeNanos; } sessionMetricUpdater.updateTimer( DefaultSessionMetric.CQL_REQUESTS, - callback.executionProfile.getName(), + executionProfile.getName(), totalLatencyNanos, TimeUnit.NANOSECONDS); } } // log the warnings if they have NOT been disabled if (!executionInfo.getWarnings().isEmpty() - && callback.executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOG_WARNINGS) + && executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOG_WARNINGS) && LOG.isWarnEnabled()) { - logServerWarnings( - callback.statement, callback.executionProfile, executionInfo.getWarnings()); + logServerWarnings(callback.statement, executionProfile, executionInfo.getWarnings()); } } catch (Throwable error) { setFinalError(callback.statement, error, callback.node, -1); @@ -418,21 +407,17 @@ private ExecutionInfo buildExecutionInfo( schemaInAgreement, session, context, - callback.executionProfile); + executionProfile); } @Override public void onThrottleFailure(@NonNull RequestThrottlingException error) { - DriverExecutionProfile executionProfile = - Conversions.resolveExecutionProfile(initialStatement, context); sessionMetricUpdater.incrementCounter( DefaultSessionMetric.THROTTLING_ERRORS, executionProfile.getName()); setFinalError(initialStatement, error, null, -1); } private void setFinalError(Statement statement, Throwable error, Node node, int execution) { - DriverExecutionProfile executionProfile = - Conversions.resolveExecutionProfile(statement, context); if (error instanceof DriverException) { ((DriverException) error) .setExecutionInfo( @@ -475,7 +460,6 @@ private class NodeResponseCallback private final long nodeStartTimeNanos = System.nanoTime(); private final Statement statement; - private final DriverExecutionProfile executionProfile; private final Node node; private final Queue queryPlan; private final DriverChannel channel; @@ -505,7 +489,6 @@ private NodeResponseCallback( this.retryCount = retryCount; this.scheduleNextExecution = scheduleNextExecution; this.logPrefix = logPrefix + "|" + execution; - this.executionProfile = Conversions.resolveExecutionProfile(statement, context); } // this gets invoked once the write completes. @@ -544,12 +527,13 @@ public void operationComplete(Future future) throws Exception { cancel(); } else { inFlightCallbacks.add(this); - if (scheduleNextExecution && Conversions.resolveIdempotence(statement, context)) { + if (scheduleNextExecution + && Conversions.resolveIdempotence(statement, executionProfile)) { int nextExecution = execution + 1; long nextDelay; try { nextDelay = - Conversions.resolveSpeculativeExecutionPolicy(statement, context) + Conversions.resolveSpeculativeExecutionPolicy(context, executionProfile) .nextExecution(node, keyspace, statement, nextExecution); } catch (Throwable cause) { // This is a bug in the policy, but not fatal since we have at least one other @@ -697,7 +681,7 @@ private void processErrorResponse(Error errorMessage) { true, reprepareMessage, repreparePayload.customPayload, - Conversions.resolveRequestTimeout(statement, context), + Conversions.resolveRequestTimeout(statement, executionProfile), throttler, sessionMetricUpdater, logPrefix); @@ -767,7 +751,7 @@ private void processErrorResponse(Error errorMessage) { trackNodeError(node, error, NANOTIME_NOT_MEASURED_YET); setFinalError(statement, error, node, execution); } else { - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); RetryVerdict verdict; if (error instanceof ReadTimeoutException) { ReadTimeoutException readTimeout = (ReadTimeoutException) error; @@ -788,7 +772,7 @@ private void processErrorResponse(Error errorMessage) { } else if (error instanceof WriteTimeoutException) { WriteTimeoutException writeTimeout = (WriteTimeoutException) error; verdict = - Conversions.resolveIdempotence(statement, context) + Conversions.resolveIdempotence(statement, executionProfile) ? retryPolicy.onWriteTimeoutVerdict( statement, writeTimeout.getConsistencyLevel(), @@ -820,7 +804,7 @@ private void processErrorResponse(Error errorMessage) { DefaultNodeMetric.IGNORES_ON_UNAVAILABLE); } else { verdict = - Conversions.resolveIdempotence(statement, context) + Conversions.resolveIdempotence(statement, executionProfile) ? retryPolicy.onErrorResponseVerdict(statement, error, retryCount) : RetryVerdict.RETHROW; updateErrorMetrics( @@ -899,12 +883,12 @@ public void onFailure(Throwable error) { } LOG.trace("[{}] Request failure, processing: {}", logPrefix, error); RetryVerdict verdict; - if (!Conversions.resolveIdempotence(statement, context) + if (!Conversions.resolveIdempotence(statement, executionProfile) || error instanceof FrameTooLongException) { verdict = RetryVerdict.RETHROW; } else { try { - RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(statement, context); + RetryPolicy retryPolicy = Conversions.resolveRetryPolicy(context, executionProfile); verdict = retryPolicy.onRequestAbortedVerdict(statement, error, retryCount); } catch (Throwable cause) { setFinalError( From a17f7be614a09ab81bc2982b7f7ab3a123b4ab28 Mon Sep 17 00:00:00 2001 From: Stefan Miklosovic Date: Thu, 22 Aug 2024 14:28:46 +0200 Subject: [PATCH 322/395] autolink JIRA tickets in commit messages patch by Stefan Miklosovic; reviewed by Michael Semb Wever for CASSANDRA-19854 --- .asf.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.asf.yaml b/.asf.yaml index 5ebca4b6e33..ad58f536398 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -19,6 +19,7 @@ notifications: commits: commits@cassandra.apache.org issues: commits@cassandra.apache.org pullrequests: pr@cassandra.apache.org + jira_options: link worklog github: description: "Java Driver for Apache Cassandra®" @@ -31,6 +32,5 @@ github: wiki: false issues: false projects: false - -notifications: - jira_options: link worklog + autolink_jira: + - CASSANDRA From 0962794b2ec724d9939cd47380e68b979b46f693 Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Sun, 20 Nov 2022 19:14:07 -0800 Subject: [PATCH 323/395] Don't return empty routing key when partition key is unbound DefaultBoundStatement#getRoutingKey has logic to infer the routing key when no one has explicitly called setRoutingKey or otherwise set the routing key on the statement. It however doesn't check for cases where nothing has been bound yet on the statement. This causes more problems if the user decides to get a BoundStatementBuilder from the PreparedStatement, set some fields on it, and then copy it by constructing new BoundStatementBuilder objects with the BoundStatement as a parameter, since the empty ByteBuffer gets copied to all bound statements, resulting in all requests being targeted to the same Cassandra node in a token-aware load balancing policy. patch by Ammar Khaku; reviewed by Andy Tolbert, and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1620 --- .../core/cql/DefaultBoundStatement.java | 3 ++- .../driver/core/cql/PreparedStatementIT.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/DefaultBoundStatement.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/DefaultBoundStatement.java index fb6b8fd7b27..3cf99c1be6e 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/DefaultBoundStatement.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/DefaultBoundStatement.java @@ -360,7 +360,8 @@ public ByteBuffer getRoutingKey() { if (indices.isEmpty()) { return null; } else if (indices.size() == 1) { - return getBytesUnsafe(indices.get(0)); + int index = indices.get(0); + return isSet(index) ? getBytesUnsafe(index) : null; } else { ByteBuffer[] components = new ByteBuffer[indices.size()]; for (int i = 0; i < components.length; i++) { diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java index c0df01e3519..5671a7684e5 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java @@ -527,6 +527,25 @@ private void should_infer_routing_information_when_partition_key_is_bound(String assertThat(tokenFactory.hash(boundStatement.getRoutingKey())).isEqualTo(expectedToken); } + @Test + public void should_return_null_routing_information_when_single_partition_key_is_unbound() { + should_return_null_routing_information_when_single_partition_key_is_unbound( + "SELECT a FROM prepared_statement_test WHERE a = ?"); + should_return_null_routing_information_when_single_partition_key_is_unbound( + "INSERT INTO prepared_statement_test (a) VALUES (?)"); + should_return_null_routing_information_when_single_partition_key_is_unbound( + "UPDATE prepared_statement_test SET b = 1 WHERE a = ?"); + should_return_null_routing_information_when_single_partition_key_is_unbound( + "DELETE FROM prepared_statement_test WHERE a = ?"); + } + + private void should_return_null_routing_information_when_single_partition_key_is_unbound( + String queryString) { + CqlSession session = sessionRule.session(); + BoundStatement boundStatement = session.prepare(queryString).bind(); + assertThat(boundStatement.getRoutingKey()).isNull(); + } + private static Iterable firstPageOf(CompletionStage stage) { return CompletableFutures.getUninterruptibly(stage).currentPage(); } From e6ae1933667066bf16ac3ac5203a2a6fdadd1946 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Fri, 16 Aug 2024 11:06:09 +0200 Subject: [PATCH 324/395] JAVA-3167: CompletableFutures.allSuccessful() may return never completed future patch by Lukasz Antoniak; reviewed by Andy Tolbert, and Bret McGuire for JAVA-3167 --- .../util/concurrent/CompletableFutures.java | 5 +++- .../concurrent/CompletableFuturesTest.java | 29 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFutures.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFutures.java index 03265bd1d77..275b2ddfeef 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFutures.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFutures.java @@ -100,7 +100,10 @@ public static CompletionStage allSuccessful(List> i } else { Throwable finalError = errors.get(0); for (int i = 1; i < errors.size(); i++) { - finalError.addSuppressed(errors.get(i)); + Throwable suppressedError = errors.get(i); + if (finalError != suppressedError) { + finalError.addSuppressed(suppressedError); + } } result.completeExceptionally(finalError); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java new file mode 100644 index 00000000000..8a710e02d50 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java @@ -0,0 +1,29 @@ +package com.datastax.oss.driver.internal.core.util.concurrent; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import org.junit.Test; + +public class CompletableFuturesTest { + @Test + public void should_not_suppress_identical_exceptions() throws Exception { + RuntimeException error = new RuntimeException(); + CompletableFuture future1 = new CompletableFuture<>(); + future1.completeExceptionally(error); + CompletableFuture future2 = new CompletableFuture<>(); + future2.completeExceptionally(error); + try { + // if timeout exception is thrown, it indicates that CompletableFutures.allSuccessful() + // did not complete the returned future and potentially caller will wait infinitely + CompletableFutures.allSuccessful(Arrays.asList(future1, future2)) + .toCompletableFuture() + .get(1, TimeUnit.SECONDS); + } catch (ExecutionException e) { + assertThat(e.getCause()).isEqualTo(error); + } + } +} From 5ee12acfff720047db7611a6f54450c1646031a3 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Tue, 3 Sep 2024 16:06:04 -0500 Subject: [PATCH 325/395] ninja-fix Various test fixes --- .../concurrent/CompletableFuturesTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java index 8a710e02d50..04f96f185fd 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFuturesTest.java @@ -1,6 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.datastax.oss.driver.internal.core.util.concurrent; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; import java.util.Arrays; import java.util.concurrent.CompletableFuture; @@ -22,6 +40,7 @@ public void should_not_suppress_identical_exceptions() throws Exception { CompletableFutures.allSuccessful(Arrays.asList(future1, future2)) .toCompletableFuture() .get(1, TimeUnit.SECONDS); + fail(); } catch (ExecutionException e) { assertThat(e.getCause()).isEqualTo(error); } From 9cfb4f6712e392c1b6c87db268565fd3b27d0c5c Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Thu, 5 Sep 2024 13:04:52 +0200 Subject: [PATCH 326/395] Run integration tests with DSE 6.9.0 patch by Lukasz Antoniak; reviewed by Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1955 --- Jenkinsfile | 19 +++++++++++++------ .../datastax/oss/driver/api/core/Version.java | 1 + .../driver/api/testinfra/ccm/CcmBridge.java | 3 ++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4f1ef95d101..4cc20d79604 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -268,6 +268,7 @@ pipeline { 'dse-6.0.18', // Previous DataStax Enterprise 'dse-6.7.17', // Previous DataStax Enterprise 'dse-6.8.30', // Current DataStax Enterprise + 'dse-6.9.0', // Current DataStax Enterprise 'ALL'], description: '''Apache Cassandra® and DataStax Enterprise server version to use for adhoc BUILD-AND-EXECUTE-TESTS builds

    Driver versionTinkerPop version
    4.17.03.5.3
    4.16.03.5.3
    4.15.03.5.3
    4.14.13.5.3
    4.0Apache Cassandra® v4.x (CURRENTLY UNDER DEVELOPMENT)Apache Cassandra® v4.0.x
    4.1Apache Cassandra® v4.1.x
    dse-4.8.16
    @@ -325,6 +326,10 @@ pipeline { + + + +
    dse-6.8.30 DataStax Enterprise v6.8.x
    dse-6.9.0DataStax Enterprise v6.9.x
    ''') choice( name: 'ADHOC_BUILD_AND_EXECUTE_TESTS_JABBA_VERSION', @@ -416,9 +421,9 @@ pipeline { H 2 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 4.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 # Every weeknight (Monday - Friday) around 12:00 PM noon ### JDK11 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 - H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 ### JDK17 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 - H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 """ : "") } @@ -452,9 +457,10 @@ pipeline { axes { axis { name 'SERVER_VERSION' - values '3.11', // Latest stable Apache CassandraⓇ - '4.1', // Development Apache CassandraⓇ - 'dse-6.8.30' // Current DataStax Enterprise + values '3.11', // Latest stable Apache CassandraⓇ + '4.1', // Development Apache CassandraⓇ + 'dse-6.8.30', // Current DataStax Enterprise + 'dse-6.9.0' // Current DataStax Enterprise } axis { name 'JABBA_VERSION' @@ -571,7 +577,8 @@ pipeline { 'dse-5.1.35', // Legacy DataStax Enterprise 'dse-6.0.18', // Previous DataStax Enterprise 'dse-6.7.17', // Previous DataStax Enterprise - 'dse-6.8.30' // Current DataStax Enterprise + 'dse-6.8.30', // Current DataStax Enterprise + 'dse-6.9.0' // Current DataStax Enterprise } } when { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/Version.java b/core/src/main/java/com/datastax/oss/driver/api/core/Version.java index 3f12c54faf7..4de006da268 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/Version.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/Version.java @@ -56,6 +56,7 @@ public class Version implements Comparable, Serializable { @NonNull public static final Version V5_0_0 = Objects.requireNonNull(parse("5.0.0")); @NonNull public static final Version V6_7_0 = Objects.requireNonNull(parse("6.7.0")); @NonNull public static final Version V6_8_0 = Objects.requireNonNull(parse("6.8.0")); + @NonNull public static final Version V6_9_0 = Objects.requireNonNull(parse("6.9.0")); private final int major; private final int minor; diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java index 995513e3919..5b0c114a5fe 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java @@ -479,7 +479,8 @@ private Optional overrideJvmVersionForDseWorkloads() { return Optional.empty(); } - if (getDseVersion().get().compareTo(Version.parse("6.8.19")) < 0) { + if (getDseVersion().get().compareTo(Version.V6_9_0) >= 0) { + // DSE 6.9.0 supports only JVM 11 onwards (also with graph workload) return Optional.empty(); } From c961012000efffd3d50476d4549487f7fc538c01 Mon Sep 17 00:00:00 2001 From: Henry Hughes Date: Wed, 23 Aug 2023 15:35:42 -0700 Subject: [PATCH 327/395] JAVA-3117: Call CcmCustomRule#after if CcmCustomRule#before fails to allow subsequent tests to run patch by Henry Hughes; reviewed by Alexandre Dutra and Andy Tolbert for JAVA-3117 --- .../api/testinfra/ccm/CustomCcmRule.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java index 58bafd438f8..cf150b12f55 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java @@ -18,6 +18,8 @@ package com.datastax.oss.driver.api.testinfra.ccm; import java.util.concurrent.atomic.AtomicReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A rule that creates a ccm cluster that can be used in a test. This should be used if you plan on @@ -30,6 +32,7 @@ */ public class CustomCcmRule extends BaseCcmRule { + private static final Logger LOG = LoggerFactory.getLogger(CustomCcmRule.class); private static final AtomicReference CURRENT = new AtomicReference<>(); CustomCcmRule(CcmBridge ccmBridge) { @@ -39,7 +42,20 @@ public class CustomCcmRule extends BaseCcmRule { @Override protected void before() { if (CURRENT.get() == null && CURRENT.compareAndSet(null, this)) { - super.before(); + try { + super.before(); + } catch (Exception e) { + // ExternalResource will not call after() when before() throws an exception + // Let's try and clean up and release the lock we have in CURRENT + LOG.warn( + "Error in CustomCcmRule before() method, attempting to clean up leftover state", e); + try { + after(); + } catch (Exception e1) { + LOG.warn("Error cleaning up CustomCcmRule before() failure", e1); + } + throw e; + } } else if (CURRENT.get() != this) { throw new IllegalStateException( "Attempting to use a Ccm rule while another is in use. This is disallowed"); From 77805f5103354cadb360384f4f41e0eca73d72f4 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 2 Sep 2024 06:44:53 +0200 Subject: [PATCH 328/395] JAVA-3149: Support request cancellation in request throttler patch by Lukasz Antoniak; reviewed by Andy Tolbert and Chris Lohfink for JAVA-3149 --- .../ContinuousRequestHandlerBase.java | 1 + .../core/graph/GraphRequestHandler.java | 1 + .../session/throttling/RequestThrottler.java | 8 +++++ .../internal/core/cql/CqlPrepareHandler.java | 1 + .../internal/core/cql/CqlRequestHandler.java | 1 + .../ConcurrencyLimitingRequestThrottler.java | 16 +++++++++ .../PassThroughRequestThrottler.java | 5 +++ .../RateLimitingRequestThrottler.java | 12 +++++++ ...ncurrencyLimitingRequestThrottlerTest.java | 5 +++ .../RateLimitingRequestThrottlerTest.java | 13 ++++++- .../driver/core/throttling/ThrottlingIT.java | 34 +++++++++++++++---- 11 files changed, 89 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java index 9a7be344721..0453022cb6a 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/cql/continuous/ContinuousRequestHandlerBase.java @@ -410,6 +410,7 @@ public void cancel() { cancelScheduledTasks(null); cancelGlobalTimeout(); + throttler.signalCancel(this); } private void cancelGlobalTimeout() { diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java index 702da69b855..5c9ceb00df2 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/graph/GraphRequestHandler.java @@ -153,6 +153,7 @@ public class GraphRequestHandler implements Throttled { try { if (t instanceof CancellationException) { cancelScheduledTasks(); + context.getRequestThrottler().signalCancel(this); } } catch (Throwable t2) { Loggers.warnWithException(LOG, "[{}] Uncaught exception", logPrefix, t2); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java index cb55fac336c..7e2b41ebbdb 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java @@ -56,4 +56,12 @@ public interface RequestThrottler extends Closeable { * perform time-based eviction on pending requests. */ void signalTimeout(@NonNull Throttled request); + + /** + * Signals that a request has been cancelled. This indicates to the throttler that another request + * might be started. + */ + default void signalCancel(@NonNull Throttled request) { + // no-op for backward compatibility purposes + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java index 8fe1adb20b1..1ee1f303ab2 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareHandler.java @@ -124,6 +124,7 @@ protected CqlPrepareHandler( try { if (t instanceof CancellationException) { cancelTimeout(); + context.getRequestThrottler().signalCancel(this); } } catch (Throwable t2) { Loggers.warnWithException(LOG, "[{}] Uncaught exception", logPrefix, t2); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java index a1c6b0e5466..0808bdce63f 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java @@ -152,6 +152,7 @@ protected CqlRequestHandler( try { if (t instanceof CancellationException) { cancelScheduledTasks(); + context.getRequestThrottler().signalCancel(this); } } catch (Throwable t2) { Loggers.warnWithException(LOG, "[{}] Uncaught exception", logPrefix, t2); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java index e8f27467c6f..438bed0953b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java @@ -145,6 +145,22 @@ public void signalTimeout(@NonNull Throttled request) { } } + @Override + public void signalCancel(@NonNull Throttled request) { + lock.lock(); + try { + if (!closed) { + if (queue.remove(request)) { // The request has been cancelled before it was active + LOG.trace("[{}] Removing cancelled request from the queue", logPrefix); + } else { + onRequestDone(); + } + } + } finally { + lock.unlock(); + } + } + @SuppressWarnings("GuardedBy") // this method is only called with the lock held private void onRequestDone() { assert lock.isHeldByCurrentThread(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/PassThroughRequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/PassThroughRequestThrottler.java index 714c712a4e8..2210e4b26f1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/PassThroughRequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/PassThroughRequestThrottler.java @@ -69,6 +69,11 @@ public void signalTimeout(@NonNull Throttled request) { // nothing to do } + @Override + public void signalCancel(@NonNull Throttled request) { + // nothing to do + } + @Override public void close() throws IOException { // nothing to do diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottler.java index 6536804ffee..03a693dc0fe 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottler.java @@ -198,6 +198,18 @@ public void signalTimeout(@NonNull Throttled request) { } } + @Override + public void signalCancel(@NonNull Throttled request) { + lock.lock(); + try { + if (!closed && queue.remove(request)) { // The request has been cancelled before it was active + LOG.trace("[{}] Removing cancelled request from the queue", logPrefix); + } + } finally { + lock.unlock(); + } + } + @Override public void close() { lock.lock(); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java index b587ac3daa2..c01b26c1e9f 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java @@ -88,6 +88,11 @@ public void should_allow_new_request_when_active_one_times_out() { should_allow_new_request_when_active_one_completes(throttler::signalTimeout); } + @Test + public void should_allow_new_request_when_active_one_canceled() { + should_allow_new_request_when_active_one_completes(throttler::signalCancel); + } + private void should_allow_new_request_when_active_one_completes( Consumer completeCallback) { // Given diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java index 7336fb447b6..0e0fe7c1c65 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java @@ -25,6 +25,7 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.session.throttling.Throttled; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.context.NettyOptions; import com.datastax.oss.driver.internal.core.util.concurrent.ScheduledTaskCapturingEventLoop; @@ -33,6 +34,7 @@ import java.time.Duration; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -164,6 +166,15 @@ public void should_reject_when_queue_is_full() { @Test public void should_remove_timed_out_request_from_queue() { + testRemoveInvalidEventFromQueue(throttler::signalTimeout); + } + + @Test + public void should_remove_cancel_request_from_queue() { + testRemoveInvalidEventFromQueue(throttler::signalCancel); + } + + private void testRemoveInvalidEventFromQueue(Consumer completeCallback) { // Given for (int i = 0; i < 5; i++) { throttler.register(new MockThrottled()); @@ -174,7 +185,7 @@ public void should_remove_timed_out_request_from_queue() { throttler.register(queued2); // When - throttler.signalTimeout(queued1); + completeCallback.accept(queued1); // Then assertThatStage(queued2.started).isNotDone(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java index a6e7295eb09..6fa1a37355b 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/throttling/ThrottlingIT.java @@ -24,13 +24,16 @@ import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import com.datastax.oss.driver.categories.ParallelizableTests; import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler; import com.datastax.oss.simulacron.common.cluster.ClusterSpec; import com.datastax.oss.simulacron.common.stubbing.PrimeDsl; +import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -39,21 +42,20 @@ public class ThrottlingIT { private static final String QUERY = "select * from foo"; + private static final int maxConcurrentRequests = 10; + private static final int maxQueueSize = 10; @Rule public SimulacronRule simulacron = new SimulacronRule(ClusterSpec.builder().withNodes(1)); - @Test - public void should_reject_request_when_throttling_by_concurrency() { + private DriverConfigLoader loader = null; + @Before + public void setUp() { // Add a delay so that requests don't complete during the test simulacron .cluster() .prime(PrimeDsl.when(QUERY).then(PrimeDsl.noRows()).delay(5, TimeUnit.SECONDS)); - - int maxConcurrentRequests = 10; - int maxQueueSize = 10; - - DriverConfigLoader loader = + loader = SessionUtils.configLoaderBuilder() .withClass( DefaultDriverOption.REQUEST_THROTTLER_CLASS, @@ -63,7 +65,10 @@ public void should_reject_request_when_throttling_by_concurrency() { maxConcurrentRequests) .withInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE, maxQueueSize) .build(); + } + @Test + public void should_reject_request_when_throttling_by_concurrency() { try (CqlSession session = SessionUtils.newSession(simulacron, loader)) { // Saturate the session and fill the queue @@ -81,4 +86,19 @@ public void should_reject_request_when_throttling_by_concurrency() { + "(concurrent requests: 10, queue size: 10)"); } } + + @Test + public void should_propagate_cancel_to_throttler() { + try (CqlSession session = SessionUtils.newSession(simulacron, loader)) { + + // Try to saturate the session and fill the queue + for (int i = 0; i < maxConcurrentRequests + maxQueueSize; i++) { + CompletionStage future = session.executeAsync(QUERY); + future.toCompletableFuture().cancel(true); + } + + // The next query should be successful, because the previous queries were cancelled + session.execute(QUERY); + } + } } From 4fb51081a3a71b2017ddc3f43a7945e3a9d19e25 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 10 Jun 2024 12:42:29 +0200 Subject: [PATCH 329/395] Fix C* 3.0 tests failing on Jenkins patch by Lukasz Antoniak; reviewed by Bret McGuire reference: #1939 --- .../test/java/com/datastax/oss/driver/mapper/DeleteIT.java | 3 +-- .../com/datastax/oss/driver/mapper/InventoryITBase.java | 6 +++++- .../oss/driver/mapper/SelectCustomWhereClauseIT.java | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java index 0acdbeae53a..03e3597501c 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteIT.java @@ -60,8 +60,7 @@ description = ">= in WHERE clause not supported in legacy versions") public class DeleteIT extends InventoryITBase { - private static CustomCcmRule CCM_RULE = - CustomCcmRule.builder().withCassandraConfiguration("enable_sasi_indexes", "true").build(); + private static CustomCcmRule CCM_RULE = CustomCcmRule.builder().build(); private static final SessionRule SESSION_RULE = SessionRule.builder(CCM_RULE).build(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java index 2be025b3739..9495003ae49 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java @@ -59,6 +59,10 @@ public abstract class InventoryITBase { new ProductSale(MP3_DOWNLOAD.getId(), DATE_3, 7, Uuids.startOf(915192000), 0.99, 12); protected static List createStatements(BaseCcmRule ccmRule) { + return createStatements(ccmRule, false); + } + + protected static List createStatements(BaseCcmRule ccmRule, boolean requiresSasiIndex) { ImmutableList.Builder builder = ImmutableList.builder() .add( @@ -71,7 +75,7 @@ protected static List createStatements(BaseCcmRule ccmRule) { "CREATE TABLE product_sale(id uuid, day text, ts uuid, customer_id int, price " + "double, count int, PRIMARY KEY ((id, day), customer_id, ts))"); - if (supportsSASI(ccmRule) && !isSasiBroken(ccmRule)) { + if (requiresSasiIndex && supportsSASI(ccmRule) && !isSasiBroken(ccmRule)) { builder.add( "CREATE CUSTOM INDEX product_description ON product(description) " + "USING 'org.apache.cassandra.index.sasi.SASIIndex' " diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java index 3df1ccd21a7..1f1b92b8623 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/SelectCustomWhereClauseIT.java @@ -75,7 +75,7 @@ public static void setup() { SchemaChangeSynchronizer.withLock( () -> { - for (String query : createStatements(CCM_RULE)) { + for (String query : createStatements(CCM_RULE, true)) { session.execute( SimpleStatement.builder(query) .setExecutionProfile(SESSION_RULE.slowProfile()) From 6d3ba47631ebde78460168a2d33c4facde0bd731 Mon Sep 17 00:00:00 2001 From: Jason Koch Date: Mon, 12 Aug 2024 22:52:13 -0700 Subject: [PATCH 330/395] Reduce lock held duration in ConcurrencyLimitingRequestThrottler It might take some (small) time for callback handling when the throttler request proceeds to submission. Before this change, the throttler proceed request will happen while holding the lock, preventing other tasks from proceeding when there is spare capacity and even preventing tasks from enqueuing until the callback completes. By tracking the expected outcome, we can perform the callback outside of the lock. This means that request registration and submission can proceed even when a long callback is being processed. patch by Jason Koch; Reviewed by Andy Tolbert and Chris Lohfink for CASSANDRA-19922 --- .../ConcurrencyLimitingRequestThrottler.java | 39 ++++- ...ncurrencyLimitingRequestThrottlerTest.java | 143 ++++++++++++++++-- .../session/throttling/MockThrottled.java | 30 +++- .../RateLimitingRequestThrottlerTest.java | 30 ++-- 4 files changed, 206 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java index 438bed0953b..ffe0ffe9650 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java @@ -25,6 +25,7 @@ import com.datastax.oss.driver.api.core.session.throttling.Throttled; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.locks.ReentrantLock; @@ -87,6 +88,8 @@ public ConcurrencyLimitingRequestThrottler(DriverContext context) { @Override public void register(@NonNull Throttled request) { + boolean notifyReadyRequired = false; + lock.lock(); try { if (closed) { @@ -96,7 +99,7 @@ public void register(@NonNull Throttled request) { // We have capacity for one more concurrent request LOG.trace("[{}] Starting newly registered request", logPrefix); concurrentRequests += 1; - request.onThrottleReady(false); + notifyReadyRequired = true; } else if (queue.size() < maxQueueSize) { LOG.trace("[{}] Enqueuing request", logPrefix); queue.add(request); @@ -112,16 +115,26 @@ public void register(@NonNull Throttled request) { } finally { lock.unlock(); } + + // no need to hold the lock while allowing the task to progress + if (notifyReadyRequired) { + request.onThrottleReady(false); + } } @Override public void signalSuccess(@NonNull Throttled request) { + Throttled nextRequest = null; lock.lock(); try { - onRequestDone(); + nextRequest = onRequestDoneAndDequeNext(); } finally { lock.unlock(); } + + if (nextRequest != null) { + nextRequest.onThrottleReady(true); + } } @Override @@ -131,48 +144,62 @@ public void signalError(@NonNull Throttled request, @NonNull Throwable error) { @Override public void signalTimeout(@NonNull Throttled request) { + Throttled nextRequest = null; lock.lock(); try { if (!closed) { if (queue.remove(request)) { // The request timed out before it was active LOG.trace("[{}] Removing timed out request from the queue", logPrefix); } else { - onRequestDone(); + nextRequest = onRequestDoneAndDequeNext(); } } } finally { lock.unlock(); } + + if (nextRequest != null) { + nextRequest.onThrottleReady(true); + } } @Override public void signalCancel(@NonNull Throttled request) { + Throttled nextRequest = null; lock.lock(); try { if (!closed) { if (queue.remove(request)) { // The request has been cancelled before it was active LOG.trace("[{}] Removing cancelled request from the queue", logPrefix); } else { - onRequestDone(); + nextRequest = onRequestDoneAndDequeNext(); } } } finally { lock.unlock(); } + + if (nextRequest != null) { + nextRequest.onThrottleReady(true); + } } @SuppressWarnings("GuardedBy") // this method is only called with the lock held - private void onRequestDone() { + @Nullable + private Throttled onRequestDoneAndDequeNext() { assert lock.isHeldByCurrentThread(); if (!closed) { if (queue.isEmpty()) { concurrentRequests -= 1; } else { LOG.trace("[{}] Starting dequeued request", logPrefix); - queue.poll().onThrottleReady(true); // don't touch concurrentRequests since we finished one but started another + return queue.poll(); } } + + // no next task was dequeued + return null; } @Override diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java index c01b26c1e9f..7eb682070cd 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottlerTest.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.session.throttling.Throttled; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import org.junit.Before; import org.junit.Test; @@ -67,7 +68,7 @@ public void should_start_immediately_when_under_capacity() { throttler.register(request); // Then - assertThatStage(request.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + assertThatStage(request.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); assertThat(throttler.getConcurrentRequests()).isEqualTo(1); assertThat(throttler.getQueue()).isEmpty(); } @@ -98,7 +99,7 @@ private void should_allow_new_request_when_active_one_completes( // Given MockThrottled first = new MockThrottled(); throttler.register(first); - assertThatStage(first.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + assertThatStage(first.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); for (int i = 0; i < 4; i++) { // fill to capacity throttler.register(new MockThrottled()); } @@ -113,7 +114,7 @@ private void should_allow_new_request_when_active_one_completes( throttler.register(incoming); // Then - assertThatStage(incoming.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + assertThatStage(incoming.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); assertThat(throttler.getConcurrentRequests()).isEqualTo(5); assertThat(throttler.getQueue()).isEmpty(); } @@ -132,7 +133,7 @@ public void should_enqueue_when_over_capacity() { throttler.register(incoming); // Then - assertThatStage(incoming.started).isNotDone(); + assertThatStage(incoming.ended).isNotDone(); assertThat(throttler.getConcurrentRequests()).isEqualTo(5); assertThat(throttler.getQueue()).containsExactly(incoming); } @@ -157,20 +158,20 @@ private void should_dequeue_when_active_completes(Consumer completeCa // Given MockThrottled first = new MockThrottled(); throttler.register(first); - assertThatStage(first.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + assertThatStage(first.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); for (int i = 0; i < 4; i++) { throttler.register(new MockThrottled()); } MockThrottled incoming = new MockThrottled(); throttler.register(incoming); - assertThatStage(incoming.started).isNotDone(); + assertThatStage(incoming.ended).isNotDone(); // When completeCallback.accept(first); // Then - assertThatStage(incoming.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); + assertThatStage(incoming.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); assertThat(throttler.getConcurrentRequests()).isEqualTo(5); assertThat(throttler.getQueue()).isEmpty(); } @@ -189,7 +190,7 @@ public void should_reject_when_queue_is_full() { throttler.register(incoming); // Then - assertThatStage(incoming.started) + assertThatStage(incoming.ended) .isFailed(error -> assertThat(error).isInstanceOf(RequestThrottlingException.class)); } @@ -208,7 +209,7 @@ public void should_remove_timed_out_request_from_queue() { throttler.signalTimeout(queued1); // Then - assertThatStage(queued2.started).isNotDone(); + assertThatStage(queued2.ended).isNotDone(); assertThat(throttler.getConcurrentRequests()).isEqualTo(5); assertThat(throttler.getQueue()).hasSize(1); } @@ -223,7 +224,7 @@ public void should_reject_enqueued_when_closing() { for (int i = 0; i < 10; i++) { MockThrottled request = new MockThrottled(); throttler.register(request); - assertThatStage(request.started).isNotDone(); + assertThatStage(request.ended).isNotDone(); enqueued.add(request); } @@ -232,7 +233,7 @@ public void should_reject_enqueued_when_closing() { // Then for (MockThrottled request : enqueued) { - assertThatStage(request.started) + assertThatStage(request.ended) .isFailed(error -> assertThat(error).isInstanceOf(RequestThrottlingException.class)); } @@ -241,7 +242,125 @@ public void should_reject_enqueued_when_closing() { throttler.register(request); // Then - assertThatStage(request.started) + assertThatStage(request.ended) .isFailed(error -> assertThat(error).isInstanceOf(RequestThrottlingException.class)); } + + @Test + public void should_run_throttle_callbacks_concurrently() throws InterruptedException { + // Given + + // a task is enqueued, which when in onThrottleReady, will stall latch countDown()ed + // register() should automatically start onThrottleReady on same thread + + // start a parallel thread + CountDownLatch firstRelease = new CountDownLatch(1); + MockThrottled first = new MockThrottled(firstRelease); + Runnable r = + () -> { + throttler.register(first); + first.ended.toCompletableFuture().thenRun(() -> throttler.signalSuccess(first)); + }; + Thread t = new Thread(r); + t.start(); + + // wait for the registration threads to reach await state + assertThatStage(first.started).isSuccess(); + assertThatStage(first.ended).isNotDone(); + + // When + // we concurrently submit a second shorter task + MockThrottled second = new MockThrottled(); + // (on a second thread, so that we can join and force a timeout in case + // registration is delayed) + Thread t2 = new Thread(() -> throttler.register(second)); + t2.start(); + t2.join(1_000); + + // Then + // registration will trigger callback, should complete ~immediately + assertThatStage(second.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + // first should still be unfinished + assertThatStage(first.started).isDone(); + assertThatStage(first.ended).isNotDone(); + // now finish, and verify + firstRelease.countDown(); + assertThatStage(first.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + + t.join(1_000); + } + + @Test + public void should_enqueue_tasks_quickly_when_callbacks_blocked() throws InterruptedException { + // Given + + // Multiple tasks are registered, up to the limit, and proceed into their + // callback + + // start five parallel threads + final int THREADS = 5; + Thread[] threads = new Thread[THREADS]; + CountDownLatch[] latches = new CountDownLatch[THREADS]; + MockThrottled[] throttled = new MockThrottled[THREADS]; + for (int i = 0; i < threads.length; i++) { + latches[i] = new CountDownLatch(1); + final MockThrottled itThrottled = new MockThrottled(latches[i]); + throttled[i] = itThrottled; + threads[i] = + new Thread( + () -> { + throttler.register(itThrottled); + itThrottled + .ended + .toCompletableFuture() + .thenRun(() -> throttler.signalSuccess(itThrottled)); + }); + threads[i].start(); + } + + // wait for the registration threads to be launched + // they are all waiting now + for (int i = 0; i < throttled.length; i++) { + assertThatStage(throttled[i].started).isSuccess(); + assertThatStage(throttled[i].ended).isNotDone(); + } + + // When + // we concurrently submit another task + MockThrottled last = new MockThrottled(); + throttler.register(last); + + // Then + // registration will enqueue the callback, and it should not + // take any time to proceed (ie: we should not be blocked) + // and there should be an element in the queue + assertThatStage(last.started).isNotDone(); + assertThatStage(last.ended).isNotDone(); + assertThat(throttler.getQueue()).containsExactly(last); + + // we still have not released, so old throttled threads should be waiting + for (int i = 0; i < throttled.length; i++) { + assertThatStage(throttled[i].started).isDone(); + assertThatStage(throttled[i].ended).isNotDone(); + } + + // now let us release .. + for (int i = 0; i < latches.length; i++) { + latches[i].countDown(); + } + + // .. and check everything finished up OK + for (int i = 0; i < latches.length; i++) { + assertThatStage(throttled[i].started).isSuccess(); + assertThatStage(throttled[i].ended).isSuccess(); + } + + // for good measure, we will also wait for the enqueued to complete + assertThatStage(last.started).isSuccess(); + assertThatStage(last.ended).isSuccess(); + + for (int i = 0; i < threads.length; i++) { + threads[i].join(1_000); + } + } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/MockThrottled.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/MockThrottled.java index b7cd0ee8a54..9e54e3d511f 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/MockThrottled.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/MockThrottled.java @@ -19,21 +19,45 @@ import com.datastax.oss.driver.api.core.RequestThrottlingException; import com.datastax.oss.driver.api.core.session.throttling.Throttled; +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.CountDownLatch; class MockThrottled implements Throttled { + final CompletionStage started = new CompletableFuture<>(); + final CompletionStage ended = new CompletableFuture<>(); + final CountDownLatch canRelease; - final CompletionStage started = new CompletableFuture<>(); + public MockThrottled() { + this(new CountDownLatch(0)); + } + + /* + * The releaseLatch can be provided to add some delay before the + * task readiness/fail callbacks complete. This can be used, eg, to + * imitate a slow callback. + */ + public MockThrottled(CountDownLatch releaseLatch) { + this.canRelease = releaseLatch; + } @Override public void onThrottleReady(boolean wasDelayed) { - started.toCompletableFuture().complete(wasDelayed); + started.toCompletableFuture().complete(null); + awaitRelease(); + ended.toCompletableFuture().complete(wasDelayed); } @Override public void onThrottleFailure(@NonNull RequestThrottlingException error) { - started.toCompletableFuture().completeExceptionally(error); + started.toCompletableFuture().complete(null); + awaitRelease(); + ended.toCompletableFuture().completeExceptionally(error); + } + + private void awaitRelease() { + Uninterruptibles.awaitUninterruptibly(canRelease); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java index 0e0fe7c1c65..1e15610bf7b 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/session/throttling/RateLimitingRequestThrottlerTest.java @@ -98,7 +98,7 @@ public void should_start_immediately_when_under_capacity() { throttler.register(request); // Then - assertThatStage(request.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + assertThatStage(request.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); assertThat(throttler.getStoredPermits()).isEqualTo(4); assertThat(throttler.getQueue()).isEmpty(); } @@ -117,7 +117,7 @@ public void should_allow_new_request_when_under_rate() { throttler.register(request); // Then - assertThatStage(request.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); + assertThatStage(request.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isFalse()); assertThat(throttler.getStoredPermits()).isEqualTo(0); assertThat(throttler.getQueue()).isEmpty(); } @@ -136,7 +136,7 @@ public void should_enqueue_when_over_rate() { throttler.register(request); // Then - assertThatStage(request.started).isNotDone(); + assertThatStage(request.ended).isNotDone(); assertThat(throttler.getStoredPermits()).isEqualTo(0); assertThat(throttler.getQueue()).containsExactly(request); @@ -160,7 +160,7 @@ public void should_reject_when_queue_is_full() { throttler.register(request); // Then - assertThatStage(request.started) + assertThatStage(request.ended) .isFailed(error -> assertThat(error).isInstanceOf(RequestThrottlingException.class)); } @@ -188,7 +188,7 @@ private void testRemoveInvalidEventFromQueue(Consumer completeCallbac completeCallback.accept(queued1); // Then - assertThatStage(queued2.started).isNotDone(); + assertThatStage(queued2.ended).isNotDone(); assertThat(throttler.getStoredPermits()).isEqualTo(0); assertThat(throttler.getQueue()).containsExactly(queued2); } @@ -202,10 +202,10 @@ public void should_dequeue_when_draining_task_runs() { MockThrottled queued1 = new MockThrottled(); throttler.register(queued1); - assertThatStage(queued1.started).isNotDone(); + assertThatStage(queued1.ended).isNotDone(); MockThrottled queued2 = new MockThrottled(); throttler.register(queued2); - assertThatStage(queued2.started).isNotDone(); + assertThatStage(queued2.ended).isNotDone(); assertThat(throttler.getStoredPermits()).isEqualTo(0); assertThat(throttler.getQueue()).hasSize(2); @@ -230,8 +230,8 @@ public void should_dequeue_when_draining_task_runs() { task.run(); // Then - assertThatStage(queued1.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); - assertThatStage(queued2.started).isNotDone(); + assertThatStage(queued1.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); + assertThatStage(queued2.ended).isNotDone(); assertThat(throttler.getStoredPermits()).isEqualTo(0); assertThat(throttler.getQueue()).containsExactly(queued2); // task reschedules itself since it did not empty the queue @@ -244,7 +244,7 @@ public void should_dequeue_when_draining_task_runs() { task.run(); // Then - assertThatStage(queued2.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); + assertThatStage(queued2.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); assertThat(throttler.getStoredPermits()).isEqualTo(0); assertThat(throttler.getQueue()).isEmpty(); assertThat(adminExecutor.nextTask()).isNull(); @@ -286,14 +286,14 @@ public void should_keep_accumulating_time_if_no_permits_created() { // Then MockThrottled queued = new MockThrottled(); throttler.register(queued); - assertThatStage(queued.started).isNotDone(); + assertThatStage(queued.ended).isNotDone(); // When clock.add(ONE_HUNDRED_MILLISECONDS); adminExecutor.nextTask().run(); // Then - assertThatStage(queued.started).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); + assertThatStage(queued.ended).isSuccess(wasDelayed -> assertThat(wasDelayed).isTrue()); } @Test @@ -306,7 +306,7 @@ public void should_reject_enqueued_when_closing() { for (int i = 0; i < 10; i++) { MockThrottled request = new MockThrottled(); throttler.register(request); - assertThatStage(request.started).isNotDone(); + assertThatStage(request.ended).isNotDone(); enqueued.add(request); } @@ -315,7 +315,7 @@ public void should_reject_enqueued_when_closing() { // Then for (MockThrottled request : enqueued) { - assertThatStage(request.started) + assertThatStage(request.ended) .isFailed(error -> assertThat(error).isInstanceOf(RequestThrottlingException.class)); } @@ -324,7 +324,7 @@ public void should_reject_enqueued_when_closing() { throttler.register(request); // Then - assertThatStage(request.started) + assertThatStage(request.ended) .isFailed(error -> assertThat(error).isInstanceOf(RequestThrottlingException.class)); } } From 306bf3744a3d24ad01700e4e1d3c14b9a696927f Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Fri, 30 Sep 2022 15:36:36 -0700 Subject: [PATCH 331/395] Annotate BatchStatement, Statement, SimpleStatement methods with CheckReturnValue Since the driver's default implementation is for BatchStatement and SimpleStatement methods to be immutable, we should annotate those methods with @CheckReturnValue. Statement#setNowInSeconds implementations are immutable so annotate that too. patch by Ammar Khaku; reviewed by Andy Tolbert and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1607 --- core/revapi.json | 133 ++++++++++++++++++ .../driver/api/core/cql/BatchStatement.java | 8 ++ .../driver/api/core/cql/SimpleStatement.java | 7 + .../oss/driver/api/core/cql/Statement.java | 1 + 4 files changed, 149 insertions(+) diff --git a/core/revapi.json b/core/revapi.json index 318e29709ec..1c875895d6c 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -6956,6 +6956,139 @@ "old": "method java.lang.Throwable java.lang.Throwable::fillInStackTrace() @ com.fasterxml.jackson.databind.deser.UnresolvedForwardReference", "new": "method com.fasterxml.jackson.databind.deser.UnresolvedForwardReference com.fasterxml.jackson.databind.deser.UnresolvedForwardReference::fillInStackTrace()", "justification": "Upgrade jackson-databind to 2.13.4.1 to address CVEs, API change cause: https://github.com/FasterXML/jackson-databind/issues/3419" + }, + { + "code": "java.annotation.added", + "old": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BatchStatement", + "new": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BatchStatement", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BatchableStatement>", + "new": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BatchStatement", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BatchableStatement>", + "new": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BatchableStatement>", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BoundStatement", + "new": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.BoundStatement", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.SimpleStatement", + "new": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int) @ com.datastax.oss.driver.api.core.cql.SimpleStatement", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int)", + "new": "method SelfT com.datastax.oss.driver.api.core.cql.Statement>::setNowInSeconds(int)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::add(com.datastax.oss.driver.api.core.cql.BatchableStatement)", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::add(com.datastax.oss.driver.api.core.cql.BatchableStatement)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::addAll(com.datastax.oss.driver.api.core.cql.BatchableStatement[])", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::addAll(com.datastax.oss.driver.api.core.cql.BatchableStatement[])", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::addAll(java.lang.Iterable>)", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::addAll(java.lang.Iterable>)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::clear()", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::clear()", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::setBatchType(com.datastax.oss.driver.api.core.cql.BatchType)", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::setBatchType(com.datastax.oss.driver.api.core.cql.BatchType)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::setKeyspace(com.datastax.oss.driver.api.core.CqlIdentifier)", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::setKeyspace(com.datastax.oss.driver.api.core.CqlIdentifier)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "JAVA-2161: Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::setKeyspace(java.lang.String)", + "new": "method com.datastax.oss.driver.api.core.cql.BatchStatement com.datastax.oss.driver.api.core.cql.BatchStatement::setKeyspace(java.lang.String)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "JAVA-2161: Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setQuery(java.lang.String)", + "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setQuery(java.lang.String)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setKeyspace(com.datastax.oss.driver.api.core.CqlIdentifier)", + "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setKeyspace(com.datastax.oss.driver.api.core.CqlIdentifier)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setKeyspace(java.lang.String)", + "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setKeyspace(java.lang.String)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setPositionalValues(java.util.List)", + "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setPositionalValues(java.util.List)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setNamedValuesWithIds(java.util.Map)", + "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setNamedValuesWithIds(java.util.Map)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.annotation.added", + "old": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setNamedValues(java.util.Map)", + "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setNamedValues(java.util.Map)", + "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", + "justification": "Annotate mutating methods with @CheckReturnValue" } ] } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/cql/BatchStatement.java b/core/src/main/java/com/datastax/oss/driver/api/core/cql/BatchStatement.java index 0f37ed71ce2..9deb33c6007 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/cql/BatchStatement.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/cql/BatchStatement.java @@ -26,6 +26,7 @@ import com.datastax.oss.driver.internal.core.util.Sizes; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.protocol.internal.PrimitiveSizes; +import edu.umd.cs.findbugs.annotations.CheckReturnValue; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.ArrayList; @@ -164,6 +165,7 @@ static BatchStatementBuilder builder(@NonNull BatchStatement template) { * method. However custom implementations may choose to be mutable and return the same instance. */ @NonNull + @CheckReturnValue BatchStatement setBatchType(@NonNull BatchType newBatchType); /** @@ -180,6 +182,7 @@ static BatchStatementBuilder builder(@NonNull BatchStatement template) { * @see Request#getKeyspace() */ @NonNull + @CheckReturnValue BatchStatement setKeyspace(@Nullable CqlIdentifier newKeyspace); /** @@ -187,6 +190,7 @@ static BatchStatementBuilder builder(@NonNull BatchStatement template) { * setKeyspace(CqlIdentifier.fromCql(newKeyspaceName))}. */ @NonNull + @CheckReturnValue default BatchStatement setKeyspace(@NonNull String newKeyspaceName) { return setKeyspace(CqlIdentifier.fromCql(newKeyspaceName)); } @@ -201,6 +205,7 @@ default BatchStatement setKeyspace(@NonNull String newKeyspaceName) { * method. However custom implementations may choose to be mutable and return the same instance. */ @NonNull + @CheckReturnValue BatchStatement add(@NonNull BatchableStatement statement); /** @@ -213,10 +218,12 @@ default BatchStatement setKeyspace(@NonNull String newKeyspaceName) { * method. However custom implementations may choose to be mutable and return the same instance. */ @NonNull + @CheckReturnValue BatchStatement addAll(@NonNull Iterable> statements); /** @see #addAll(Iterable) */ @NonNull + @CheckReturnValue default BatchStatement addAll(@NonNull BatchableStatement... statements) { return addAll(Arrays.asList(statements)); } @@ -231,6 +238,7 @@ default BatchStatement addAll(@NonNull BatchableStatement... statements) { * method. However custom implementations may choose to be mutable and return the same instance. */ @NonNull + @CheckReturnValue BatchStatement clear(); @Override diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/cql/SimpleStatement.java b/core/src/main/java/com/datastax/oss/driver/api/core/cql/SimpleStatement.java index fd5f456f11c..ef04cd14a5b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/cql/SimpleStatement.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/cql/SimpleStatement.java @@ -28,6 +28,7 @@ import com.datastax.oss.protocol.internal.PrimitiveSizes; import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableList; import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; +import edu.umd.cs.findbugs.annotations.CheckReturnValue; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -197,6 +198,7 @@ static SimpleStatementBuilder builder(@NonNull SimpleStatement template) { * @see #setNamedValuesWithIds(Map) */ @NonNull + @CheckReturnValue SimpleStatement setQuery(@NonNull String newQuery); /** @@ -209,6 +211,7 @@ static SimpleStatementBuilder builder(@NonNull SimpleStatement template) { * @see Request#getKeyspace() */ @NonNull + @CheckReturnValue SimpleStatement setKeyspace(@Nullable CqlIdentifier newKeyspace); /** @@ -216,6 +219,7 @@ static SimpleStatementBuilder builder(@NonNull SimpleStatement template) { * setKeyspace(CqlIdentifier.fromCql(newKeyspaceName))}. */ @NonNull + @CheckReturnValue default SimpleStatement setKeyspace(@NonNull String newKeyspaceName) { return setKeyspace(CqlIdentifier.fromCql(newKeyspaceName)); } @@ -236,6 +240,7 @@ default SimpleStatement setKeyspace(@NonNull String newKeyspaceName) { * @see #setQuery(String) */ @NonNull + @CheckReturnValue SimpleStatement setPositionalValues(@NonNull List newPositionalValues); @NonNull @@ -256,6 +261,7 @@ default SimpleStatement setKeyspace(@NonNull String newKeyspaceName) { * @see #setQuery(String) */ @NonNull + @CheckReturnValue SimpleStatement setNamedValuesWithIds(@NonNull Map newNamedValues); /** @@ -263,6 +269,7 @@ default SimpleStatement setKeyspace(@NonNull String newKeyspaceName) { * converted on the fly with {@link CqlIdentifier#fromCql(String)}. */ @NonNull + @CheckReturnValue default SimpleStatement setNamedValues(@NonNull Map newNamedValues) { return setNamedValuesWithIds(DefaultSimpleStatement.wrapKeys(newNamedValues)); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java b/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java index 594c627e324..d70c56686c5 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/cql/Statement.java @@ -513,6 +513,7 @@ default int getNowInSeconds() { * @see #NO_NOW_IN_SECONDS */ @NonNull + @CheckReturnValue @SuppressWarnings("unchecked") default SelfT setNowInSeconds(int nowInSeconds) { return (SelfT) this; From 8444c79ff843a072e5c1a1d8de5140a47051e2a0 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 16 Sep 2024 16:30:43 -0500 Subject: [PATCH 332/395] Remove "beta" support for Java17 from docs patch by Bret McGuire; reviewed by Andy Tolbert and Alexandre Dutra reference: https://github.com/apache/cassandra-java-driver/pull/1962 --- upgrade_guide/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/upgrade_guide/README.md b/upgrade_guide/README.md index c6df74ffc2a..56d55aaab36 100644 --- a/upgrade_guide/README.md +++ b/upgrade_guide/README.md @@ -19,7 +19,7 @@ under the License. ## Upgrade guide -### NEW VERSION PLACEHOLDER +### 4.18.1 #### Keystore reloading in DefaultSslEngineFactory @@ -32,12 +32,9 @@ This feature is disabled by default for compatibility. To enable, see `keystore- ### 4.17.0 -#### Beta support for Java17 +#### Support for Java17 With the completion of [JAVA-3042](https://datastax-oss.atlassian.net/browse/JAVA-3042) the driver now passes our automated test matrix for Java Driver releases. -While all features function normally when run with Java 17 tests, we do not offer full support for this -platform until we've received feedback from other users in the ecosystem. - If you discover an issue with the Java Driver running on Java 17, please let us know. We will triage and address Java 17 issues. #### Updated API for vector search From a40e7587b175cc198fb533eadabd31e94f837369 Mon Sep 17 00:00:00 2001 From: Christian Aistleitner Date: Thu, 6 Jun 2024 09:14:16 +0200 Subject: [PATCH 333/395] Fix uncaught exception during graceful channel shutdown after exceeding max orphan ids patch by Christian Aistleitner; reviewed by Andy Tolbert, and Bret McGuire for #1938 --- .../core/channel/InFlightHandler.java | 4 +- .../core/channel/InFlightHandlerTest.java | 63 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/InFlightHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/InFlightHandler.java index 9060f80b7cd..90b02f358cd 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/InFlightHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/InFlightHandler.java @@ -199,14 +199,14 @@ private void startGracefulShutdown(ChannelHandlerContext ctx) { LOG.debug("[{}] No pending queries, completing graceful shutdown now", logPrefix); ctx.channel().close(); } else { - // remove heartbeat handler from pipeline if present. + // Remove heartbeat handler from pipeline if present. ChannelHandler heartbeatHandler = ctx.pipeline().get(ChannelFactory.HEARTBEAT_HANDLER_NAME); if (heartbeatHandler != null) { ctx.pipeline().remove(heartbeatHandler); } LOG.debug("[{}] There are pending queries, delaying graceful shutdown", logPrefix); closingGracefully = true; - closeStartedFuture.setSuccess(); + closeStartedFuture.trySuccess(); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/channel/InFlightHandlerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/channel/InFlightHandlerTest.java index 79a575d9eb6..35049e99af1 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/channel/InFlightHandlerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/channel/InFlightHandlerTest.java @@ -39,7 +39,9 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPromise; import java.net.InetSocketAddress; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; @@ -256,7 +258,7 @@ public void should_refuse_new_writes_during_graceful_close() { } @Test - public void should_close_gracefully_if_orphan_ids_above_max_and_pending_requests() { + public void should_close_gracefully_if_orphan_ids_above_max_and_pending_request() { // Given addToPipeline(); // Generate n orphan ids by writing and cancelling the requests: @@ -311,6 +313,65 @@ public void should_close_gracefully_if_orphan_ids_above_max_and_pending_requests assertThat(channel.closeFuture()).isSuccess(); } + @Test + public void should_close_gracefully_if_orphan_ids_above_max_and_multiple_pending_requests() { + // Given + addToPipeline(); + // Generate n orphan ids by writing and cancelling the requests. + for (int i = 0; i < MAX_ORPHAN_IDS; i++) { + when(streamIds.acquire()).thenReturn(i); + MockResponseCallback responseCallback = new MockResponseCallback(); + channel + .writeAndFlush( + new DriverChannel.RequestMessage(QUERY, false, Frame.NO_PAYLOAD, responseCallback)) + .awaitUninterruptibly(); + channel.writeAndFlush(responseCallback).awaitUninterruptibly(); + } + // Generate 3 additional requests that are pending and not cancelled. + List pendingResponseCallbacks = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + when(streamIds.acquire()).thenReturn(MAX_ORPHAN_IDS + i); + MockResponseCallback responseCallback = new MockResponseCallback(); + channel + .writeAndFlush( + new DriverChannel.RequestMessage(QUERY, false, Frame.NO_PAYLOAD, responseCallback)) + .awaitUninterruptibly(); + pendingResponseCallbacks.add(responseCallback); + } + + // When + // Generate the n+1th orphan id that makes us go above the threshold by canceling one if the + // pending requests. + channel.writeAndFlush(pendingResponseCallbacks.remove(0)).awaitUninterruptibly(); + + // Then + // Channel should be closing gracefully but there's no way to observe that from the outside + // besides writing another request and check that it's rejected. + assertThat(channel.closeFuture()).isNotDone(); + ChannelFuture otherWriteFuture = + channel.writeAndFlush( + new DriverChannel.RequestMessage( + QUERY, false, Frame.NO_PAYLOAD, new MockResponseCallback())); + assertThat(otherWriteFuture).isFailed(); + assertThat(otherWriteFuture.cause()) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Channel is closing"); + + // When + // Cancel the remaining pending requests causing the n+ith orphan ids above the threshold. + for (MockResponseCallback pendingResponseCallback : pendingResponseCallbacks) { + ChannelFuture future = channel.writeAndFlush(pendingResponseCallback).awaitUninterruptibly(); + + // Then + // The future should succeed even though the channel has started closing gracefully. + assertThat(future).isSuccess(); + } + + // Then + // The graceful shutdown completes. + assertThat(channel.closeFuture()).isSuccess(); + } + @Test public void should_close_immediately_if_orphan_ids_above_max_and_no_pending_requests() { // Given From eb57fd7d46fb8b84655e66a3ca8e9ceef77b5164 Mon Sep 17 00:00:00 2001 From: janehe Date: Wed, 18 Sep 2024 08:49:37 +0000 Subject: [PATCH 334/395] Build a public CI for Apache Cassandra Java Driver patch by Siyao (Jane) He; reviewed by Mick Semb Wever for CASSANDRA-19832 --- Jenkinsfile-asf | 80 +++++++++++++++++++++++++++++ Jenkinsfile => Jenkinsfile-datastax | 0 ci/create-user.sh | 60 ++++++++++++++++++++++ ci/run-tests.sh | 10 ++++ 4 files changed, 150 insertions(+) create mode 100644 Jenkinsfile-asf rename Jenkinsfile => Jenkinsfile-datastax (100%) create mode 100644 ci/create-user.sh create mode 100755 ci/run-tests.sh diff --git a/Jenkinsfile-asf b/Jenkinsfile-asf new file mode 100644 index 00000000000..a1be4bcd4f6 --- /dev/null +++ b/Jenkinsfile-asf @@ -0,0 +1,80 @@ +#!groovy + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +pipeline { + agent { + label 'cassandra-small' + } + + triggers { + // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) + cron(branchPatternCron().matcher(env.BRANCH_NAME).matches() ? '@weekly' : '') + } + + stages { + stage('Matrix') { + matrix { + axes { + axis { + name 'TEST_JAVA_VERSION' + values 'openjdk@1.8.0-292', 'openjdk@1.11.0-9', 'openjdk@17' + } + axis { + name 'SERVER_VERSION' + values '3.11.17', + '4.0.13', + '5.0-beta1' + } + } + stages { + stage('Tests') { + agent { + label 'cassandra-medium' + } + steps { + script { + executeTests() + junit testResults: '**/target/surefire-reports/TEST-*.xml', allowEmptyResults: true + junit testResults: '**/target/failsafe-reports/TEST-*.xml', allowEmptyResults: true + } + } + } + } + } + } + } +} + +def executeTests() { + def testJavaMajorVersion = (TEST_JAVA_VERSION =~ /@(?:1\.)?(\d+)/)[0][1] + sh """ + container_id=\$(docker run -td -e TEST_JAVA_VERSION=${TEST_JAVA_VERSION} -e SERVER_VERSION=${SERVER_VERSION} -e TEST_JAVA_MAJOR_VERSION=${testJavaMajorVersion} -v \$(pwd):/home/docker/cassandra-java-driver apache.jfrog.io/cassan-docker/apache/cassandra-java-driver-testing-ubuntu2204 'sleep 2h') + docker exec --user root \$container_id bash -c \"sudo bash /home/docker/cassandra-java-driver/ci/create-user.sh docker \$(id -u) \$(id -g) /home/docker/cassandra-java-driver\" + docker exec --user docker \$container_id './cassandra-java-driver/ci/run-tests.sh' + ( nohup docker stop \$container_id >/dev/null 2>/dev/null & ) + """ +} + +// branch pattern for cron +// should match 3.x, 4.x, 4.5.x, etc +def branchPatternCron() { + ~'((\\d+(\\.[\\dx]+)+))' +} diff --git a/Jenkinsfile b/Jenkinsfile-datastax similarity index 100% rename from Jenkinsfile rename to Jenkinsfile-datastax diff --git a/ci/create-user.sh b/ci/create-user.sh new file mode 100644 index 00000000000..fb193df9a00 --- /dev/null +++ b/ci/create-user.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################ +# +# Prep +# +################################ + +if [ "$1" == "-h" ]; then + echo "$0 [-h] " + echo " this script is used internally by other scripts in the same directory to create a user with the running host user's same uid and gid" + exit 1 +fi + +# arguments +username=$1 +uid=$2 +gid=$3 +BUILD_HOME=$4 + +################################ +# +# Main +# +################################ + +# disable git directory ownership checks +su ${username} -c "git config --global safe.directory '*'" + +if grep "^ID=" /etc/os-release | grep -q 'debian\|ubuntu' ; then + deluser docker + adduser --quiet --disabled-login --no-create-home --uid $uid --gecos ${username} ${username} + groupmod --non-unique -g $gid $username + gpasswd -a ${username} sudo >/dev/null +else + adduser --no-create-home --uid $uid ${username} +fi + +# sudo priviledges +echo "${username} ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/${username} +chmod 0440 /etc/sudoers.d/${username} + +# proper permissions +chown -R ${username}:${username} /home/docker +chmod og+wx ${BUILD_HOME} \ No newline at end of file diff --git a/ci/run-tests.sh b/ci/run-tests.sh new file mode 100755 index 00000000000..02a8070e7a9 --- /dev/null +++ b/ci/run-tests.sh @@ -0,0 +1,10 @@ +#!/bin/bash -x + +. ~/.jabba/jabba.sh +. ~/env.txt +cd $(dirname "$(readlink -f "$0")")/.. +printenv | sort +mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true +jabba use ${TEST_JAVA_VERSION} +printenv | sort +mvn -B -V verify -T 1 -Ptest-jdk-${TEST_JAVA_MAJOR_VERSION} -DtestJavaHome=$(jabba which ${TEST_JAVA_VERSION}) -Dccm.version=${SERVER_VERSION} -Dccm.dse=false -Dmaven.test.failure.ignore=true -Dmaven.javadoc.skip=true From 72c729b1ba95695fed467ca3734de7a39a2b3201 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Thu, 3 Oct 2024 09:32:17 +0200 Subject: [PATCH 335/395] CASSANDRA-19932: Allow to define extensions while creating table patch by Lukasz Antoniak; reviewed by Bret McGuire and Chris Lohfink --- .../schema/CreateTableWithOptions.java | 11 +++++ .../schema/RawOptionsWrapper.java | 45 +++++++++++++++++++ .../querybuilder/schema/CreateTableTest.java | 9 +++- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/RawOptionsWrapper.java diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.java index 4dd3193da15..c7bddf575fb 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableWithOptions.java @@ -18,7 +18,11 @@ package com.datastax.oss.driver.api.querybuilder.schema; import com.datastax.oss.driver.api.querybuilder.BuildableQuery; +import com.datastax.oss.driver.internal.querybuilder.schema.RawOptionsWrapper; +import com.datastax.oss.driver.shaded.guava.common.collect.Maps; +import edu.umd.cs.findbugs.annotations.CheckReturnValue; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Map; public interface CreateTableWithOptions extends BuildableQuery, RelationStructure { @@ -26,4 +30,11 @@ public interface CreateTableWithOptions /** Enables COMPACT STORAGE in the CREATE TABLE statement. */ @NonNull CreateTableWithOptions withCompactStorage(); + + /** Attaches custom metadata to CQL table definition. */ + @NonNull + @CheckReturnValue + default CreateTableWithOptions withExtensions(@NonNull Map extensions) { + return withOption("extensions", Maps.transformValues(extensions, RawOptionsWrapper::of)); + } } diff --git a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/RawOptionsWrapper.java b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/RawOptionsWrapper.java new file mode 100644 index 00000000000..64cdb50f887 --- /dev/null +++ b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/schema/RawOptionsWrapper.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.querybuilder.schema; + +import com.datastax.oss.driver.api.core.data.ByteUtils; + +/** + * Wrapper class to indicate that the contained String value should be understood to represent a CQL + * literal that can be included directly in a CQL statement (i.e. without escaping). + */ +public class RawOptionsWrapper { + private final String val; + + private RawOptionsWrapper(String val) { + this.val = val; + } + + public static RawOptionsWrapper of(String val) { + return new RawOptionsWrapper(val); + } + + public static RawOptionsWrapper of(byte[] val) { + return new RawOptionsWrapper(ByteUtils.toHexString(val)); + } + + @Override + public String toString() { + return this.val; + } +} diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java index d32c66f629b..7a5542c51f0 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java @@ -28,6 +28,7 @@ import com.datastax.oss.driver.api.querybuilder.schema.compaction.TimeWindowCompactionStrategy.CompactionWindowUnit; import com.datastax.oss.driver.api.querybuilder.schema.compaction.TimeWindowCompactionStrategy.TimestampResolution; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import java.nio.charset.StandardCharsets; import org.junit.Test; public class CreateTableTest { @@ -169,6 +170,12 @@ public void should_generate_create_table_with_options() { .withComment("Hello world") .withDcLocalReadRepairChance(0.54) .withDefaultTimeToLiveSeconds(86400) + .withExtensions( + ImmutableMap.of( + "key1", + "apache".getBytes(StandardCharsets.UTF_8), + "key2", + "cassandra".getBytes(StandardCharsets.UTF_8))) .withGcGraceSeconds(864000) .withMemtableFlushPeriodInMs(10000) .withMinIndexInterval(1024) @@ -176,7 +183,7 @@ public void should_generate_create_table_with_options() { .withReadRepairChance(0.55) .withSpeculativeRetry("99percentile")) .hasCql( - "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH bloom_filter_fp_chance=0.42 AND cdc=false AND comment='Hello world' AND dclocal_read_repair_chance=0.54 AND default_time_to_live=86400 AND gc_grace_seconds=864000 AND memtable_flush_period_in_ms=10000 AND min_index_interval=1024 AND max_index_interval=4096 AND read_repair_chance=0.55 AND speculative_retry='99percentile'"); + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH bloom_filter_fp_chance=0.42 AND cdc=false AND comment='Hello world' AND dclocal_read_repair_chance=0.54 AND default_time_to_live=86400 AND extensions={'key1':0x617061636865,'key2':0x63617373616e647261} AND gc_grace_seconds=864000 AND memtable_flush_period_in_ms=10000 AND min_index_interval=1024 AND max_index_interval=4096 AND read_repair_chance=0.55 AND speculative_retry='99percentile'"); } @Test From 8ebcd9f85afb548f38e953fb1190d9ff04d8df5a Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Tue, 15 Oct 2024 19:24:00 -0400 Subject: [PATCH 336/395] Fix DefaultSslEngineFactory missing null check on close patch by Abe Ratnofsky; reviewed by Andy Tolbert and Chris Lohfink for CASSANDRA-20001 --- .../oss/driver/internal/core/ssl/DefaultSslEngineFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java index bb95dc738c7..475ec38d578 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java @@ -164,6 +164,6 @@ private ReloadingKeyManagerFactory buildReloadingKeyManagerFactory(DriverExecuti @Override public void close() throws Exception { - kmf.close(); + if (kmf != null) kmf.close(); } } From f98e3433b91b49e0facfbce8e94e01e304714968 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Wed, 2 Oct 2024 18:04:19 -0500 Subject: [PATCH 337/395] Query builder support for NOT CQL syntax patch by Bret McGuire; reviewed by Bret McGuire and Andy Tolbert for CASSANDRA-19930 --- .../relation/ColumnRelationBuilder.java | 24 +++++++ .../relation/InRelationBuilder.java | 32 +++++++++ .../querybuilder/relation/RelationTest.java | 69 ++++++++++++++++++- 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/ColumnRelationBuilder.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/ColumnRelationBuilder.java index 613e72291b7..247d61eaed5 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/ColumnRelationBuilder.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/ColumnRelationBuilder.java @@ -46,4 +46,28 @@ default ResultT contains(@NonNull Term term) { default ResultT containsKey(@NonNull Term term) { return build(" CONTAINS KEY ", term); } + + /** + * Builds a NOT CONTAINS relation for the column. + * + *

    Note that NOT CONTAINS support is only available in Cassandra 5.1 or later. See CASSANDRA-18584 for more + * information. + */ + @NonNull + default ResultT notContains(@NonNull Term term) { + return build(" NOT CONTAINS ", term); + } + + /** + * Builds a NOT CONTAINS KEY relation for the column. + * + *

    Note that NOT CONTAINS KEY support is only available in Cassandra 5.1 or later. See CASSANDRA-18584 for more + * information. + */ + @NonNull + default ResultT notContainsKey(@NonNull Term term) { + return build(" NOT CONTAINS KEY ", term); + } } diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/InRelationBuilder.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/InRelationBuilder.java index d3fc8dce91d..afaa19ff724 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/InRelationBuilder.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/relation/InRelationBuilder.java @@ -50,6 +50,38 @@ default ResultT in(@NonNull Term... alternatives) { return in(Arrays.asList(alternatives)); } + /** + * Builds a NOT IN relation where the whole set of possible values is a bound variable, as in + * {@code NOT IN ?}. + * + *

    Note that NOT IN support is only available in Cassandra 5.1 or later. See CASSANDRA-18584 for more + * information. + */ + @NonNull + default ResultT notIn(@NonNull BindMarker bindMarker) { + return build(" NOT IN ", bindMarker); + } + + /** + * Builds an IN relation where the arguments are the possible values, as in {@code IN (term1, + * term2...)}. + * + *

    Note that NOT IN support is only available in Cassandra 5.1 or later. See CASSANDRA-18584 for more + * information. + */ + @NonNull + default ResultT notIn(@NonNull Iterable alternatives) { + return build(" NOT IN ", QueryBuilder.tuple(alternatives)); + } + + /** Var-arg equivalent of {@link #notIn(Iterable)} . */ + @NonNull + default ResultT notIn(@NonNull Term... alternatives) { + return notIn(Arrays.asList(alternatives)); + } + @NonNull ResultT build(@NonNull String operator, @Nullable Term rightOperand); } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/relation/RelationTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/relation/RelationTest.java index 515a336f5f4..ec121eaa050 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/relation/RelationTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/relation/RelationTest.java @@ -19,10 +19,12 @@ import static com.datastax.oss.driver.api.querybuilder.Assertions.assertThat; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.bindMarker; +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.raw; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.tuple; +import org.assertj.core.util.Lists; import org.junit.Test; public class RelationTest { @@ -42,13 +44,78 @@ public void should_generate_is_not_null_relation() { } @Test - public void should_generate_in_relation() { + public void should_generate_contains_relation() { + assertThat(selectFrom("foo").all().where(Relation.column("k").contains(literal(1)))) + .hasCql("SELECT * FROM foo WHERE k CONTAINS 1"); + } + + @Test + public void should_generate_contains_key_relation() { + assertThat(selectFrom("foo").all().where(Relation.column("k").containsKey(literal(1)))) + .hasCql("SELECT * FROM foo WHERE k CONTAINS KEY 1"); + } + + @Test + public void should_generate_not_contains_relation() { + assertThat(selectFrom("foo").all().where(Relation.column("k").notContains(literal(1)))) + .hasCql("SELECT * FROM foo WHERE k NOT CONTAINS 1"); + } + + @Test + public void should_generate_not_contains_key_relation() { + assertThat(selectFrom("foo").all().where(Relation.column("k").notContainsKey(literal(1)))) + .hasCql("SELECT * FROM foo WHERE k NOT CONTAINS KEY 1"); + } + + @Test + public void should_generate_in_relation_bind_markers() { assertThat(selectFrom("foo").all().where(Relation.column("k").in(bindMarker()))) .hasCql("SELECT * FROM foo WHERE k IN ?"); assertThat(selectFrom("foo").all().where(Relation.column("k").in(bindMarker(), bindMarker()))) .hasCql("SELECT * FROM foo WHERE k IN (?,?)"); } + @Test + public void should_generate_in_relation_terms() { + assertThat( + selectFrom("foo") + .all() + .where( + Relation.column("k") + .in(Lists.newArrayList(literal(1), literal(2), literal(3))))) + .hasCql("SELECT * FROM foo WHERE k IN (1,2,3)"); + assertThat( + selectFrom("foo") + .all() + .where(Relation.column("k").in(literal(1), literal(2), literal(3)))) + .hasCql("SELECT * FROM foo WHERE k IN (1,2,3)"); + } + + @Test + public void should_generate_not_in_relation_bind_markers() { + assertThat(selectFrom("foo").all().where(Relation.column("k").notIn(bindMarker()))) + .hasCql("SELECT * FROM foo WHERE k NOT IN ?"); + assertThat( + selectFrom("foo").all().where(Relation.column("k").notIn(bindMarker(), bindMarker()))) + .hasCql("SELECT * FROM foo WHERE k NOT IN (?,?)"); + } + + @Test + public void should_generate_not_in_relation_terms() { + assertThat( + selectFrom("foo") + .all() + .where( + Relation.column("k") + .notIn(Lists.newArrayList(literal(1), literal(2), literal(3))))) + .hasCql("SELECT * FROM foo WHERE k NOT IN (1,2,3)"); + assertThat( + selectFrom("foo") + .all() + .where(Relation.column("k").notIn(literal(1), literal(2), literal(3)))) + .hasCql("SELECT * FROM foo WHERE k NOT IN (1,2,3)"); + } + @Test public void should_generate_token_relation() { assertThat(selectFrom("foo").all().where(Relation.token("k1", "k2").isEqualTo(bindMarker("t")))) From dfe11a8b671d76be6c4e90981a736325b0e4719b Mon Sep 17 00:00:00 2001 From: Dmitry Kropachev Date: Sat, 14 Sep 2024 06:43:15 -0400 Subject: [PATCH 338/395] Fix CustomCcmRule to drop `CURRENT` flag no matter what If super.after() throws an Exception `CURRENT` flag is never dropped which leads next tests to fail with IllegalStateException("Attempting to use a Ccm rule while another is in use. This is disallowed") Patch by Dmitry Kropachev; reviewed by Andy Tolbert and Bret McGuire for JAVA-3117 --- .../oss/driver/api/testinfra/ccm/CustomCcmRule.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java index cf150b12f55..5ea1bf7ed3c 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CustomCcmRule.java @@ -53,6 +53,7 @@ protected void before() { after(); } catch (Exception e1) { LOG.warn("Error cleaning up CustomCcmRule before() failure", e1); + e.addSuppressed(e1); } throw e; } @@ -64,8 +65,11 @@ protected void before() { @Override protected void after() { - super.after(); - CURRENT.compareAndSet(this, null); + try { + super.after(); + } finally { + CURRENT.compareAndSet(this, null); + } } public CcmBridge getCcmBridge() { From 787783770b0a624f4e58d35aeff16eff8bcddc02 Mon Sep 17 00:00:00 2001 From: janehe Date: Wed, 30 Oct 2024 11:34:11 -0700 Subject: [PATCH 339/395] JAVA-3051: Memory leak patch by Jane He; reviewed by Alexandre Dutra and Bret McGuire for JAVA-3051 --- .../core/control/ControlConnection.java | 21 ++-- .../DefaultLoadBalancingPolicy.java | 96 ++++++++++++------- .../metadata/LoadBalancingPolicyWrapper.java | 12 ++- .../core/metrics/AbstractMetricUpdater.java | 5 +- .../internal/core/session/DefaultSession.java | 14 ++- .../util/concurrent/ReplayingEventFilter.java | 1 + ...faultLoadBalancingPolicyQueryPlanTest.java | 9 +- ...LoadBalancingPolicyRequestTrackerTest.java | 52 +++++----- 8 files changed, 126 insertions(+), 84 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java b/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java index 5ee9c6e7810..5c29a9b704b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/control/ControlConnection.java @@ -253,8 +253,8 @@ private class SingleThreaded { private final Reconnection reconnection; private DriverChannelOptions channelOptions; // The last events received for each node - private final Map lastDistanceEvents = new WeakHashMap<>(); - private final Map lastStateEvents = new WeakHashMap<>(); + private final Map lastNodeDistance = new WeakHashMap<>(); + private final Map lastNodeState = new WeakHashMap<>(); private SingleThreaded(InternalDriverContext context) { this.context = context; @@ -366,8 +366,8 @@ private void connect( .whenCompleteAsync( (channel, error) -> { try { - DistanceEvent lastDistanceEvent = lastDistanceEvents.get(node); - NodeStateEvent lastStateEvent = lastStateEvents.get(node); + NodeDistance lastDistance = lastNodeDistance.get(node); + NodeState lastState = lastNodeState.get(node); if (error != null) { if (closeWasCalled || initFuture.isCancelled()) { onSuccess.run(); // abort, we don't really care about the result @@ -406,8 +406,7 @@ private void connect( channel); channel.forceClose(); onSuccess.run(); - } else if (lastDistanceEvent != null - && lastDistanceEvent.distance == NodeDistance.IGNORED) { + } else if (lastDistance == NodeDistance.IGNORED) { LOG.debug( "[{}] New channel opened ({}) but node became ignored, " + "closing and trying next node", @@ -415,9 +414,9 @@ private void connect( channel); channel.forceClose(); connect(nodes, errors, onSuccess, onFailure); - } else if (lastStateEvent != null - && (lastStateEvent.newState == null /*(removed)*/ - || lastStateEvent.newState == NodeState.FORCED_DOWN)) { + } else if (lastNodeState.containsKey(node) + && (lastState == null /*(removed)*/ + || lastState == NodeState.FORCED_DOWN)) { LOG.debug( "[{}] New channel opened ({}) but node was removed or forced down, " + "closing and trying next node", @@ -534,7 +533,7 @@ private void reconnectNow() { private void onDistanceEvent(DistanceEvent event) { assert adminExecutor.inEventLoop(); - this.lastDistanceEvents.put(event.node, event); + this.lastNodeDistance.put(event.node, event.distance); if (event.distance == NodeDistance.IGNORED && channel != null && !channel.closeFuture().isDone() @@ -549,7 +548,7 @@ private void onDistanceEvent(DistanceEvent event) { private void onStateEvent(NodeStateEvent event) { assert adminExecutor.inEventLoop(); - this.lastStateEvents.put(event.node, event); + this.lastNodeState.put(event.node, event.newState); if ((event.newState == null /*(removed)*/ || event.newState == NodeState.FORCED_DOWN) && channel != null && !channel.closeFuture().isDone() diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java index 47edcdfe53e..0f03cbb3643 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java @@ -33,15 +33,19 @@ import com.datastax.oss.driver.internal.core.util.ArrayUtils; import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import com.datastax.oss.driver.shaded.guava.common.collect.MapMaker; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.BitSet; import java.util.Map; import java.util.Optional; +import java.util.OptionalLong; import java.util.Queue; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicLongArray; import net.jcip.annotations.ThreadSafe; @@ -96,7 +100,7 @@ public class DefaultLoadBalancingPolicy extends BasicLoadBalancingPolicy impleme private static final int MAX_IN_FLIGHT_THRESHOLD = 10; private static final long RESPONSE_COUNT_RESET_INTERVAL_NANOS = MILLISECONDS.toNanos(200); - protected final Map responseTimes = new ConcurrentHashMap<>(); + protected final ConcurrentMap responseTimes; protected final Map upTimes = new ConcurrentHashMap<>(); private final boolean avoidSlowReplicas; @@ -104,6 +108,7 @@ public DefaultLoadBalancingPolicy(@NonNull DriverContext context, @NonNull Strin super(context, profileName); this.avoidSlowReplicas = profile.getBoolean(DefaultDriverOption.LOAD_BALANCING_POLICY_SLOW_AVOIDANCE, true); + this.responseTimes = new MapMaker().weakKeys().makeMap(); } @NonNull @@ -274,40 +279,19 @@ protected boolean isBusy(@NonNull Node node, @NonNull Session session) { } protected boolean isResponseRateInsufficient(@NonNull Node node, long now) { - // response rate is considered insufficient when less than 2 responses were obtained in - // the past interval delimited by RESPONSE_COUNT_RESET_INTERVAL_NANOS. - if (responseTimes.containsKey(node)) { - AtomicLongArray array = responseTimes.get(node); - if (array.length() == 2) { - long threshold = now - RESPONSE_COUNT_RESET_INTERVAL_NANOS; - long leastRecent = array.get(0); - return leastRecent - threshold < 0; - } - } - return true; + NodeResponseRateSample sample = responseTimes.get(node); + return !(sample == null || sample.hasSufficientResponses(now)); } + /** + * Synchronously updates the response times for the given node. It is synchronous because the + * {@link #DefaultLoadBalancingPolicy(com.datastax.oss.driver.api.core.context.DriverContext, + * java.lang.String) CacheLoader.load} assigned is synchronous. + * + * @param node The node to update. + */ protected void updateResponseTimes(@NonNull Node node) { - responseTimes.compute( - node, - (n, array) -> { - // The array stores at most two timestamps, since we don't need more; - // the first one is always the least recent one, and hence the one to inspect. - long now = nanoTime(); - if (array == null) { - array = new AtomicLongArray(1); - array.set(0, now); - } else if (array.length() == 1) { - long previous = array.get(0); - array = new AtomicLongArray(2); - array.set(0, previous); - array.set(1, now); - } else { - array.set(0, array.get(1)); - array.set(1, now); - } - return array; - }); + this.responseTimes.compute(node, (k, v) -> v == null ? new NodeResponseRateSample() : v.next()); } protected int getInFlight(@NonNull Node node, @NonNull Session session) { @@ -318,4 +302,52 @@ protected int getInFlight(@NonNull Node node, @NonNull Session session) { // processing them). return (pool == null) ? 0 : pool.getInFlight(); } + + protected class NodeResponseRateSample { + + @VisibleForTesting protected final long oldest; + @VisibleForTesting protected final OptionalLong newest; + + private NodeResponseRateSample() { + long now = nanoTime(); + this.oldest = now; + this.newest = OptionalLong.empty(); + } + + private NodeResponseRateSample(long oldestSample) { + this(oldestSample, nanoTime()); + } + + private NodeResponseRateSample(long oldestSample, long newestSample) { + this.oldest = oldestSample; + this.newest = OptionalLong.of(newestSample); + } + + @VisibleForTesting + protected NodeResponseRateSample(AtomicLongArray times) { + assert times.length() >= 1; + this.oldest = times.get(0); + this.newest = (times.length() > 1) ? OptionalLong.of(times.get(1)) : OptionalLong.empty(); + } + + // Our newest sample becomes the oldest in the next generation + private NodeResponseRateSample next() { + return new NodeResponseRateSample(this.getNewestValidSample(), nanoTime()); + } + + // If we have a pair of values return the newest, otherwise we have just one value... so just + // return it + private long getNewestValidSample() { + return this.newest.orElse(this.oldest); + } + + // response rate is considered insufficient when less than 2 responses were obtained in + // the past interval delimited by RESPONSE_COUNT_RESET_INTERVAL_NANOS. + private boolean hasSufficientResponses(long now) { + // If we only have one sample it's an automatic failure + if (!this.newest.isPresent()) return true; + long threshold = now - RESPONSE_COUNT_RESET_INTERVAL_NANOS; + return this.oldest - threshold >= 0; + } + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java index 20d045d4e72..5c8473a3b67 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/LoadBalancingPolicyWrapper.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Queue; import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; @@ -105,7 +106,7 @@ public LoadBalancingPolicyWrapper( // Just an alias to make the rest of the code more readable this.policies = reporters.keySet(); - this.distances = new HashMap<>(); + this.distances = new WeakHashMap<>(); this.logPrefix = context.getSessionName(); context.getEventBus().register(NodeStateEvent.class, this::onNodeStateEvent); @@ -172,6 +173,7 @@ private void onNodeStateEvent(NodeStateEvent event) { // once it has gone through the filter private void processNodeStateEvent(NodeStateEvent event) { + DefaultNode node = event.node; switch (stateRef.get()) { case BEFORE_INIT: case DURING_INIT: @@ -181,13 +183,13 @@ private void processNodeStateEvent(NodeStateEvent event) { case RUNNING: for (LoadBalancingPolicy policy : policies) { if (event.newState == NodeState.UP) { - policy.onUp(event.node); + policy.onUp(node); } else if (event.newState == NodeState.DOWN || event.newState == NodeState.FORCED_DOWN) { - policy.onDown(event.node); + policy.onDown(node); } else if (event.newState == NodeState.UNKNOWN) { - policy.onAdd(event.node); + policy.onAdd(node); } else if (event.newState == null) { - policy.onRemove(event.node); + policy.onRemove(node); } else { LOG.warn("[{}] Unsupported event: {}", logPrefix, event); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java index 5e2392a2e7f..3d7dc50a7c0 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metrics/AbstractMetricUpdater.java @@ -173,9 +173,8 @@ protected Timeout newTimeout() { .getTimer() .newTimeout( t -> { - if (t.isExpired()) { - clearMetrics(); - } + clearMetrics(); + cancelMetricsExpirationTimeout(); }, expireAfter.toNanos(), TimeUnit.NANOSECONDS); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java index 6f063ae9a50..b795c30fce7 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/DefaultSession.java @@ -527,14 +527,18 @@ private void notifyListeners() { private void onNodeStateChanged(NodeStateEvent event) { assert adminExecutor.inEventLoop(); - if (event.newState == null) { - context.getNodeStateListener().onRemove(event.node); + DefaultNode node = event.node; + if (node == null) { + LOG.debug( + "[{}] Node for this event was removed, ignoring state change: {}", logPrefix, event); + } else if (event.newState == null) { + context.getNodeStateListener().onRemove(node); } else if (event.oldState == null && event.newState == NodeState.UNKNOWN) { - context.getNodeStateListener().onAdd(event.node); + context.getNodeStateListener().onAdd(node); } else if (event.newState == NodeState.UP) { - context.getNodeStateListener().onUp(event.node); + context.getNodeStateListener().onUp(node); } else if (event.newState == NodeState.DOWN || event.newState == NodeState.FORCED_DOWN) { - context.getNodeStateListener().onDown(event.node); + context.getNodeStateListener().onDown(node); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java index 12679db7ff0..27ca1b6ff42 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/ReplayingEventFilter.java @@ -82,6 +82,7 @@ public void markReady() { consumer.accept(event); } } finally { + recordedEvents.clear(); stateLock.writeLock().unlock(); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java index 6098653bc2e..fff86a1b750 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyQueryPlanTest.java @@ -203,7 +203,10 @@ public void should_prioritize_and_shuffle_3_or_more_replicas_when_first_unhealth given(pool3.getInFlight()).willReturn(0); given(pool5.getInFlight()).willReturn(0); - dsePolicy.responseTimes.put(node1, new AtomicLongArray(new long[] {T0, T0})); // unhealthy + dsePolicy.responseTimes.put( + node1, + dsePolicy + .new NodeResponseRateSample(new AtomicLongArray(new long[] {T0, T0}))); // unhealthy // When Queue plan1 = dsePolicy.newQueryPlan(request, session); @@ -232,7 +235,9 @@ public void should_prioritize_and_shuffle_3_or_more_replicas_when_first_unhealth given(pool3.getInFlight()).willReturn(0); given(pool5.getInFlight()).willReturn(0); - dsePolicy.responseTimes.put(node1, new AtomicLongArray(new long[] {T1, T1})); // healthy + dsePolicy.responseTimes.put( + node1, + dsePolicy.new NodeResponseRateSample(new AtomicLongArray(new long[] {T1, T1}))); // healthy // When Queue plan1 = dsePolicy.newQueryPlan(request, session); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java index bcc6439a2a5..757af43ef67 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicyRequestTrackerTest.java @@ -69,11 +69,11 @@ public void should_record_first_response_time_on_node_success() { // Then assertThat(policy.responseTimes) - .hasEntrySatisfying(node1, value -> assertThat(value.get(0)).isEqualTo(123L)) + .hasEntrySatisfying(node1, value -> assertThat(value.oldest).isEqualTo(123L)) .doesNotContainKeys(node2, node3); - assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isTrue(); + assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isFalse(); } @Test @@ -91,13 +91,13 @@ public void should_record_second_response_time_on_node_success() { node1, value -> { // oldest value first - assertThat(value.get(0)).isEqualTo(123); - assertThat(value.get(1)).isEqualTo(456); + assertThat(value.oldest).isEqualTo(123); + assertThat(value.newest.getAsLong()).isEqualTo(456); }) .doesNotContainKeys(node2, node3); assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isFalse(); - assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isTrue(); + assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isFalse(); } @Test @@ -116,14 +116,14 @@ public void should_record_further_response_times_on_node_success() { node1, value -> { // values should rotate left (bubble up) - assertThat(value.get(0)).isEqualTo(456); - assertThat(value.get(1)).isEqualTo(789); + assertThat(value.oldest).isEqualTo(456); + assertThat(value.newest.getAsLong()).isEqualTo(789); }) - .hasEntrySatisfying(node2, value -> assertThat(value.get(0)).isEqualTo(789)) + .hasEntrySatisfying(node2, value -> assertThat(value.oldest).isEqualTo(789)) .doesNotContainKey(node3); assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isFalse(); - assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isTrue(); + assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isFalse(); } @Test @@ -137,11 +137,11 @@ public void should_record_first_response_time_on_node_error() { // Then assertThat(policy.responseTimes) - .hasEntrySatisfying(node1, value -> assertThat(value.get(0)).isEqualTo(123L)) + .hasEntrySatisfying(node1, value -> assertThat(value.oldest).isEqualTo(123L)) .doesNotContainKeys(node2, node3); - assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isTrue(); + assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isFalse(); } @Test @@ -160,13 +160,13 @@ public void should_record_second_response_time_on_node_error() { node1, value -> { // oldest value first - assertThat(value.get(0)).isEqualTo(123); - assertThat(value.get(1)).isEqualTo(456); + assertThat(value.oldest).isEqualTo(123); + assertThat(value.newest.getAsLong()).isEqualTo(456); }) .doesNotContainKeys(node2, node3); assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isFalse(); - assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isTrue(); + assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isFalse(); } @Test @@ -186,13 +186,13 @@ public void should_record_further_response_times_on_node_error() { node1, value -> { // values should rotate left (bubble up) - assertThat(value.get(0)).isEqualTo(456); - assertThat(value.get(1)).isEqualTo(789); + assertThat(value.oldest).isEqualTo(456); + assertThat(value.newest.getAsLong()).isEqualTo(789); }) - .hasEntrySatisfying(node2, value -> assertThat(value.get(0)).isEqualTo(789)) + .hasEntrySatisfying(node2, value -> assertThat(value.oldest).isEqualTo(789)) .doesNotContainKey(node3); assertThat(policy.isResponseRateInsufficient(node1, nextNanoTime)).isFalse(); - assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isTrue(); - assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isTrue(); + assertThat(policy.isResponseRateInsufficient(node2, nextNanoTime)).isFalse(); + assertThat(policy.isResponseRateInsufficient(node3, nextNanoTime)).isFalse(); } } From a4175f33e43344fd1b092aae332ed5979a1bd831 Mon Sep 17 00:00:00 2001 From: "Siyao (Jane) He" Date: Mon, 28 Oct 2024 14:44:22 -0700 Subject: [PATCH 340/395] Automate latest Cassandra versions when running CI patch by Siyao (Jane) He; reviewed by Mick Semb Wever for CASSJAVA-25 --- Jenkinsfile-asf | 7 ++++--- ci/run-tests.sh | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile-asf b/Jenkinsfile-asf index a1be4bcd4f6..0217d0455d6 100644 --- a/Jenkinsfile-asf +++ b/Jenkinsfile-asf @@ -39,9 +39,10 @@ pipeline { } axis { name 'SERVER_VERSION' - values '3.11.17', - '4.0.13', - '5.0-beta1' + values '3.11', + '4.0', + '4.1', + '5.0' } } stages { diff --git a/ci/run-tests.sh b/ci/run-tests.sh index 02a8070e7a9..5268bdd7113 100755 --- a/ci/run-tests.sh +++ b/ci/run-tests.sh @@ -6,5 +6,7 @@ cd $(dirname "$(readlink -f "$0")")/.. printenv | sort mvn -B -V install -DskipTests -Dmaven.javadoc.skip=true jabba use ${TEST_JAVA_VERSION} +# Find out the latest patch version of Cassandra +PATCH_SERVER_VERSION=$(curl -s https://downloads.apache.org/cassandra/ | grep -oP '(?<=href=\")[0-9]+\.[0-9]+\.[0-9]+(?=)' | sort -rV | uniq -w 3 | grep $SERVER_VERSION) printenv | sort -mvn -B -V verify -T 1 -Ptest-jdk-${TEST_JAVA_MAJOR_VERSION} -DtestJavaHome=$(jabba which ${TEST_JAVA_VERSION}) -Dccm.version=${SERVER_VERSION} -Dccm.dse=false -Dmaven.test.failure.ignore=true -Dmaven.javadoc.skip=true +mvn -B -V verify -T 1 -Ptest-jdk-${TEST_JAVA_MAJOR_VERSION} -DtestJavaHome=$(jabba which ${TEST_JAVA_VERSION}) -Dccm.version=${PATCH_SERVER_VERSION} -Dccm.dse=false -Dmaven.test.failure.ignore=true -Dmaven.javadoc.skip=true From 01c6151cd4a3c1dbbd4d1251fb453305385668e1 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Sun, 8 Sep 2024 15:06:53 +0200 Subject: [PATCH 341/395] Refactor integration tests to support multiple C* distributions. Test with DataStax HCD 1.0.0 patch by Lukasz Antoniak; reviewed by Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1958 --- Jenkinsfile-datastax | 34 +++- .../datastax/oss/driver/api/core/Version.java | 1 + .../cql/continuous/ContinuousPagingIT.java | 8 +- .../remote/GraphTraversalRemoteITBase.java | 5 +- .../graph/statement/GraphTraversalITBase.java | 5 +- .../schema/DseAggregateMetadataIT.java | 6 +- .../schema/DseFunctionMetadataIT.java | 6 +- .../core/compression/DirectCompressionIT.java | 6 +- .../core/compression/HeapCompressionIT.java | 3 +- .../oss/driver/core/cql/QueryTraceIT.java | 3 +- .../oss/driver/core/metadata/DescribeIT.java | 28 +-- .../driver/core/metadata/NodeMetadataIT.java | 7 +- .../driver/core/metadata/SchemaChangesIT.java | 5 +- .../oss/driver/core/metadata/SchemaIT.java | 8 +- .../oss/driver/mapper/DeleteReactiveIT.java | 5 +- .../oss/driver/mapper/InventoryITBase.java | 11 +- .../src/test/resources/DescribeIT/hcd/1.0.cql | 186 ++++++++++++++++++ osgi-tests/README.md | 4 +- .../osgi/support/CcmStagedReactor.java | 8 +- test-infra/revapi.json | 21 ++ .../driver/api/testinfra/ccm/BaseCcmRule.java | 24 ++- .../driver/api/testinfra/ccm/CcmBridge.java | 83 ++++---- .../DefaultCcmBridgeBuilderCustomizer.java | 8 +- .../ccm/DistributionCassandraVersions.java | 57 ++++++ .../requirement/BackendRequirementRule.java | 2 +- .../testinfra/requirement/BackendType.java | 13 +- .../api/testinfra/session/SessionRule.java | 13 +- 27 files changed, 439 insertions(+), 121 deletions(-) create mode 100644 integration-tests/src/test/resources/DescribeIT/hcd/1.0.cql create mode 100644 test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DistributionCassandraVersions.java diff --git a/Jenkinsfile-datastax b/Jenkinsfile-datastax index 4cc20d79604..af3faafee20 100644 --- a/Jenkinsfile-datastax +++ b/Jenkinsfile-datastax @@ -61,7 +61,7 @@ def initializeEnvironment() { . ${JABBA_SHELL} jabba which 1.8''', returnStdout: true).trim() - sh label: 'Download Apache CassandraⓇ or DataStax Enterprise',script: '''#!/bin/bash -le + sh label: 'Download Apache CassandraⓇ, DataStax Enterprise or DataStax HCD ',script: '''#!/bin/bash -le . ${JABBA_SHELL} jabba use 1.8 . ${CCM_ENVIRONMENT_SHELL} ${SERVER_VERSION} @@ -75,13 +75,26 @@ CCM_CASSANDRA_VERSION=${DSE_FIXED_VERSION} # maintain for backwards compatibilit CCM_VERSION=${DSE_FIXED_VERSION} CCM_SERVER_TYPE=dse DSE_VERSION=${DSE_FIXED_VERSION} -CCM_IS_DSE=true CCM_BRANCH=${DSE_FIXED_VERSION} DSE_BRANCH=${DSE_FIXED_VERSION} ENVIRONMENT_EOF ''' } + if (env.SERVER_VERSION.split('-')[0] == 'hcd') { + env.HCD_FIXED_VERSION = env.SERVER_VERSION.split('-')[1] + sh label: 'Update environment for DataStax HCD', script: '''#!/bin/bash -le + cat >> ${HOME}/environment.txt << ENVIRONMENT_EOF +CCM_CASSANDRA_VERSION=${HCD_FIXED_VERSION} # maintain for backwards compatibility +CCM_VERSION=${HCD_FIXED_VERSION} +CCM_SERVER_TYPE=hcd +HCD_VERSION=${HCD_FIXED_VERSION} +CCM_BRANCH=${HCD_FIXED_VERSION} +HCD_BRANCH=${HCD_FIXED_VERSION} +ENVIRONMENT_EOF + ''' + } + sh label: 'Display Java and environment information',script: '''#!/bin/bash -le # Load CCM environment variables set -o allexport @@ -144,7 +157,7 @@ def executeTests() { -Dmaven.test.failure.ignore=true \ -Dmaven.javadoc.skip=${SKIP_JAVADOCS} \ -Dccm.version=${CCM_CASSANDRA_VERSION} \ - -Dccm.dse=${CCM_IS_DSE} \ + -Dccm.distribution=${CCM_SERVER_TYPE:cassandra} \ -Dproxy.path=${HOME}/proxy \ ${SERIAL_ITS_ARGUMENT} \ ${ISOLATED_ITS_ARGUMENT} \ @@ -269,6 +282,7 @@ pipeline { 'dse-6.7.17', // Previous DataStax Enterprise 'dse-6.8.30', // Current DataStax Enterprise 'dse-6.9.0', // Current DataStax Enterprise + 'hcd-1.0.0', // Current DataStax HCD 'ALL'], description: '''Apache Cassandra® and DataStax Enterprise server version to use for adhoc BUILD-AND-EXECUTE-TESTS builds @@ -330,6 +344,10 @@ pipeline { + + + +
    dse-6.9.0 DataStax Enterprise v6.9.x
    hcd-1.0.0DataStax HCD v1.0.x
    ''') choice( name: 'ADHOC_BUILD_AND_EXECUTE_TESTS_JABBA_VERSION', @@ -421,9 +439,9 @@ pipeline { H 2 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 4.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 # Every weeknight (Monday - Friday) around 12:00 PM noon ### JDK11 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 - H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0 hcd-1.0.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 ### JDK17 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 - H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0 hcd-1.0.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 """ : "") } @@ -460,7 +478,8 @@ pipeline { values '3.11', // Latest stable Apache CassandraⓇ '4.1', // Development Apache CassandraⓇ 'dse-6.8.30', // Current DataStax Enterprise - 'dse-6.9.0' // Current DataStax Enterprise + 'dse-6.9.0', // Current DataStax Enterprise + 'hcd-1.0.0' // Current DataStax HCD } axis { name 'JABBA_VERSION' @@ -578,7 +597,8 @@ pipeline { 'dse-6.0.18', // Previous DataStax Enterprise 'dse-6.7.17', // Previous DataStax Enterprise 'dse-6.8.30', // Current DataStax Enterprise - 'dse-6.9.0' // Current DataStax Enterprise + 'dse-6.9.0', // Current DataStax Enterprise + 'hcd-1.0.0' // Current DataStax HCD } } when { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/Version.java b/core/src/main/java/com/datastax/oss/driver/api/core/Version.java index 4de006da268..52751e02984 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/Version.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/Version.java @@ -48,6 +48,7 @@ public class Version implements Comparable, Serializable { private static final Pattern pattern = Pattern.compile(VERSION_REGEXP); + @NonNull public static final Version V1_0_0 = Objects.requireNonNull(parse("1.0.0")); @NonNull public static final Version V2_1_0 = Objects.requireNonNull(parse("2.1.0")); @NonNull public static final Version V2_2_0 = Objects.requireNonNull(parse("2.2.0")); @NonNull public static final Version V3_0_0 = Objects.requireNonNull(parse("3.0.0")); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java index 24ee5c0373d..45cc84f0719 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/cql/continuous/ContinuousPagingIT.java @@ -46,7 +46,6 @@ import java.time.Duration; import java.util.Collections; import java.util.Iterator; -import java.util.Objects; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -281,11 +280,8 @@ public void prepared_statement_paging_should_be_resilient_to_schema_change() { // dropped. Row row = it.next(); assertThat(row.getString("k")).isNotNull(); - if (ccmRule - .getDseVersion() - .orElseThrow(IllegalStateException::new) - .compareTo(Objects.requireNonNull(Version.parse("6.0.0"))) - >= 0) { + if (ccmRule.isDistributionOf( + BackendType.DSE, (dist, cass) -> dist.compareTo(Version.parse("6.0.0")) >= 0)) { // DSE 6 only, v should be null here since dropped. // Not reliable for 5.1 since we may have gotten page queued before schema changed. assertThat(row.isNull("v")).isTrue(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java index 69949951378..3db8a7d1a12 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/remote/GraphTraversalRemoteITBase.java @@ -30,6 +30,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; +import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; import com.datastax.oss.driver.api.testinfra.requirement.BackendType; @@ -643,9 +644,9 @@ public void should_allow_use_of_dsl_graph_binary() { */ @Test public void should_return_correct_results_when_bulked() { - Optional dseVersion = ccmRule().getCcmBridge().getDseVersion(); Assumptions.assumeThat( - dseVersion.isPresent() && dseVersion.get().compareTo(Version.parse("5.1.2")) > 0) + CcmBridge.isDistributionOf( + BackendType.DSE, (dist, cass) -> dist.compareTo(Version.parse("5.1.2")) > 0)) .isTrue(); List results = graphTraversalSource().E().label().barrier().toList(); diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalITBase.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalITBase.java index 98d9ccf1b80..5bcb01bc165 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalITBase.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/graph/statement/GraphTraversalITBase.java @@ -36,7 +36,9 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException; import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; import java.util.List; @@ -598,7 +600,8 @@ public void should_allow_use_of_dsl_graph_binary() throws Exception { @Test public void should_return_correct_results_when_bulked() { Assumptions.assumeThat( - ccmRule().getCcmBridge().getDseVersion().get().compareTo(Version.parse("5.1.2")) > 0) + CcmBridge.isDistributionOf( + BackendType.DSE, (dist, cass) -> dist.compareTo(Version.parse("5.1.2")) > 0)) .isTrue(); GraphResultSet rs = diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java index b0e989e86a3..4c899fa5e63 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseAggregateMetadataIT.java @@ -106,9 +106,9 @@ public void should_parse_aggregate_with_deterministic() { } private static boolean isDse6OrHigher() { - assumeThat(CCM_RULE.getDseVersion()) + assumeThat(CCM_RULE.isDistributionOf(BackendType.DSE)) .describedAs("DSE required for DseFunctionMetadata tests") - .isPresent(); - return CCM_RULE.getDseVersion().get().compareTo(DSE_6_0_0) >= 0; + .isTrue(); + return CCM_RULE.getDistributionVersion().compareTo(DSE_6_0_0) >= 0; } } diff --git a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java index 53e2d1be8f8..53559a66b1b 100644 --- a/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/dse/driver/api/core/metadata/schema/DseFunctionMetadataIT.java @@ -233,9 +233,9 @@ public void should_parse_function_with_deterministic_and_monotonic_on() { } private static boolean isDse6OrHigher() { - assumeThat(CCM_RULE.getDseVersion()) + assumeThat(CCM_RULE.isDistributionOf(BackendType.DSE)) .describedAs("DSE required for DseFunctionMetadata tests") - .isPresent(); - return CCM_RULE.getDseVersion().get().compareTo(DSE_6_0_0) >= 0; + .isTrue(); + return CCM_RULE.getDistributionVersion().compareTo(DSE_6_0_0) >= 0; } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java index 51f71f85b5c..3dad08f4de6 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/DirectCompressionIT.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -75,8 +76,9 @@ public static void setup() { public void should_execute_queries_with_snappy_compression() throws Exception { Assume.assumeTrue( "Snappy is not supported in OSS C* 4.0+ with protocol v5", - CCM_RULE.getDseVersion().isPresent() - || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0); + !CCM_RULE.isDistributionOf(BackendType.HCD) + && (CCM_RULE.isDistributionOf(BackendType.DSE) + || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0)); createAndCheckCluster("snappy"); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java index 466a9d87ac3..a14c3b29b21 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/compression/HeapCompressionIT.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.IsolatedTests; @@ -79,7 +80,7 @@ public static void setup() { public void should_execute_queries_with_snappy_compression() throws Exception { Assume.assumeTrue( "Snappy is not supported in OSS C* 4.0+ with protocol v5", - CCM_RULE.getDseVersion().isPresent() + CCM_RULE.isDistributionOf(BackendType.DSE) || CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) < 0); createAndCheckCluster("snappy"); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java index f4ac85d6629..37a600efbc4 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/QueryTraceIT.java @@ -28,6 +28,7 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.categories.ParallelizableTests; import java.net.InetAddress; @@ -82,7 +83,7 @@ public void should_fetch_trace_when_tracing_enabled() { InetAddress nodeAddress = ((InetSocketAddress) contactPoint.resolve()).getAddress(); boolean expectPorts = CCM_RULE.getCassandraVersion().nextStable().compareTo(Version.V4_0_0) >= 0 - && !CCM_RULE.getDseVersion().isPresent(); + && !CCM_RULE.isDistributionOf(BackendType.DSE); QueryTrace queryTrace = executionInfo.getQueryTrace(); assertThat(queryTrace.getTracingId()).isEqualTo(executionInfo.getTracingId()); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java index 9fbf5e355eb..4d6c2a7a3b1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/DescribeIT.java @@ -29,6 +29,7 @@ import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.datastax.oss.driver.categories.ParallelizableTests; @@ -37,12 +38,14 @@ import com.datastax.oss.driver.internal.core.metadata.schema.DefaultTableMetadata; import com.datastax.oss.driver.shaded.guava.common.base.Charsets; import com.datastax.oss.driver.shaded.guava.common.base.Splitter; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.google.common.io.Files; import java.io.File; import java.io.IOException; import java.net.URL; import java.time.Duration; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; import org.junit.BeforeClass; @@ -79,17 +82,23 @@ public class DescribeIT { Splitter.on(Pattern.compile(";\n")).omitEmptyStrings(); private static Version serverVersion; - private static boolean isDse; + + private static final Map scriptFileForBackend = + ImmutableMap.builder() + .put(BackendType.CASSANDRA, "DescribeIT/oss") + .put(BackendType.DSE, "DescribeIT/dse") + .put(BackendType.HCD, "DescribeIT/hcd") + .build(); private static File scriptFile; private static String scriptContents; @BeforeClass public static void setup() { - Optional dseVersion = CCM_RULE.getDseVersion(); - isDse = dseVersion.isPresent(); serverVersion = - isDse ? dseVersion.get().nextStable() : CCM_RULE.getCassandraVersion().nextStable(); + CCM_RULE.isDistributionOf(BackendType.CASSANDRA) + ? CCM_RULE.getCassandraVersion().nextStable() + : CCM_RULE.getDistributionVersion().nextStable(); scriptFile = getScriptFile(); assertThat(scriptFile).exists(); @@ -114,12 +123,12 @@ public void describe_output_should_match_creation_script() throws Exception { "Describe output doesn't match create statements, " + "maybe you need to add a new script in integration-tests/src/test/resources. " + "Server version = %s %s, used script = %s", - isDse ? "DSE" : "Cassandra", serverVersion, scriptFile) + CCM_RULE.getDistribution(), serverVersion, scriptFile) .isEqualTo(scriptContents); } private boolean atLeastVersion(Version dseVersion, Version ossVersion) { - Version comparison = isDse ? dseVersion : ossVersion; + Version comparison = CCM_RULE.isDistributionOf(BackendType.DSE) ? dseVersion : ossVersion; return serverVersion.compareTo(comparison) >= 0; } @@ -138,11 +147,9 @@ public void keyspace_metadata_should_be_serializable() throws Exception { assertThat(ks.getUserDefinedTypes()).isNotEmpty(); assertThat(ks.getTables()).isNotEmpty(); if (atLeastVersion(Version.V5_0_0, Version.V3_0_0)) { - assertThat(ks.getViews()).isNotEmpty(); } if (atLeastVersion(Version.V5_0_0, Version.V2_2_0)) { - assertThat(ks.getFunctions()).isNotEmpty(); assertThat(ks.getAggregates()).isNotEmpty(); } @@ -177,7 +184,7 @@ private static File getScriptFile() { logbackTestUrl); } File resourcesDir = new File(logbackTestUrl.getFile()).getParentFile(); - File scriptsDir = new File(resourcesDir, isDse ? "DescribeIT/dse" : "DescribeIT/oss"); + File scriptsDir = new File(resourcesDir, scriptFileForBackend.get(CCM_RULE.getDistribution())); LOG.debug("Looking for a matching script in directory {}", scriptsDir); File[] candidates = scriptsDir.listFiles(); @@ -204,8 +211,7 @@ private static File getScriptFile() { .as("Could not find create script with version <= %s in %s", serverVersion, scriptsDir) .isNotNull(); - LOG.info( - "Using {} to test against {} {}", bestFile, isDse ? "DSE" : "Cassandra", serverVersion); + LOG.info("Using {} to test against {} {}", bestFile, CCM_RULE.getDistribution(), serverVersion); return bestFile; } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java index c7b51c040b5..8f5680ff41a 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/NodeMetadataIT.java @@ -62,8 +62,9 @@ public void should_expose_node_metadata() { assertThat(node.getListenAddress().get().getAddress()).isEqualTo(connectAddress.getAddress()); assertThat(node.getDatacenter()).isEqualTo("dc1"); assertThat(node.getRack()).isEqualTo("r1"); - if (!CcmBridge.DSE_ENABLEMENT) { - // CcmBridge does not report accurate C* versions for DSE, only approximated values + if (CcmBridge.isDistributionOf(BackendType.CASSANDRA)) { + // CcmBridge does not report accurate C* versions for other distributions (e.g. DSE), only + // approximated values assertThat(node.getCassandraVersion()).isEqualTo(ccmRule.getCassandraVersion()); } assertThat(node.getState()).isSameAs(NodeState.UP); @@ -106,7 +107,7 @@ public void should_expose_dse_node_properties() { DseNodeProperties.DSE_WORKLOADS, DseNodeProperties.SERVER_ID); assertThat(node.getExtras().get(DseNodeProperties.DSE_VERSION)) - .isEqualTo(ccmRule.getDseVersion().get()); + .isEqualTo(ccmRule.getDistributionVersion()); assertThat(node.getExtras().get(DseNodeProperties.SERVER_ID)).isInstanceOf(String.class); assertThat(node.getExtras().get(DseNodeProperties.DSE_WORKLOADS)).isInstanceOf(Set.class); } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java index 6f1dcb791c6..85fcfc02cdb 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaChangesIT.java @@ -33,6 +33,7 @@ import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; import com.google.common.collect.ImmutableList; @@ -54,8 +55,8 @@ public class SchemaChangesIT { static { CustomCcmRule.Builder builder = CustomCcmRule.builder(); - if (!CcmBridge.DSE_ENABLEMENT - && CcmBridge.VERSION.nextStable().compareTo(Version.V4_0_0) >= 0) { + if (!CcmBridge.isDistributionOf( + BackendType.DSE, (dist, cass) -> cass.nextStable().compareTo(Version.V4_0_0) >= 0)) { builder.withCassandraConfiguration("enable_materialized_views", true); } CCM_RULE = builder.build(); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java index 805b2d970cc..df5571974c1 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/metadata/SchemaIT.java @@ -335,11 +335,9 @@ public void should_exclude_virtual_keyspaces_from_token_map() { private void skipIfDse60() { // Special case: DSE 6.0 reports C* 4.0 but does not support virtual tables - if (ccmRule.getDseVersion().isPresent()) { - Version dseVersion = ccmRule.getDseVersion().get(); - if (dseVersion.compareTo(DSE_MIN_VIRTUAL_TABLES) < 0) { - throw new AssumptionViolatedException("DSE 6.0 does not support virtual tables"); - } + if (!ccmRule.isDistributionOf( + BackendType.DSE, (dist, cass) -> dist.compareTo(DSE_MIN_VIRTUAL_TABLES) >= 0)) { + throw new AssumptionViolatedException("DSE 6.0 does not support virtual tables"); } } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java index 3a418c73653..2eb898021ba 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/DeleteReactiveIT.java @@ -37,6 +37,7 @@ import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.session.SessionRule; import io.reactivex.Flowable; import java.util.UUID; @@ -57,8 +58,8 @@ public class DeleteReactiveIT extends InventoryITBase { @ClassRule public static TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); private static CustomCcmRule.Builder configureCcm(CustomCcmRule.Builder builder) { - if (!CcmBridge.DSE_ENABLEMENT - && CcmBridge.VERSION.nextStable().compareTo(Version.V4_0_0) >= 0) { + if (!CcmBridge.isDistributionOf( + BackendType.DSE, (dist, cass) -> cass.nextStable().compareTo(Version.V4_0_0) >= 0)) { builder.withCassandraConfiguration("enable_sasi_indexes", true); } return builder; diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java index 9495003ae49..1bd899e4541 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java @@ -23,10 +23,10 @@ import com.datastax.oss.driver.api.mapper.annotations.Entity; import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; import com.datastax.oss.driver.api.testinfra.ccm.BaseCcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.UUID; /** Factors common code for mapper tests that rely on a simple inventory model. */ @@ -93,13 +93,14 @@ protected static List createStatements(BaseCcmRule ccmRule, boolean requ return builder.build(); } - private static final Version MINIMUM_SASI_VERSION = Version.parse("3.4.0"); - private static final Version BROKEN_SASI_VERSION = Version.parse("6.8.0"); + private static final Version MINIMUM_SASI_VERSION = + Objects.requireNonNull(Version.parse("3.4.0")); + private static final Version BROKEN_SASI_VERSION = Objects.requireNonNull(Version.parse("6.8.0")); protected static boolean isSasiBroken(BaseCcmRule ccmRule) { - Optional dseVersion = ccmRule.getDseVersion(); // creating SASI indexes is broken in DSE 6.8.0 - return dseVersion.isPresent() && dseVersion.get().compareTo(BROKEN_SASI_VERSION) == 0; + return ccmRule.isDistributionOf( + BackendType.DSE, (dist, cass) -> dist.compareTo(BROKEN_SASI_VERSION) == 0); } protected static boolean supportsSASI(BaseCcmRule ccmRule) { diff --git a/integration-tests/src/test/resources/DescribeIT/hcd/1.0.cql b/integration-tests/src/test/resources/DescribeIT/hcd/1.0.cql new file mode 100644 index 00000000000..abc70728206 --- /dev/null +++ b/integration-tests/src/test/resources/DescribeIT/hcd/1.0.cql @@ -0,0 +1,186 @@ + +CREATE KEYSPACE ks_0 WITH replication = { 'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor': '1' } AND durable_writes = true; + +CREATE TYPE ks_0.btype ( + a text +); + +CREATE TYPE ks_0.xtype ( + d text +); + +CREATE TYPE ks_0.ztype ( + c text, + a int +); + +CREATE TYPE ks_0.ctype ( + z frozen, + x frozen +); + +CREATE TYPE ks_0.atype ( + c frozen +); + +CREATE TABLE ks_0.cyclist_mv ( + cid uuid, + age int, + birthday date, + country text, + name text, + PRIMARY KEY (cid) +) WITH additional_write_policy = '99p' + AND bloom_filter_fp_chance = 0.01 + AND caching = {'keys':'ALL','rows_per_partition':'NONE'} + AND comment = '' + AND compaction = {'class':'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy','max_threshold':'32','min_threshold':'4'} + AND compression = {'chunk_length_in_kb':'64','class':'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND default_time_to_live = 0 + AND extensions = {} + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND read_repair = 'BLOCKING' + AND speculative_retry = '99p'; + +CREATE INDEX cyclist_by_country ON ks_0.cyclist_mv (country); + +CREATE TABLE ks_0.rank_by_year_and_name ( + race_year int, + race_name text, + rank int, + cyclist_name text, + PRIMARY KEY ((race_year, race_name), rank) +) WITH CLUSTERING ORDER BY (rank DESC) + AND additional_write_policy = '99p' + AND bloom_filter_fp_chance = 0.01 + AND caching = {'keys':'ALL','rows_per_partition':'NONE'} + AND comment = '' + AND compaction = {'class':'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy','max_threshold':'32','min_threshold':'4'} + AND compression = {'chunk_length_in_kb':'64','class':'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND default_time_to_live = 0 + AND extensions = {} + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND read_repair = 'BLOCKING' + AND speculative_retry = '99p'; + +CREATE INDEX rrank ON ks_0.rank_by_year_and_name (rank); + +CREATE INDEX ryear ON ks_0.rank_by_year_and_name (race_year); + +CREATE TABLE ks_0.ztable ( + zkey text, + a frozen, + PRIMARY KEY (zkey) +) WITH additional_write_policy = '99p' + AND bloom_filter_fp_chance = 0.1 + AND caching = {'keys':'ALL','rows_per_partition':'NONE'} + AND comment = '' + AND compaction = {'class':'org.apache.cassandra.db.compaction.LeveledCompactionStrategy','max_threshold':'32','min_threshold':'4','sstable_size_in_mb':'95'} + AND compression = {'chunk_length_in_kb':'64','class':'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND default_time_to_live = 0 + AND extensions = {} + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND read_repair = 'BLOCKING' + AND speculative_retry = '99p'; + +CREATE MATERIALIZED VIEW ks_0.cyclist_by_a_age AS +SELECT * FROM ks_0.cyclist_mv +WHERE age IS NOT NULL AND cid IS NOT NULL +PRIMARY KEY (age, cid) WITH additional_write_policy = '99p' + AND bloom_filter_fp_chance = 0.01 + AND caching = {'keys':'ALL','rows_per_partition':'NONE'} + AND comment = '' + AND compaction = {'class':'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy','max_threshold':'32','min_threshold':'4'} + AND compression = {'chunk_length_in_kb':'64','class':'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND extensions = {} + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND read_repair = 'BLOCKING' + AND speculative_retry = '99p'; + +CREATE MATERIALIZED VIEW ks_0.cyclist_by_age AS +SELECT + age, + cid, + birthday, + country, + name +FROM ks_0.cyclist_mv +WHERE age IS NOT NULL AND cid IS NOT NULL +PRIMARY KEY (age, cid) WITH additional_write_policy = '99p' + AND bloom_filter_fp_chance = 0.01 + AND caching = {'keys':'ALL','rows_per_partition':'NONE'} + AND comment = 'simple view' + AND compaction = {'class':'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy','max_threshold':'32','min_threshold':'4'} + AND compression = {'chunk_length_in_kb':'64','class':'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND extensions = {} + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND read_repair = 'BLOCKING' + AND speculative_retry = '99p'; + +CREATE MATERIALIZED VIEW ks_0.cyclist_by_r_age AS +SELECT + age, + cid, + birthday, + country, + name +FROM ks_0.cyclist_mv +WHERE age IS NOT NULL AND cid IS NOT NULL +PRIMARY KEY (age, cid) WITH additional_write_policy = '99p' + AND bloom_filter_fp_chance = 0.01 + AND caching = {'keys':'ALL','rows_per_partition':'NONE'} + AND comment = '' + AND compaction = {'class':'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy','max_threshold':'32','min_threshold':'4'} + AND compression = {'chunk_length_in_kb':'64','class':'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND extensions = {} + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND read_repair = 'BLOCKING' + AND speculative_retry = '99p'; + +CREATE FUNCTION ks_0.avgfinal(state tuple) + CALLED ON NULL INPUT + RETURNS double + LANGUAGE java + AS 'double r = 0; if (state.getInt(0) == 0) return null; r = state.getLong(1); r /= state.getInt(0); return Double.valueOf(r);'; + +CREATE FUNCTION ks_0.avgstate(state tuple,val int) + CALLED ON NULL INPUT + RETURNS tuple + LANGUAGE java + AS 'if (val !=null) { state.setInt(0, state.getInt(0)+1); state.setLong(1, state.getLong(1)+val.intValue()); } return state;'; + +CREATE AGGREGATE ks_0.average(int) + SFUNC avgstate + STYPE tuple + FINALFUNC avgfinal + INITCOND (0,0); + +CREATE AGGREGATE ks_0.mean(int) + SFUNC avgstate + STYPE tuple + FINALFUNC avgfinal + INITCOND (0,0); diff --git a/osgi-tests/README.md b/osgi-tests/README.md index 89ad0ba27c8..1ca6211d427 100644 --- a/osgi-tests/README.md +++ b/osgi-tests/README.md @@ -53,8 +53,8 @@ OSGi ones, you can do so as follows: You can pass the following system properties to your tests: 1. `ccm.version`: the CCM version to use -2. `ccm.dse`: whether to use DSE -3. `osgi.debug`: whether to enable remote debugging of the OSGi container (see +2. `ccm.distribution`: choose target backend type (e.g. DSE, HCD) +3. `osgi.debug`: whether to enable remote debugging of the OSGi container (see below). ## Debugging OSGi tests diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java index 8b140930870..ce4d9095361 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmStagedReactor.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import java.util.List; import java.util.Objects; import net.jcip.annotations.GuardedBy; @@ -38,7 +39,7 @@ public class CcmStagedReactor extends AllConfinedStagedReactor { static { CcmBridge.Builder builder = CcmBridge.builder().withNodes(1); - if (CcmBridge.DSE_ENABLEMENT && CcmBridge.VERSION.compareTo(DSE_5_0) >= 0) { + if (CcmBridge.isDistributionOf(BackendType.DSE, (dist, cass) -> dist.compareTo(DSE_5_0) >= 0)) { builder.withDseWorkloads("graph"); } CCM_BRIDGE = builder.build(); @@ -54,11 +55,10 @@ public CcmStagedReactor(List containers, List m @Override public synchronized void beforeSuite() { if (!running) { - boolean dse = CCM_BRIDGE.getDseVersion().isPresent(); LOGGER.info( "Starting CCM, running {} version {}", - dse ? "DSE" : "Cassandra", - dse ? CCM_BRIDGE.getDseVersion().get() : CCM_BRIDGE.getCassandraVersion()); + CcmBridge.DISTRIBUTION, + CcmBridge.getDistributionVersion()); CCM_BRIDGE.create(); CCM_BRIDGE.start(); LOGGER.info("CCM started"); diff --git a/test-infra/revapi.json b/test-infra/revapi.json index 3cfbc8b5337..c75a98cb4af 100644 --- a/test-infra/revapi.json +++ b/test-infra/revapi.json @@ -171,6 +171,27 @@ "code": "java.method.removed", "old": "method void com.datastax.oss.driver.api.testinfra.ccm.CcmRule::reloadCore(int, java.lang.String, java.lang.String, boolean)", "justification": "Modifying the state of a globally shared CCM instance is dangerous" + }, + { + "code": "java.method.removed", + "old": "method java.util.Optional com.datastax.oss.driver.api.testinfra.ccm.BaseCcmRule::getDseVersion()", + "justification": "Method has been replaced with more generic isDistributionOf(BackendType) and getDistributionVersion()" + }, + { + "code": "java.field.removed", + "old": "field com.datastax.oss.driver.api.testinfra.ccm.CcmBridge.DSE_ENABLEMENT", + "justification": "Method has been replaced with more generic isDistributionOf(BackendType) and getDistributionVersion()" + }, + { + "code": "java.method.nowStatic", + "old": "method com.datastax.oss.driver.api.core.Version com.datastax.oss.driver.api.testinfra.ccm.CcmBridge::getCassandraVersion()", + "new": "method com.datastax.oss.driver.api.core.Version com.datastax.oss.driver.api.testinfra.ccm.CcmBridge::getCassandraVersion()", + "justification": "Previous and current implemntation do not relay on non-static fields" + }, + { + "code": "java.method.removed", + "old": "method java.util.Optional com.datastax.oss.driver.api.testinfra.ccm.CcmBridge::getDseVersion()", + "justification": "Method has been replaced with more generic isDistributionOf(BackendType) and getDistributionVersion()" } ] } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java index 65210acd2a2..882cd55b948 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java @@ -22,7 +22,7 @@ import com.datastax.oss.driver.api.core.Version; import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirementRule; -import java.util.Optional; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import org.junit.AssumptionViolatedException; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -72,17 +72,29 @@ public void evaluate() { } } - public Version getCassandraVersion() { - return ccmBridge.getCassandraVersion(); + public BackendType getDistribution() { + return CcmBridge.DISTRIBUTION; + } + + public boolean isDistributionOf(BackendType type) { + return CcmBridge.isDistributionOf(type); + } + + public boolean isDistributionOf(BackendType type, CcmBridge.VersionComparator comparator) { + return CcmBridge.isDistributionOf(type, comparator); + } + + public Version getDistributionVersion() { + return CcmBridge.getDistributionVersion(); } - public Optional getDseVersion() { - return ccmBridge.getDseVersion(); + public Version getCassandraVersion() { + return CcmBridge.getCassandraVersion(); } @Override public ProtocolVersion getHighestProtocolVersion() { - if (ccmBridge.getCassandraVersion().compareTo(Version.V2_2_0) >= 0) { + if (CcmBridge.getCassandraVersion().compareTo(Version.V2_2_0) >= 0) { return DefaultProtocolVersion.V4; } else { return DefaultProtocolVersion.V3; diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java index 5b0c114a5fe..f0ce6bc5b0e 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/CcmBridge.java @@ -18,6 +18,7 @@ package com.datastax.oss.driver.api.testinfra.ccm; import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.shaded.guava.common.base.Joiner; import com.datastax.oss.driver.shaded.guava.common.io.Resources; import java.io.File; @@ -54,6 +55,9 @@ public class CcmBridge implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(CcmBridge.class); + public static BackendType DISTRIBUTION = + BackendType.valueOf( + System.getProperty("ccm.distribution", BackendType.CASSANDRA.name()).toUpperCase()); public static final Version VERSION = Objects.requireNonNull(Version.parse(System.getProperty("ccm.version", "4.0.0"))); @@ -61,8 +65,6 @@ public class CcmBridge implements AutoCloseable { public static final String BRANCH = System.getProperty("ccm.branch"); - public static final Boolean DSE_ENABLEMENT = Boolean.getBoolean("ccm.dse"); - public static final String CLUSTER_NAME = "ccm_1"; public static final String DEFAULT_CLIENT_TRUSTSTORE_PASSWORD = "fakePasswordForTests"; @@ -101,22 +103,21 @@ public class CcmBridge implements AutoCloseable { createTempStore(DEFAULT_SERVER_LOCALHOST_KEYSTORE_PATH); // major DSE versions - private static final Version V6_0_0 = Version.parse("6.0.0"); - private static final Version V5_1_0 = Version.parse("5.1.0"); - private static final Version V5_0_0 = Version.parse("5.0.0"); + public static final Version V6_0_0 = Version.parse("6.0.0"); + public static final Version V5_1_0 = Version.parse("5.1.0"); + public static final Version V5_0_0 = Version.parse("5.0.0"); // mapped C* versions from DSE versions - private static final Version V4_0_0 = Version.parse("4.0.0"); - private static final Version V3_10 = Version.parse("3.10"); - private static final Version V3_0_15 = Version.parse("3.0.15"); - private static final Version V2_1_19 = Version.parse("2.1.19"); + public static final Version V4_0_0 = Version.parse("4.0.0"); + public static final Version V3_10 = Version.parse("3.10"); + public static final Version V3_0_15 = Version.parse("3.0.15"); + public static final Version V2_1_19 = Version.parse("2.1.19"); + + // mapped C* versions from HCD versions + public static final Version V4_0_11 = Version.parse("4.0.11"); static { - if (DSE_ENABLEMENT) { - LOG.info("CCM Bridge configured with DSE version {}", VERSION); - } else { - LOG.info("CCM Bridge configured with Apache Cassandra version {}", VERSION); - } + LOG.info("CCM Bridge configured with {} version {}", DISTRIBUTION.getFriendlyName(), VERSION); } private final int[] nodes; @@ -175,25 +176,24 @@ private static boolean isWindows() { return System.getProperty("os.name", "").toLowerCase(Locale.US).contains("win"); } - public Optional getDseVersion() { - return DSE_ENABLEMENT ? Optional.of(VERSION) : Optional.empty(); + public static boolean isDistributionOf(BackendType type) { + return DISTRIBUTION == type; + } + + public static boolean isDistributionOf(BackendType type, VersionComparator comparator) { + return isDistributionOf(type) + && comparator.accept(getDistributionVersion(), getCassandraVersion()); + } + + public static Version getDistributionVersion() { + return VERSION; } - public Version getCassandraVersion() { - if (!DSE_ENABLEMENT) { + public static Version getCassandraVersion() { + if (isDistributionOf(BackendType.CASSANDRA)) { return VERSION; - } else { - Version stableVersion = VERSION.nextStable(); - if (stableVersion.compareTo(V6_0_0) >= 0) { - return V4_0_0; - } else if (stableVersion.compareTo(V5_1_0) >= 0) { - return V3_10; - } else if (stableVersion.compareTo(V5_0_0) >= 0) { - return V3_0_15; - } else { - return V2_1_19; - } } + return DistributionCassandraVersions.getCassandraVersion(DISTRIBUTION, VERSION); } private String getCcmVersionString(Version version) { @@ -225,9 +225,7 @@ public void create() { } else { createOptions.add("-v " + getCcmVersionString(VERSION)); } - if (DSE_ENABLEMENT) { - createOptions.add("--dse"); - } + createOptions.addAll(Arrays.asList(DISTRIBUTION.getCcmOptions())); execute( "create", CLUSTER_NAME, @@ -252,7 +250,7 @@ public void create() { // If we're dealing with anything more recent than 2.2 explicitly enable UDF... but run it // through our conversion process to make // sure more recent versions don't have a problem. - if (cassandraVersion.compareTo(Version.V2_2_0) >= 0) { + if (cassandraVersion.compareTo(Version.V2_2_0) >= 0 || isDistributionOf(BackendType.HCD)) { String originalKey = "enable_user_defined_functions"; Object originalValue = "true"; execute( @@ -264,7 +262,7 @@ public void create() { } // Note that we aren't performing any substitution on DSE key/value props (at least for now) - if (DSE_ENABLEMENT) { + if (isDistributionOf(BackendType.DSE)) { for (Map.Entry conf : dseConfiguration.entrySet()) { execute("updatedseconf", String.format("%s:%s", conf.getKey(), conf.getValue())); } @@ -338,11 +336,10 @@ public void stop(int n) { } public void add(int n, String dc) { - if (getDseVersion().isPresent()) { - execute("add", "-i", ipPrefix + n, "-d", dc, "node" + n, "--dse"); - } else { - execute("add", "-i", ipPrefix + n, "-d", dc, "node" + n); - } + List addOptions = new ArrayList<>(); + addOptions.addAll(Arrays.asList("add", "-i", ipPrefix + n, "-d", dc, "node" + n)); + addOptions.addAll(Arrays.asList(DISTRIBUTION.getCcmOptions())); + execute(addOptions.toArray(new String[0])); start(n); } @@ -475,11 +472,11 @@ private Optional overrideJvmVersionForDseWorkloads() { return Optional.empty(); } - if (!DSE_ENABLEMENT || !getDseVersion().isPresent()) { + if (!isDistributionOf(BackendType.DSE)) { return Optional.empty(); } - if (getDseVersion().get().compareTo(Version.V6_9_0) >= 0) { + if (getDistributionVersion().compareTo(Version.V6_9_0) >= 0) { // DSE 6.9.0 supports only JVM 11 onwards (also with graph workload) return Optional.empty(); } @@ -641,4 +638,8 @@ public CcmBridge build() { dseWorkloads); } } + + public interface VersionComparator { + boolean accept(Version distribution, Version cassandra); + } } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java index ac2507cec53..0819f785446 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DefaultCcmBridgeBuilderCustomizer.java @@ -18,18 +18,20 @@ package com.datastax.oss.driver.api.testinfra.ccm; import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; /** @see CcmRule */ @SuppressWarnings("unused") public class DefaultCcmBridgeBuilderCustomizer { public static CcmBridge.Builder configureBuilder(CcmBridge.Builder builder) { - if (!CcmBridge.DSE_ENABLEMENT - && CcmBridge.VERSION.nextStable().compareTo(Version.V4_0_0) >= 0) { + if (!CcmBridge.isDistributionOf( + BackendType.DSE, (dist, cass) -> dist.nextStable().compareTo(Version.V4_0_0) >= 0) + || CcmBridge.isDistributionOf(BackendType.HCD)) { builder.withCassandraConfiguration("enable_materialized_views", true); builder.withCassandraConfiguration("enable_sasi_indexes", true); } - if (CcmBridge.VERSION.nextStable().compareTo(Version.V3_0_0) >= 0) { + if (CcmBridge.getDistributionVersion().nextStable().compareTo(Version.V3_0_0) >= 0) { builder.withJvmArgs("-Dcassandra.superuser_setup_delay_ms=0"); builder.withJvmArgs("-Dcassandra.skip_wait_for_gossip_to_settle=0"); builder.withCassandraConfiguration("num_tokens", "1"); diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DistributionCassandraVersions.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DistributionCassandraVersions.java new file mode 100644 index 00000000000..9f7634d1b37 --- /dev/null +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/DistributionCassandraVersions.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.testinfra.ccm; + +import com.datastax.oss.driver.api.core.Version; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSortedMap; +import java.util.HashMap; +import java.util.Map; + +/** Defines mapping of various distributions to shipped Apache Cassandra version. */ +public abstract class DistributionCassandraVersions { + private static final Map> mappings = + new HashMap<>(); + + static { + { + // DSE + ImmutableSortedMap dse = + ImmutableSortedMap.of( + Version.V1_0_0, CcmBridge.V2_1_19, + Version.V5_0_0, CcmBridge.V3_0_15, + CcmBridge.V5_1_0, CcmBridge.V3_10, + CcmBridge.V6_0_0, CcmBridge.V4_0_0); + mappings.put(BackendType.DSE, dse); + } + { + // HCD + ImmutableSortedMap hcd = + ImmutableSortedMap.of(Version.V1_0_0, CcmBridge.V4_0_11); + mappings.put(BackendType.HCD, hcd); + } + } + + public static Version getCassandraVersion(BackendType type, Version version) { + ImmutableSortedMap mapping = mappings.get(type); + if (mapping == null) { + return null; + } + return mapping.floorEntry(version).getValue(); + } +} diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java index 6c59e216602..343861571e0 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendRequirementRule.java @@ -41,7 +41,7 @@ public void evaluate() { } protected static BackendType getBackendType() { - return CcmBridge.DSE_ENABLEMENT ? BackendType.DSE : BackendType.CASSANDRA; + return CcmBridge.DISTRIBUTION; } protected static Version getVersion() { diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java index 1683dd86136..e0058ca324a 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/requirement/BackendType.java @@ -18,9 +18,9 @@ package com.datastax.oss.driver.api.testinfra.requirement; public enum BackendType { - CASSANDRA("C*"), - DSE("Dse"), - ; + CASSANDRA("Apache Cassandra"), + DSE("DSE"), + HCD("HCD"); final String friendlyName; @@ -31,4 +31,11 @@ public enum BackendType { public String getFriendlyName() { return friendlyName; } + + public String[] getCcmOptions() { + if (this == CASSANDRA) { + return new String[0]; + } + return new String[] {"--" + name().toLowerCase()}; + } } diff --git a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java index 5396e5c6cc6..3b792374769 100644 --- a/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java +++ b/test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/session/SessionRule.java @@ -29,10 +29,11 @@ import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.testinfra.CassandraResourceRule; import com.datastax.oss.driver.api.testinfra.ccm.BaseCcmRule; +import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.SchemaChangeSynchronizer; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; import com.datastax.oss.driver.api.testinfra.simulacron.SimulacronRule; import java.util.Objects; -import java.util.Optional; import org.junit.rules.ExternalResource; /** @@ -154,14 +155,12 @@ protected void before() { Statement.SYNC); } if (graphName != null) { - Optional dseVersion = - (cassandraResource instanceof BaseCcmRule) - ? ((BaseCcmRule) cassandraResource).getDseVersion() - : Optional.empty(); - if (!dseVersion.isPresent()) { + BaseCcmRule rule = + (cassandraResource instanceof BaseCcmRule) ? ((BaseCcmRule) cassandraResource) : null; + if (rule == null || !CcmBridge.isDistributionOf(BackendType.DSE)) { throw new IllegalArgumentException("DseSessionRule should work with DSE."); } - if (dseVersion.get().compareTo(V6_8_0) >= 0) { + if (rule.getDistributionVersion().compareTo(V6_8_0) >= 0) { session() .execute( ScriptGraphStatement.newInstance( From e84378681aecdbb87696dc4b53cb6fd336c82b6b Mon Sep 17 00:00:00 2001 From: Stefan Miklosovic Date: Wed, 23 Oct 2024 22:23:39 +0200 Subject: [PATCH 342/395] Fix TableMetadata.describe() when containing a vector column patch by Stefan Miklosovic; reviewed by Bret McGuire for CASSJAVA-2 --- .../internal/core/type/DefaultVectorType.java | 2 +- .../metadata/schema/TableMetadataTest.java | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/TableMetadataTest.java diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java index 5915adc2fb3..c9180d44edc 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java @@ -60,7 +60,7 @@ public String getClassName() { @NonNull @Override public String asCql(boolean includeFrozen, boolean pretty) { - return String.format("'%s(%d)'", getClassName(), getDimensions()); + return String.format("vector<%s, %d>", getElementType().asCql(true, false), getDimensions()); } /* ============== General class implementation ============== */ diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/TableMetadataTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/TableMetadataTest.java new file mode 100644 index 00000000000..03d63230992 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/schema/TableMetadataTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.metadata.schema; + +import static com.datastax.oss.driver.api.core.CqlIdentifier.fromCql; +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; +import com.datastax.oss.driver.internal.core.type.DefaultVectorType; +import com.datastax.oss.driver.internal.core.type.PrimitiveType; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import com.datastax.oss.protocol.internal.ProtocolConstants.DataType; +import com.google.common.collect.ImmutableList; +import java.util.UUID; +import org.junit.Test; + +public class TableMetadataTest { + + /** Tests CASSJAVA-2 */ + @Test + public void should_describe_table_with_vector_correctly() { + TableMetadata tableMetadata = + new DefaultTableMetadata( + fromCql("ks"), + fromCql("tb"), + UUID.randomUUID(), + false, + false, + ImmutableList.of( + new DefaultColumnMetadata( + fromCql("ks"), + fromCql("ks"), + fromCql("tb"), + new PrimitiveType(DataType.ASCII), + false)), + ImmutableMap.of(), + ImmutableMap.of( + fromCql("a"), + new DefaultColumnMetadata( + fromCql("ks"), + fromCql("ks"), + fromCql("tb"), + new DefaultVectorType(new PrimitiveType(DataType.INT), 3), + false)), + ImmutableMap.of(), + ImmutableMap.of()); + + String describe1 = tableMetadata.describe(true); + + assertThat(describe1).contains("vector,"); + } +} From 62cea5a5f34d5cc6ef335f99829d0ae3cf9cf396 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Wed, 6 Nov 2024 17:47:30 -0600 Subject: [PATCH 343/395] Move Apache Cassandra 5.x off of beta1 and remove some older Apache Cassandra versions. patch by Bret McGuire; reviewed by Bret McGuire for CASSJAVA-54 --- Jenkinsfile-datastax | 52 +++++++++++++------------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/Jenkinsfile-datastax b/Jenkinsfile-datastax index af3faafee20..cd48f325a29 100644 --- a/Jenkinsfile-datastax +++ b/Jenkinsfile-datastax @@ -268,13 +268,9 @@ pipeline { ''') choice( name: 'ADHOC_BUILD_AND_EXECUTE_TESTS_SERVER_VERSION', - choices: ['2.1', // Legacy Apache CassandraⓇ - '2.2', // Legacy Apache CassandraⓇ - '3.0', // Previous Apache CassandraⓇ - '3.11', // Previous Apache CassandraⓇ - '4.0', // Previous Apache CassandraⓇ - '4.1', // Current Apache CassandraⓇ - '5.0-beta1', // Development Apache CassandraⓇ + choices: ['4.0', // Previous Apache CassandraⓇ + '4.1', // Previous Apache CassandraⓇ + '5.0', // Current Apache CassandraⓇ 'dse-4.8.16', // Previous EOSL DataStax Enterprise 'dse-5.0.15', // Long Term Support DataStax Enterprise 'dse-5.1.35', // Legacy DataStax Enterprise @@ -292,22 +288,6 @@ pipeline { Choice Description - - 2.1 - Apache Cassandra® v2.1.x - - - 2.2 - Apache Cassandra® v2.2.x - - - 3.0 - Apache Cassandra® v3.0.x - - - 3.11 - Apache Cassandra® v3.11.x - 4.0 Apache Cassandra® v4.0.x @@ -316,6 +296,10 @@ pipeline { 4.1 Apache Cassandra® v4.1.x + + 5.0 + Apache Cassandra® v5.0.x + dse-4.8.16 DataStax Enterprise v4.8.x (END OF SERVICE LIFE) @@ -435,13 +419,10 @@ pipeline { // schedules only run against release branches (i.e. 3.x, 4.x, 4.5.x, etc.) parameterizedCron(branchPatternCron().matcher(env.BRANCH_NAME).matches() ? """ # Every weekend (Saturday, Sunday) around 2:00 AM - ### JDK8 tests against 2.1, 3.0, 4.0, DSE 4.8, DSE 5.0, DSE 5.1, dse-6.0.18 and DSE 6.7 - H 2 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=2.1 3.0 4.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 + H 2 * * 0 %CI_SCHEDULE=WEEKENDS;CI_SCHEDULE_SERVER_VERSIONS=4.0 4.1 5.0 dse-4.8.16 dse-5.0.15 dse-5.1.35 dse-6.0.18 dse-6.7.17;CI_SCHEDULE_JABBA_VERSION=1.8 # Every weeknight (Monday - Friday) around 12:00 PM noon - ### JDK11 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 - H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0 hcd-1.0.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 - ### JDK17 tests against 3.11, 4.1, 5.0-beta1 and DSE 6.8 - H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=3.11 4.1 5.0-beta1 dse-6.8.30 dse-6.9.0 hcd-1.0.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=4.1 5.0 dse-6.8.30 dse-6.9.0 hcd-1.0.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.11 + H 12 * * 1-5 %CI_SCHEDULE=WEEKNIGHTS;CI_SCHEDULE_SERVER_VERSIONS=4.1 5.0 dse-6.8.30 dse-6.9.0 hcd-1.0.0;CI_SCHEDULE_JABBA_VERSION=openjdk@1.17 """ : "") } @@ -475,8 +456,8 @@ pipeline { axes { axis { name 'SERVER_VERSION' - values '3.11', // Latest stable Apache CassandraⓇ - '4.1', // Development Apache CassandraⓇ + values '4.0', // Previous Apache CassandraⓇ + '5.0', // Current Apache CassandraⓇ 'dse-6.8.30', // Current DataStax Enterprise 'dse-6.9.0', // Current DataStax Enterprise 'hcd-1.0.0' // Current DataStax HCD @@ -585,12 +566,9 @@ pipeline { axes { axis { name 'SERVER_VERSION' - values '2.1', // Legacy Apache CassandraⓇ - '3.0', // Previous Apache CassandraⓇ - '3.11', // Previous Apache CassandraⓇ - '4.0', // Previous Apache CassandraⓇ - '4.1', // Current Apache CassandraⓇ - '5.0-beta1', // Development Apache CassandraⓇ + values '4.0', // Previous Apache CassandraⓇ + '4.1', // Previous Apache CassandraⓇ + '5.0', // Current Apache CassandraⓇ 'dse-4.8.16', // Previous EOSL DataStax Enterprise 'dse-5.0.15', // Last EOSL DataStax Enterprise 'dse-5.1.35', // Legacy DataStax Enterprise From a322ca265654605123f4d7b889ad736c114f0c7e Mon Sep 17 00:00:00 2001 From: Jeremy Hanna Date: Wed, 27 Nov 2024 12:41:02 -0600 Subject: [PATCH 344/395] Update link to Jira to be CASSJAVA Updating the link to Jira. Previously we had a component in the CASSANDRA Jira project but now we have a project for each driver - in the case of Java, it's CASSJAVA. Added CASSJAVA to .asf.yaml patch by Jeremy Hanna; reviewed by Bret McGuire for CASSJAVA-61 --- .asf.yaml | 1 + README.md | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.asf.yaml b/.asf.yaml index ad58f536398..ac29efed9ff 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -34,3 +34,4 @@ github: projects: false autolink_jira: - CASSANDRA + - CASSJAVA diff --git a/README.md b/README.md index 2a30cb68c9a..b6e1cc337d8 100644 --- a/README.md +++ b/README.md @@ -75,13 +75,13 @@ See the [Cassandra error handling done right blog](https://www.datastax.com/blog * [Manual](manual/) * [API docs] -* Bug tracking: [JIRA]. Make sure to select the "Client/java-driver" component when filing new tickets! +* Bug tracking: [JIRA] * [Mailing list] * [Changelog] * [FAQ] [API docs]: https://docs.datastax.com/en/drivers/java/4.17 -[JIRA]: https://issues.apache.org/jira/issues/?jql=project%20%3D%20CASSANDRA%20AND%20component%20%3D%20%22Client%2Fjava-driver%22%20ORDER%20BY%20key%20DESC +[JIRA]: https://issues.apache.org/jira/issues/?jql=project%20%3D%20CASSJAVA%20ORDER%20BY%20key%20DESC [Mailing list]: https://groups.google.com/a/lists.datastax.com/forum/#!forum/java-driver-user [Changelog]: changelog/ [FAQ]: faq/ @@ -108,4 +108,4 @@ Apache Cassandra, Apache, Tomcat, Lucene, Solr, Hadoop, Spark, TinkerPop, and Ca trademarks of the [Apache Software Foundation](http://www.apache.org/) or its subsidiaries in Canada, the United States and/or other countries. -Binary artifacts of this product bundle Java Native Runtime libraries, which is available under the Eclipse Public License version 2.0. \ No newline at end of file +Binary artifacts of this product bundle Java Native Runtime libraries, which is available under the Eclipse Public License version 2.0. From 7bc085bdfb337b91255573bc3e130815e280954a Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Wed, 6 Nov 2024 08:31:36 +0100 Subject: [PATCH 345/395] Move DataStax shaded Guava module into Java driver patch by Lukasz Antoniak; reviewed by Alexandre Dutra and Bret McGuire for CASSJAVA-52 --- bom/pom.xml | 10 +- core-shaded/pom.xml | 4 +- core/pom.xml | 4 +- distribution/src/assembly/binary-tarball.xml | 6 +- guava-shaded/pom.xml | 215 ++++++++++++++++++ guava-shaded/src/assembly/shaded-jar.xml | 48 ++++ ...graphicalComparatorHolderSubstitution.java | 39 ++++ .../UnsafeComparatorSubstitution.java | 25 ++ guava-shaded/src/main/javadoc/README.txt | 2 + manual/core/integration/README.md | 2 +- mapper-processor/pom.xml | 4 +- osgi-tests/pom.xml | 4 +- .../internal/osgi/support/BundleOptions.java | 2 +- pom.xml | 3 +- query-builder/pom.xml | 4 +- 15 files changed, 351 insertions(+), 21 deletions(-) create mode 100644 guava-shaded/pom.xml create mode 100644 guava-shaded/src/assembly/shaded-jar.xml create mode 100644 guava-shaded/src/main/java/com/google/common/primitives/LexicographicalComparatorHolderSubstitution.java create mode 100644 guava-shaded/src/main/java/com/google/common/primitives/UnsafeComparatorSubstitution.java create mode 100644 guava-shaded/src/main/javadoc/README.txt diff --git a/bom/pom.xml b/bom/pom.xml index 96b7a6ceb18..08f212f6157 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -55,6 +55,11 @@ java-driver-query-builder 4.18.2-SNAPSHOT + + org.apache.cassandra + java-driver-guava-shaded + 4.18.2-SNAPSHOT + org.apache.cassandra java-driver-test-infra @@ -75,11 +80,6 @@ native-protocol 1.5.1 - - com.datastax.oss - java-driver-shaded-guava - 25.1-jre-graal-sub-1 - diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 6c139aab127..9a708beb2a7 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -57,8 +57,8 @@ native-protocol - com.datastax.oss - java-driver-shaded-guava + org.apache.cassandra + java-driver-guava-shaded com.typesafe diff --git a/core/pom.xml b/core/pom.xml index 33688754f1b..2a48e8bf9ce 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -49,8 +49,8 @@ netty-handler - com.datastax.oss - java-driver-shaded-guava + org.apache.cassandra + java-driver-guava-shaded com.typesafe diff --git a/distribution/src/assembly/binary-tarball.xml b/distribution/src/assembly/binary-tarball.xml index 0d025fafb2c..b6294a25340 100644 --- a/distribution/src/assembly/binary-tarball.xml +++ b/distribution/src/assembly/binary-tarball.xml @@ -66,8 +66,8 @@ org.apache.cassandra:java-driver-core org.apache.cassandra:java-driver-mapper-runtime org.apache.cassandra:java-driver-mapper-processor + org.apache.cassandra:java-driver-guava-shaded - com.datastax.oss:java-driver-shaded-guava com.github.stephenc.jcip:jcip-annotations com.github.spotbugs:spotbugs-annotations @@ -91,8 +91,8 @@ org.apache.cassandra:java-driver-core org.apache.cassandra:java-driver-query-builder org.apache.cassandra:java-driver-mapper-processor + org.apache.cassandra:java-driver-guava-shaded - com.datastax.oss:java-driver-shaded-guava com.github.stephenc.jcip:jcip-annotations com.github.spotbugs:spotbugs-annotations @@ -116,8 +116,8 @@ org.apache.cassandra:java-driver-core org.apache.cassandra:java-driver-query-builder org.apache.cassandra:java-driver-mapper-runtime + org.apache.cassandra:java-driver-guava-shaded - com.datastax.oss:java-driver-shaded-guava com.github.stephenc.jcip:jcip-annotations com.github.spotbugs:spotbugs-annotations diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml new file mode 100644 index 00000000000..9854fcc48ba --- /dev/null +++ b/guava-shaded/pom.xml @@ -0,0 +1,215 @@ + + + + 4.0.0 + + org.apache.cassandra + java-driver-parent + 4.18.2-SNAPSHOT + + java-driver-guava-shaded + Apache Cassandra Java Driver - guava shaded dep + Shaded Guava artifact for use in the Java driver for Apache Cassandra® + + + com.google.guava + guava + + + com.google.code.findbugs + jsr305 + + + org.checkerframework + checker-qual + + + com.google.errorprone + error_prone_annotations + + + com.google.j2objc + j2objc-annotations + + + org.codehaus.mojo + animal-sniffer-annotations + + + + + org.graalvm.nativeimage + svm + 20.0.0 + provided + + + + + + maven-shade-plugin + + + shade-guava-dependency + package + + shade + + + + + org.apache.cassandra:java-driver-guava-shaded + com.google.guava:guava + + + + + com.google + com.datastax.oss.driver.shaded.guava + + + + + com.google.guava:* + + META-INF/** + + + + true + true + + + + + + maven-clean-plugin + + + clean-classes + package + + clean + + + ${project.build.outputDirectory} + + + + + + maven-dependency-plugin + + + unpack-shaded-classes + package + + unpack + + + ${project.build.outputDirectory} + + + org.apache.cassandra + java-driver-guava-shaded + ${project.version} + jar + + + + + + + + org.apache.felix + maven-bundle-plugin + + 3.5.0 + true + + + generate-shaded-manifest + package + + manifest + + + + com.datastax.oss.driver.shaded.guava + !com.datastax.oss.driver.shaded.guava.errorprone.*, !org.checkerframework.*, * + javax.annotation.*;resolution:=optional;version="[3.0,4)", javax.crypto.*;resolution:=optional, sun.misc.*;resolution:=optional, !com.oracle.svm.*, !com.datastax.oss.driver.shaded.guava.errorprone.*, !org.checkerframework.*, * + + + + + + + maven-assembly-plugin + + + generate-final-shaded-jar + package + + single + + + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + src/assembly/shaded-jar.xml + + + false + + + + + + maven-jar-plugin + + + empty-javadoc-jar + + jar + + + javadoc + ${basedir}/src/main/javadoc + + + + + + org.revapi + revapi-maven-plugin + + true + + + + + diff --git a/guava-shaded/src/assembly/shaded-jar.xml b/guava-shaded/src/assembly/shaded-jar.xml new file mode 100644 index 00000000000..d762a27b20f --- /dev/null +++ b/guava-shaded/src/assembly/shaded-jar.xml @@ -0,0 +1,48 @@ + + + + shaded-jar + + jar + + false + + + + ${project.build.outputDirectory} + + META-INF/maven/org.apache.cassandra/java-driver-guava-shaded/pom.xml + + + + + + + + ${project.basedir}/dependency-reduced-pom.xml + META-INF/maven/org.apache.cassandra/java-driver-guava-shaded + pom.xml + + + diff --git a/guava-shaded/src/main/java/com/google/common/primitives/LexicographicalComparatorHolderSubstitution.java b/guava-shaded/src/main/java/com/google/common/primitives/LexicographicalComparatorHolderSubstitution.java new file mode 100644 index 00000000000..95e9c70cdbc --- /dev/null +++ b/guava-shaded/src/main/java/com/google/common/primitives/LexicographicalComparatorHolderSubstitution.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.common.primitives; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import java.util.Comparator; + +@TargetClass(UnsignedBytes.LexicographicalComparatorHolder.class) +final class LexicographicalComparatorHolderSubstitution { + + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias) + static Comparator BEST_COMPARATOR = UnsignedBytes.lexicographicalComparatorJavaImpl(); + + /* All known cases should be covered by the field substitution above... keeping this only + * for sake of completeness */ + @Substitute + static Comparator getBestComparator() { + return UnsignedBytes.lexicographicalComparatorJavaImpl(); + } +} diff --git a/guava-shaded/src/main/java/com/google/common/primitives/UnsafeComparatorSubstitution.java b/guava-shaded/src/main/java/com/google/common/primitives/UnsafeComparatorSubstitution.java new file mode 100644 index 00000000000..549de0b5c02 --- /dev/null +++ b/guava-shaded/src/main/java/com/google/common/primitives/UnsafeComparatorSubstitution.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.common.primitives; + +import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(UnsignedBytes.LexicographicalComparatorHolder.UnsafeComparator.class) +@Delete +final class UnsafeComparatorSubstitution {} diff --git a/guava-shaded/src/main/javadoc/README.txt b/guava-shaded/src/main/javadoc/README.txt new file mode 100644 index 00000000000..57f82b2a265 --- /dev/null +++ b/guava-shaded/src/main/javadoc/README.txt @@ -0,0 +1,2 @@ +This empty JAR is generated for compliance with Maven Central rules. Please refer to the original +Guava API docs. \ No newline at end of file diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index 2dfc0155c63..f2a96160bce 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -671,7 +671,7 @@ The remaining core driver dependencies are the only ones that are truly mandator * the [native protocol](https://github.com/datastax/native-protocol) layer. This is essentially part of the driver code, but was externalized for reuse in other projects; -* `java-driver-shaded-guava`, a shaded version of [Guava](https://github.com/google/guava). It is +* `java-driver-guava-shaded`, a shaded version of [Guava](https://github.com/google/guava). It is relocated to a different package, and only used by internal driver code, so it should be completely transparent to third-party code; * the [SLF4J](https://www.slf4j.org/) API for [logging](../logging/). diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 61906f41987..6588f17d5f7 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -44,8 +44,8 @@ java-driver-mapper-runtime - com.datastax.oss - java-driver-shaded-guava + org.apache.cassandra + java-driver-guava-shaded com.squareup diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 5947aff1bc5..f0e66b656ca 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -71,8 +71,8 @@ logback-classic - com.datastax.oss - java-driver-shaded-guava + org.apache.cassandra + java-driver-guava-shaded org.xerial.snappy diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java index 536a6d96c77..3e6171ca530 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java @@ -35,7 +35,7 @@ public class BundleOptions { public static CompositeOption commonBundles() { return () -> options( - mavenBundle("com.datastax.oss", "java-driver-shaded-guava").versionAsInProject(), + mavenBundle("org.apache.cassandra", "java-driver-guava-shaded").versionAsInProject(), mavenBundle("io.dropwizard.metrics", "metrics-core").versionAsInProject(), mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), mavenBundle("org.hdrhistogram", "HdrHistogram").versionAsInProject(), diff --git a/pom.xml b/pom.xml index 94311719e5f..620cf1db4bb 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ mapper-processor metrics/micrometer metrics/microprofile + guava-shaded test-infra integration-tests osgi-tests @@ -110,7 +111,7 @@ ${netty.version} - + com.google.guava guava 25.1-jre diff --git a/query-builder/pom.xml b/query-builder/pom.xml index bae0e0c6ca0..4e09a10e584 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -45,8 +45,8 @@ java-driver-core - com.datastax.oss - java-driver-shaded-guava + org.apache.cassandra + java-driver-guava-shaded com.github.stephenc.jcip From 7ca013fbd5f1ec589df52ef0e6441986f07c11ff Mon Sep 17 00:00:00 2001 From: Ammar Khaku Date: Sat, 22 Apr 2023 16:13:15 -0700 Subject: [PATCH 346/395] JAVA-3057 Allow decoding a UDT that has more fields than expected patch by Ammar Khaku; reviewed by Andy Tolbert and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1635 --- .../internal/core/type/codec/UdtCodec.java | 10 ++- .../core/type/codec/UdtCodecTest.java | 24 +++--- .../internal/core/type/codec/UdtCodecIT.java | 77 +++++++++++++++++++ 3 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecIT.java diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java index f5177e63b5e..5d0a379f761 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodec.java @@ -30,10 +30,14 @@ import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @ThreadSafe public class UdtCodec implements TypeCodec { + private static final Logger LOG = LoggerFactory.getLogger(UdtCodec.class); + private final UserDefinedType cqlType; public UdtCodec(@NonNull UserDefinedType cqlType) { @@ -107,10 +111,8 @@ public UdtValue decode(@Nullable ByteBuffer bytes, @NonNull ProtocolVersion prot int i = 0; while (input.hasRemaining()) { if (i == cqlType.getFieldTypes().size()) { - throw new IllegalArgumentException( - String.format( - "Too many fields in encoded UDT value, expected %d", - cqlType.getFieldTypes().size())); + LOG.debug("Encountered unexpected fields when parsing codec {}", cqlType); + break; } int elementSize = input.getInt(); ByteBuffer element; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java index bf7c1e98b26..af94247f937 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecTest.java @@ -136,18 +136,18 @@ public void should_decode_udt() { } @Test - public void should_fail_to_decode_udt_when_too_many_fields() { - assertThatThrownBy( - () -> - decode( - "0x" - + ("00000004" + "00000001") - + "ffffffff" - + ("00000001" + "61") - // extra contents - + "ffffffff")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Too many fields in encoded UDT value, expected 3"); + public void should_decode_udt_when_too_many_fields() { + UdtValue udt = + decode( + "0x" + + ("00000004" + "00000001") + + "ffffffff" + + ("00000001" + "61") + // extra contents + + "ffffffff"); + assertThat(udt.getInt(0)).isEqualTo(1); + assertThat(udt.isNull(1)).isTrue(); + assertThat(udt.getString(2)).isEqualTo("a"); } /** Test for JAVA-2557. Ensures that the codec can decode null fields with any negative length. */ diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecIT.java new file mode 100644 index 00000000000..804a078bbe0 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/internal/core/type/codec/UdtCodecIT.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type.codec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.data.UdtValue; +import com.datastax.oss.driver.api.core.type.UserDefinedType; +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.categories.ParallelizableTests; +import java.util.Objects; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; + +@Category(ParallelizableTests.class) +public class UdtCodecIT { + + private CcmRule ccmRule = CcmRule.getInstance(); + + private SessionRule sessionRule = SessionRule.builder(ccmRule).build(); + + @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); + + @Test + public void should_decoding_udt_be_backward_compatible() { + CqlSession session = sessionRule.session(); + session.execute("CREATE TYPE test_type_1 (a text, b int)"); + session.execute("CREATE TABLE test_table_1 (e int primary key, f frozen)"); + // insert a row using version 1 of the UDT schema + session.execute("INSERT INTO test_table_1(e, f) VALUES(1, {a: 'a', b: 1})"); + UserDefinedType udt = + session + .getMetadata() + .getKeyspace(sessionRule.keyspace()) + .flatMap(ks -> ks.getUserDefinedType("test_type_1")) + .orElseThrow(IllegalStateException::new); + TypeCodec oldCodec = session.getContext().getCodecRegistry().codecFor(udt); + // update UDT schema + session.execute("ALTER TYPE test_type_1 add i text"); + // insert a row using version 2 of the UDT schema + session.execute("INSERT INTO test_table_1(e, f) VALUES(2, {a: 'b', b: 2, i: 'b'})"); + Row row = + Objects.requireNonNull(session.execute("SELECT f FROM test_table_1 WHERE e = ?", 2).one()); + // Try to read new row with old codec. Using row.getUdtValue() would not cause any issues, + // because new codec will be automatically registered (using all 3 attributes). + // If application leverages generic row.get(String, Codec) method, data reading with old codec + // should + // be backward-compatible. + UdtValue value = Objects.requireNonNull((UdtValue) row.get("f", oldCodec)); + assertThat(value.getString("a")).isEqualTo("b"); + assertThat(value.getInt("b")).isEqualTo(2); + assertThatThrownBy(() -> value.getString("i")).hasMessage("i is not a field in this UDT"); + } +} From 6a8674f2db92668359196b5492753612b3844594 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 11 Nov 2024 11:49:20 -0600 Subject: [PATCH 347/395] CASSJAVA-55 Remove setting "Host" header for metadata requests. With some sysprops enabled this will actually be respected which completely borks Astra routing. patch by Bret McGuire; reviewed by Alexandre Dutra and Bret McGuire for CASSJAVA-55 --- .../driver/internal/core/config/cloud/CloudConfigFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/config/cloud/CloudConfigFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/config/cloud/CloudConfigFactory.java index b6b2cccc466..817b3263d25 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/config/cloud/CloudConfigFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/config/cloud/CloudConfigFactory.java @@ -229,7 +229,6 @@ protected BufferedReader fetchProxyMetadata( HttpsURLConnection connection = (HttpsURLConnection) metadataServiceUrl.openConnection(); connection.setSSLSocketFactory(sslContext.getSocketFactory()); connection.setRequestMethod("GET"); - connection.setRequestProperty("host", "localhost"); return new BufferedReader( new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)); } catch (ConnectException e) { From 7689c5a81e89bce5598d9976a041068a1f5e2a7f Mon Sep 17 00:00:00 2001 From: SiyaoIsHiding <113857408+SiyaoIsHiding@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:30:58 +0800 Subject: [PATCH 348/395] JAVA-3118: Add support for vector data type in Schema Builder, QueryBuilder patch by Jane He; reviewed by Mick Semb Wever and Bret McGuire for JAVA-3118 reference: #1931 --- manual/query_builder/select/README.md | 23 +++++ query-builder/revapi.json | 10 +++ .../api/querybuilder/select/Select.java | 11 +++ .../querybuilder/select/DefaultSelect.java | 86 +++++++++++++++++-- .../delete/DeleteSelectorTest.java | 11 +++ .../insert/RegularInsertTest.java | 7 ++ .../querybuilder/schema/AlterTableTest.java | 6 ++ .../querybuilder/schema/AlterTypeTest.java | 6 ++ .../querybuilder/schema/CreateTableTest.java | 9 ++ .../querybuilder/schema/CreateTypeTest.java | 9 ++ .../select/SelectOrderingTest.java | 20 +++++ .../select/SelectSelectorTest.java | 43 ++++++++++ 12 files changed, 233 insertions(+), 8 deletions(-) diff --git a/manual/query_builder/select/README.md b/manual/query_builder/select/README.md index 92c058608e7..0425423a402 100644 --- a/manual/query_builder/select/README.md +++ b/manual/query_builder/select/README.md @@ -387,6 +387,29 @@ selectFrom("sensor_data") // SELECT reading FROM sensor_data WHERE id=? ORDER BY date DESC ``` +Vector Search: + +```java + +import com.datastax.oss.driver.api.core.data.CqlVector; + +selectFrom("foo") + .all() + .where(Relation.column("k").isEqualTo(literal(1))) + .orderByAnnOf("c1", CqlVector.newInstance(0.1, 0.2, 0.3)); +// SELECT * FROM foo WHERE k=1 ORDER BY c1 ANN OF [0.1, 0.2, 0.3] + +selectFrom("cycling", "comments_vs") + .column("comment") + .function( + "similarity_cosine", + Selector.column("comment_vector"), + literal(CqlVector.newInstance(0.2, 0.15, 0.3, 0.2, 0.05))) + .orderByAnnOf("comment_vector", CqlVector.newInstance(0.1, 0.15, 0.3, 0.12, 0.05)) + .limit(1); +// SELECT comment,similarity_cosine(comment_vector,[0.2, 0.15, 0.3, 0.2, 0.05]) FROM cycling.comments_vs ORDER BY comment_vector ANN OF [0.1, 0.15, 0.3, 0.12, 0.05] LIMIT 1 +``` + Limits: ```java diff --git a/query-builder/revapi.json b/query-builder/revapi.json index 9d0163b487e..c4d8aa27212 100644 --- a/query-builder/revapi.json +++ b/query-builder/revapi.json @@ -2772,6 +2772,16 @@ "code": "java.method.addedToInterface", "new": "method com.datastax.oss.driver.api.querybuilder.update.UpdateStart com.datastax.oss.driver.api.querybuilder.update.UpdateStart::usingTtl(int)", "justification": "JAVA-2210: Add ability to set TTL for modification queries" + }, + { + "code": "java.method.addedToInterface", + "new": "method com.datastax.oss.driver.api.querybuilder.select.Select com.datastax.oss.driver.api.querybuilder.select.Select::orderByAnnOf(java.lang.String, com.datastax.oss.driver.api.core.data.CqlVector)", + "justification": "JAVA-3118: Add support for vector data type in Schema Builder, QueryBuilder" + }, + { + "code": "java.method.addedToInterface", + "new": "method com.datastax.oss.driver.api.querybuilder.select.Select com.datastax.oss.driver.api.querybuilder.select.Select::orderByAnnOf(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector)", + "justification": "JAVA-3118: Add support for vector data type in Schema Builder, QueryBuilder" } ] } diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/select/Select.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/select/Select.java index a22b45c35bd..159657989da 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/select/Select.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/select/Select.java @@ -18,6 +18,7 @@ package com.datastax.oss.driver.api.querybuilder.select; import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder; import com.datastax.oss.driver.api.querybuilder.BindMarker; import com.datastax.oss.driver.api.querybuilder.BuildableQuery; @@ -146,6 +147,16 @@ default Select orderBy(@NonNull String columnName, @NonNull ClusteringOrder orde return orderBy(CqlIdentifier.fromCql(columnName), order); } + /** + * Shortcut for {@link #orderByAnnOf(CqlIdentifier, CqlVector)}, adding an ORDER BY ... ANN OF ... + * clause + */ + @NonNull + Select orderByAnnOf(@NonNull String columnName, @NonNull CqlVector ann); + + /** Adds the ORDER BY ... ANN OF ... clause, usually used for vector search */ + @NonNull + Select orderByAnnOf(@NonNull CqlIdentifier columnId, @NonNull CqlVector ann); /** * Adds a LIMIT clause to this query with a literal value. * diff --git a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/select/DefaultSelect.java b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/select/DefaultSelect.java index 86a2a07a3f2..5daf252a9eb 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/select/DefaultSelect.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/internal/querybuilder/select/DefaultSelect.java @@ -20,8 +20,10 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.SimpleStatementBuilder; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder; import com.datastax.oss.driver.api.querybuilder.BindMarker; +import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import com.datastax.oss.driver.api.querybuilder.relation.Relation; import com.datastax.oss.driver.api.querybuilder.select.Select; import com.datastax.oss.driver.api.querybuilder.select.SelectFrom; @@ -49,6 +51,7 @@ public class DefaultSelect implements SelectFrom, Select { private final ImmutableList relations; private final ImmutableList groupByClauses; private final ImmutableMap orderings; + private final Ann ann; private final Object limit; private final Object perPartitionLimit; private final boolean allowsFiltering; @@ -65,6 +68,7 @@ public DefaultSelect(@Nullable CqlIdentifier keyspace, @NonNull CqlIdentifier ta ImmutableMap.of(), null, null, + null, false); } @@ -74,6 +78,8 @@ public DefaultSelect(@Nullable CqlIdentifier keyspace, @NonNull CqlIdentifier ta * @param selectors if it contains {@link AllSelector#INSTANCE}, that must be the only element. * This isn't re-checked because methods that call this constructor internally already do it, * make sure you do it yourself. + * @param ann Approximate nearest neighbor. ANN ordering does not support secondary ordering or + * ASC order. */ public DefaultSelect( @Nullable CqlIdentifier keyspace, @@ -84,6 +90,7 @@ public DefaultSelect( @NonNull ImmutableList relations, @NonNull ImmutableList groupByClauses, @NonNull ImmutableMap orderings, + @Nullable Ann ann, @Nullable Object limit, @Nullable Object perPartitionLimit, boolean allowsFiltering) { @@ -94,6 +101,9 @@ public DefaultSelect( || (limit instanceof Integer && (Integer) limit > 0) || limit instanceof BindMarker, "limit must be a strictly positive integer or a bind marker"); + Preconditions.checkArgument( + orderings.isEmpty() || ann == null, "ANN ordering does not support secondary ordering"); + this.ann = ann; this.keyspace = keyspace; this.table = table; this.isJson = isJson; @@ -117,6 +127,7 @@ public SelectFrom json() { relations, groupByClauses, orderings, + ann, limit, perPartitionLimit, allowsFiltering); @@ -134,6 +145,7 @@ public SelectFrom distinct() { relations, groupByClauses, orderings, + ann, limit, perPartitionLimit, allowsFiltering); @@ -193,6 +205,7 @@ public Select withSelectors(@NonNull ImmutableList newSelectors) { relations, groupByClauses, orderings, + ann, limit, perPartitionLimit, allowsFiltering); @@ -221,6 +234,7 @@ public Select withRelations(@NonNull ImmutableList newRelations) { newRelations, groupByClauses, orderings, + ann, limit, perPartitionLimit, allowsFiltering); @@ -249,6 +263,7 @@ public Select withGroupByClauses(@NonNull ImmutableList newGroupByClau relations, newGroupByClauses, orderings, + ann, limit, perPartitionLimit, allowsFiltering); @@ -260,6 +275,18 @@ public Select orderBy(@NonNull CqlIdentifier columnId, @NonNull ClusteringOrder return withOrderings(ImmutableCollections.append(orderings, columnId, order)); } + @NonNull + @Override + public Select orderByAnnOf(@NonNull String columnName, @NonNull CqlVector ann) { + return withAnn(new Ann(CqlIdentifier.fromCql(columnName), ann)); + } + + @NonNull + @Override + public Select orderByAnnOf(@NonNull CqlIdentifier columnId, @NonNull CqlVector ann) { + return withAnn(new Ann(columnId, ann)); + } + @NonNull @Override public Select orderByIds(@NonNull Map newOrderings) { @@ -277,6 +304,24 @@ public Select withOrderings(@NonNull ImmutableMap entry : orderings.entrySet()) { - if (first) { - builder.append(" ORDER BY "); - first = false; - } else { - builder.append(","); + if (ann != null) { + builder.append(" ORDER BY ").append(this.ann.columnId.asCql(true)).append(" ANN OF "); + QueryBuilder.literal(ann.vector).appendTo(builder); + } else { + boolean first = true; + for (Map.Entry entry : orderings.entrySet()) { + if (first) { + builder.append(" ORDER BY "); + first = false; + } else { + builder.append(","); + } + builder.append(entry.getKey().asCql(true)).append(" ").append(entry.getValue().name()); } - builder.append(entry.getKey().asCql(true)).append(" ").append(entry.getValue().name()); } if (limit != null) { @@ -499,6 +554,11 @@ public Object getLimit() { return limit; } + @Nullable + public Ann getAnn() { + return ann; + } + @Nullable public Object getPerPartitionLimit() { return perPartitionLimit; @@ -512,4 +572,14 @@ public boolean allowsFiltering() { public String toString() { return asCql(); } + + public static class Ann { + private final CqlVector vector; + private final CqlIdentifier columnId; + + private Ann(CqlIdentifier columnId, CqlVector vector) { + this.vector = vector; + this.columnId = columnId; + } + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/delete/DeleteSelectorTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/delete/DeleteSelectorTest.java index 23210971bc6..cce4cf51a10 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/delete/DeleteSelectorTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/delete/DeleteSelectorTest.java @@ -22,6 +22,7 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.deleteFrom; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; +import com.datastax.oss.driver.api.core.data.CqlVector; import org.junit.Test; public class DeleteSelectorTest { @@ -34,6 +35,16 @@ public void should_generate_column_deletion() { .hasCql("DELETE v FROM ks.foo WHERE k=?"); } + @Test + public void should_generate_vector_deletion() { + assertThat( + deleteFrom("foo") + .column("v") + .whereColumn("k") + .isEqualTo(literal(CqlVector.newInstance(0.1, 0.2)))) + .hasCql("DELETE v FROM foo WHERE k=[0.1, 0.2]"); + } + @Test public void should_generate_field_deletion() { assertThat( diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java index 36133445b34..89c833ff1c6 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/insert/RegularInsertTest.java @@ -23,6 +23,7 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; import static org.assertj.core.api.Assertions.catchThrowable; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.querybuilder.term.Term; import com.datastax.oss.driver.internal.querybuilder.insert.DefaultInsert; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; @@ -41,6 +42,12 @@ public void should_generate_column_assignments() { .hasCql("INSERT INTO foo (a,b) VALUES (?,?)"); } + @Test + public void should_generate_vector_literals() { + assertThat(insertInto("foo").value("a", literal(CqlVector.newInstance(0.1, 0.2, 0.3)))) + .hasCql("INSERT INTO foo (a) VALUES ([0.1, 0.2, 0.3])"); + } + @Test public void should_keep_last_assignment_if_column_listed_twice() { assertThat( diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java index 1567b0848cf..2c99b154b38 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTableTest.java @@ -108,4 +108,10 @@ public void should_generate_alter_table_with_no_compression() { assertThat(alterTable("bar").withNoCompression()) .hasCql("ALTER TABLE bar WITH compression={'sstable_compression':''}"); } + + @Test + public void should_generate_alter_table_with_vector() { + assertThat(alterTable("bar").alterColumn("v", DataTypes.vectorOf(DataTypes.FLOAT, 3))) + .hasCql("ALTER TABLE bar ALTER v TYPE vector"); + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTypeTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTypeTest.java index 2becb9338f9..14bec0a6ce3 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTypeTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/AlterTypeTest.java @@ -53,4 +53,10 @@ public void should_generate_alter_table_with_rename_three_columns() { assertThat(alterType("bar").renameField("x", "y").renameField("u", "v").renameField("b", "a")) .hasCql("ALTER TYPE bar RENAME x TO y AND u TO v AND b TO a"); } + + @Test + public void should_generate_alter_type_with_vector() { + assertThat(alterType("foo", "bar").alterField("vec", DataTypes.vectorOf(DataTypes.FLOAT, 3))) + .hasCql("ALTER TYPE foo.bar ALTER vec TYPE vector"); + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java index 7a5542c51f0..15cd12c75eb 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java @@ -314,4 +314,13 @@ public void should_generate_create_table_time_window_compaction() { .hasCql( "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compaction={'class':'TimeWindowCompactionStrategy','compaction_window_size':10,'compaction_window_unit':'DAYS','timestamp_resolution':'MICROSECONDS','unsafe_aggressive_sstable_expiration':false}"); } + + @Test + public void should_generate_vector_column() { + assertThat( + createTable("foo") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.vectorOf(DataTypes.FLOAT, 3))) + .hasCql("CREATE TABLE foo (k int PRIMARY KEY,v vector)"); + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTypeTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTypeTest.java index d881a0500cb..f7c15788a0f 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTypeTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTypeTest.java @@ -83,4 +83,13 @@ public void should_create_type_with_collections() { .withField("map", DataTypes.mapOf(DataTypes.INT, DataTypes.TEXT))) .hasCql("CREATE TYPE ks1.type (map map)"); } + + @Test + public void should_create_type_with_vector() { + assertThat( + createType("ks1", "type") + .withField("c1", DataTypes.INT) + .withField("vec", DataTypes.vectorOf(DataTypes.FLOAT, 3))) + .hasCql("CREATE TYPE ks1.type (c1 int,vec vector)"); + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectOrderingTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectOrderingTest.java index ff27fde4f8f..a9c618e9559 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectOrderingTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectOrderingTest.java @@ -23,6 +23,7 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.querybuilder.relation.Relation; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import org.junit.Test; @@ -74,4 +75,23 @@ public void should_replace_previous_ordering() { .orderBy(ImmutableMap.of("c1", DESC, "c2", ASC))) .hasCql("SELECT * FROM foo WHERE k=1 ORDER BY c3 ASC,c1 DESC,c2 ASC"); } + + @Test + public void should_generate_ann_clause() { + assertThat( + selectFrom("foo") + .all() + .where(Relation.column("k").isEqualTo(literal(1))) + .orderByAnnOf("c1", CqlVector.newInstance(0.1, 0.2, 0.3))) + .hasCql("SELECT * FROM foo WHERE k=1 ORDER BY c1 ANN OF [0.1, 0.2, 0.3]"); + } + + @Test(expected = IllegalArgumentException.class) + public void should_fail_when_provided_ann_with_other_orderings() { + selectFrom("foo") + .all() + .where(Relation.column("k").isEqualTo(literal(1))) + .orderBy("c1", ASC) + .orderByAnnOf("c2", CqlVector.newInstance(0.1, 0.2, 0.3)); + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectSelectorTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectSelectorTest.java index dc7cc98c6cc..7e03627d4b7 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectSelectorTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/select/SelectSelectorTest.java @@ -22,6 +22,7 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.raw; import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.type.DataTypes; import com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException; import com.datastax.oss.driver.api.querybuilder.CharsetCodec; @@ -230,6 +231,48 @@ public void should_generate_raw_selector() { .hasCql("SELECT bar,baz FROM foo"); } + @Test + public void should_generate_similarity_functions() { + Select similarity_cosine_clause = + selectFrom("cycling", "comments_vs") + .column("comment") + .function( + "similarity_cosine", + Selector.column("comment_vector"), + literal(CqlVector.newInstance(0.2, 0.15, 0.3, 0.2, 0.05))) + .orderByAnnOf("comment_vector", CqlVector.newInstance(0.1, 0.15, 0.3, 0.12, 0.05)) + .limit(1); + assertThat(similarity_cosine_clause) + .hasCql( + "SELECT comment,similarity_cosine(comment_vector,[0.2, 0.15, 0.3, 0.2, 0.05]) FROM cycling.comments_vs ORDER BY comment_vector ANN OF [0.1, 0.15, 0.3, 0.12, 0.05] LIMIT 1"); + + Select similarity_euclidean_clause = + selectFrom("cycling", "comments_vs") + .column("comment") + .function( + "similarity_euclidean", + Selector.column("comment_vector"), + literal(CqlVector.newInstance(0.2, 0.15, 0.3, 0.2, 0.05))) + .orderByAnnOf("comment_vector", CqlVector.newInstance(0.1, 0.15, 0.3, 0.12, 0.05)) + .limit(1); + assertThat(similarity_euclidean_clause) + .hasCql( + "SELECT comment,similarity_euclidean(comment_vector,[0.2, 0.15, 0.3, 0.2, 0.05]) FROM cycling.comments_vs ORDER BY comment_vector ANN OF [0.1, 0.15, 0.3, 0.12, 0.05] LIMIT 1"); + + Select similarity_dot_product_clause = + selectFrom("cycling", "comments_vs") + .column("comment") + .function( + "similarity_dot_product", + Selector.column("comment_vector"), + literal(CqlVector.newInstance(0.2, 0.15, 0.3, 0.2, 0.05))) + .orderByAnnOf("comment_vector", CqlVector.newInstance(0.1, 0.15, 0.3, 0.12, 0.05)) + .limit(1); + assertThat(similarity_dot_product_clause) + .hasCql( + "SELECT comment,similarity_dot_product(comment_vector,[0.2, 0.15, 0.3, 0.2, 0.05]) FROM cycling.comments_vs ORDER BY comment_vector ANN OF [0.1, 0.15, 0.3, 0.12, 0.05] LIMIT 1"); + } + @Test public void should_alias_selectors() { assertThat(selectFrom("foo").column("bar").as("baz")).hasCql("SELECT bar AS baz FROM foo"); From 8c1009959e988d9f7249151ad260f64aa6afed63 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 23 Dec 2024 08:20:42 +0100 Subject: [PATCH 349/395] Upgrade Guava to 33.3.1-jre patch by Lukasz Antoniak; reviewed by Alexandre Dutra and Bret McGuire for CASSJAVA-53 --- .../internal/core/cql/reactive/TestSubscriber.java | 5 +++-- guava-shaded/pom.xml | 10 ++-------- .../dse/driver/api/mapper/reactive/TestSubscriber.java | 6 +++++- pom.xml | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java index aed7a4dfc8e..652155e5309 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/cql/reactive/TestSubscriber.java @@ -81,7 +81,8 @@ public List getElements() { } public void awaitTermination() { - Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES); - if (latch.getCount() > 0) fail("subscriber not terminated"); + if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES)) { + fail("subscriber not terminated"); + } } } diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index 9854fcc48ba..f480f9258cc 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -45,14 +45,6 @@ com.google.errorprone error_prone_annotations - - com.google.j2objc - j2objc-annotations - - - org.codehaus.mojo - animal-sniffer-annotations - @@ -78,6 +70,8 @@ org.apache.cassandra:java-driver-guava-shaded com.google.guava:guava + com.google.guava:failureaccess + com.google.j2objc:j2objc-annotations diff --git a/mapper-runtime/src/test/java/com/datastax/dse/driver/api/mapper/reactive/TestSubscriber.java b/mapper-runtime/src/test/java/com/datastax/dse/driver/api/mapper/reactive/TestSubscriber.java index 6f23cfca98a..6886b9a7622 100644 --- a/mapper-runtime/src/test/java/com/datastax/dse/driver/api/mapper/reactive/TestSubscriber.java +++ b/mapper-runtime/src/test/java/com/datastax/dse/driver/api/mapper/reactive/TestSubscriber.java @@ -17,6 +17,8 @@ */ package com.datastax.dse.driver.api.mapper.reactive; +import static org.assertj.core.api.Fail.fail; + import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -70,6 +72,8 @@ public List getElements() { } public void awaitTermination() { - Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES); + if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.MINUTES)) { + fail("subscriber not terminated"); + } } } diff --git a/pom.xml b/pom.xml index 620cf1db4bb..c61e6485fd3 100644 --- a/pom.xml +++ b/pom.xml @@ -114,7 +114,7 @@ com.google.guava guava - 25.1-jre + 33.3.1-jre com.typesafe From 75a269d04d49630032be6afedae2ded0c4334e42 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 30 Dec 2024 07:18:06 +0100 Subject: [PATCH 350/395] Do not always cleanup Guava shaded module before packaging --- guava-shaded/pom.xml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index f480f9258cc..6a22663e956 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -94,21 +94,6 @@ - - maven-clean-plugin - - - clean-classes - package - - clean - - - ${project.build.outputDirectory} - - - - maven-dependency-plugin From 01671d99247bdc783c832c128a8570ba846875c4 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Fri, 10 Jan 2025 16:05:42 +0100 Subject: [PATCH 351/395] Revert "Do not always cleanup Guava shaded module before packaging" This reverts commit 5be52ec1a8d014c81566180c731b828a591082da. --- guava-shaded/pom.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index 6a22663e956..f480f9258cc 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -94,6 +94,21 @@ + + maven-clean-plugin + + + clean-classes + package + + clean + + + ${project.build.outputDirectory} + + + + maven-dependency-plugin From 342e2dcf47afab238f357ac2afde65b079ce6b79 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Fri, 10 Jan 2025 16:16:26 +0100 Subject: [PATCH 352/395] Conditionally compile shaded Guava module --- guava-shaded/pom.xml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index f480f9258cc..ca8f0161b04 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -56,6 +56,32 @@ + + + org.codehaus.mojo + build-helper-maven-plugin + 1.12 + + + regex-property + + regex-property + + + maven.main.skip + ${java.version} + ^(?!1.8).+ + true + false + + + + maven-shade-plugin @@ -95,6 +121,12 @@ + maven-clean-plugin From 2e0c44c020819c928730e1aac812bf2f475d8256 Mon Sep 17 00:00:00 2001 From: SiyaoIsHiding <113857408+SiyaoIsHiding@users.noreply.github.com> Date: Sun, 26 Jan 2025 22:38:52 +0800 Subject: [PATCH 353/395] JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit patch by Jane He; reviewed by Bret McGuire and João Reis reference: https://github.com/apache/cassandra-java-driver/pull/1952 --- core/revapi.json | 297 ++++++++++++++++++ .../oss/driver/api/core/data/CqlVector.java | 72 ++++- .../driver/api/core/data/GettableById.java | 2 +- .../driver/api/core/data/GettableByIndex.java | 3 +- .../driver/api/core/data/GettableByName.java | 2 +- .../driver/api/core/data/SettableById.java | 2 +- .../driver/api/core/data/SettableByIndex.java | 2 +- .../driver/api/core/data/SettableByName.java | 2 +- .../oss/driver/api/core/type/DataTypes.java | 19 +- .../driver/api/core/type/codec/TypeCodec.java | 6 + .../api/core/type/codec/TypeCodecs.java | 4 +- .../api/core/type/reflect/GenericType.java | 6 +- .../parsing/DataTypeClassNameParser.java | 8 + .../internal/core/type/DefaultVectorType.java | 2 +- .../internal/core/type/codec/BigIntCodec.java | 7 + .../core/type/codec/BooleanCodec.java | 7 + .../internal/core/type/codec/DoubleCodec.java | 7 + .../internal/core/type/codec/FloatCodec.java | 7 + .../internal/core/type/codec/IntCodec.java | 7 + .../core/type/codec/TimestampCodec.java | 7 + .../internal/core/type/codec/UuidCodec.java | 7 + .../internal/core/type/codec/VectorCodec.java | 86 +++-- .../extras/time/TimestampMillisCodec.java | 7 + .../codec/registry/CachingCodecRegistry.java | 12 +- .../internal/core/type/util/VIntCoding.java | 77 ++++- .../driver/api/core/data/CqlVectorTest.java | 167 +++++----- .../core/type/codec/VectorCodecTest.java | 265 ++++++++++++---- ...CachingCodecRegistryTestDataProviders.java | 20 ++ .../core/type/util/VIntCodingTest.java | 86 +++++ .../oss/driver/core/data/DataTypeIT.java | 38 ++- 30 files changed, 1002 insertions(+), 232 deletions(-) create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/type/util/VIntCodingTest.java diff --git a/core/revapi.json b/core/revapi.json index 1c875895d6c..5aa46a3ccad 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -7089,6 +7089,303 @@ "new": "method com.datastax.oss.driver.api.core.cql.SimpleStatement com.datastax.oss.driver.api.core.cql.SimpleStatement::setNamedValues(java.util.Map)", "annotation": "@edu.umd.cs.findbugs.annotations.CheckReturnValue", "justification": "Annotate mutating methods with @CheckReturnValue" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::from(java.lang.String, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "new": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::from(java.lang.String, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::from(java.lang.String, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::from(java.lang.String, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::from(java.lang.String, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::from(java.lang.String, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeChanged", + "old": "method T com.datastax.oss.driver.api.core.data.CqlVector::get(int)", + "new": "method T com.datastax.oss.driver.api.core.data.CqlVector::get(int)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method java.util.Iterator com.datastax.oss.driver.api.core.data.CqlVector::iterator()", + "new": "method java.util.Iterator com.datastax.oss.driver.api.core.data.CqlVector::iterator()", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeChanged", + "old": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(===V[]===)", + "new": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(===V[]===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(V[])", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(V[])", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(V[])", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(V[])", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(===java.util.List===)", + "new": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(===java.util.List===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(java.util.List)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(java.util.List)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(java.util.List)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::newInstance(java.util.List)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeChanged", + "old": "parameter T com.datastax.oss.driver.api.core.data.CqlVector::set(int, ===T===)", + "new": "parameter T com.datastax.oss.driver.api.core.data.CqlVector::set(int, ===T===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeChanged", + "old": "method T com.datastax.oss.driver.api.core.data.CqlVector::set(int, T)", + "new": "method T com.datastax.oss.driver.api.core.data.CqlVector::set(int, T)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method java.util.Spliterator java.lang.Iterable::spliterator() @ com.datastax.oss.driver.api.core.data.CqlVector", + "new": "method java.util.Spliterator java.lang.Iterable::spliterator() @ com.datastax.oss.driver.api.core.data.CqlVector", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method java.util.stream.Stream com.datastax.oss.driver.api.core.data.CqlVector::stream()", + "new": "method java.util.stream.Stream com.datastax.oss.driver.api.core.data.CqlVector::stream()", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::subVector(int, int)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.CqlVector::subVector(int, int)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.class.noLongerImplementsInterface", + "old": "class com.datastax.oss.driver.api.core.data.CqlVector", + "new": "class com.datastax.oss.driver.api.core.data.CqlVector", + "interface": "java.lang.Iterable", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "class com.datastax.oss.driver.api.core.data.CqlVector", + "new": "class com.datastax.oss.driver.api.core.data.CqlVector", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.class.superTypeTypeParametersChanged", + "old": "class com.datastax.oss.driver.api.core.data.CqlVector", + "new": "class com.datastax.oss.driver.api.core.data.CqlVector", + "oldSuperType": "java.lang.Iterable", + "newSuperType": "java.lang.Iterable", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getVector(com.datastax.oss.driver.api.core.CqlIdentifier, ===java.lang.Class===)", + "new": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getVector(com.datastax.oss.driver.api.core.CqlIdentifier, ===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getVector(com.datastax.oss.driver.api.core.CqlIdentifier, java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getVector(com.datastax.oss.driver.api.core.CqlIdentifier, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getVector(com.datastax.oss.driver.api.core.CqlIdentifier, java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableById::getVector(com.datastax.oss.driver.api.core.CqlIdentifier, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getVector(int, ===java.lang.Class===)", + "new": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getVector(int, ===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getVector(int, java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getVector(int, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getVector(int, java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByIndex::getVector(int, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getVector(java.lang.String, ===java.lang.Class===)", + "new": "parameter com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getVector(java.lang.String, ===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getVector(java.lang.String, java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getVector(java.lang.String, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getVector(java.lang.String, java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.data.CqlVector com.datastax.oss.driver.api.core.data.GettableByName::getVector(java.lang.String, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableById>::setVector(com.datastax.oss.driver.api.core.CqlIdentifier, ===com.datastax.oss.driver.api.core.data.CqlVector===, java.lang.Class)", + "new": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableById>::setVector(com.datastax.oss.driver.api.core.CqlIdentifier, ===com.datastax.oss.driver.api.core.data.CqlVector===, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableById>::setVector(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector, ===java.lang.Class===)", + "new": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableById>::setVector(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector, ===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method SelfT com.datastax.oss.driver.api.core.data.SettableById>::setVector(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector, java.lang.Class)", + "new": "method SelfT com.datastax.oss.driver.api.core.data.SettableById>::setVector(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setVector(int, ===com.datastax.oss.driver.api.core.data.CqlVector===, java.lang.Class)", + "new": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setVector(int, ===com.datastax.oss.driver.api.core.data.CqlVector===, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setVector(int, com.datastax.oss.driver.api.core.data.CqlVector, ===java.lang.Class===)", + "new": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setVector(int, com.datastax.oss.driver.api.core.data.CqlVector, ===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setVector(int, com.datastax.oss.driver.api.core.data.CqlVector, java.lang.Class)", + "new": "method SelfT com.datastax.oss.driver.api.core.data.SettableByIndex>::setVector(int, com.datastax.oss.driver.api.core.data.CqlVector, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setVector(java.lang.String, ===com.datastax.oss.driver.api.core.data.CqlVector===, java.lang.Class)", + "new": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setVector(java.lang.String, ===com.datastax.oss.driver.api.core.data.CqlVector===, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setVector(java.lang.String, com.datastax.oss.driver.api.core.data.CqlVector, ===java.lang.Class===)", + "new": "parameter SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setVector(java.lang.String, com.datastax.oss.driver.api.core.data.CqlVector, ===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setVector(java.lang.String, com.datastax.oss.driver.api.core.data.CqlVector, java.lang.Class)", + "new": "method SelfT com.datastax.oss.driver.api.core.data.SettableByName>::setVector(java.lang.String, com.datastax.oss.driver.api.core.data.CqlVector, java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "new": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(com.datastax.oss.driver.api.core.type.VectorType, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(int, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "new": "parameter com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(int, ===com.datastax.oss.driver.api.core.type.codec.TypeCodec===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(int, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(int, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(int, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "new": "method com.datastax.oss.driver.api.core.type.codec.TypeCodec> com.datastax.oss.driver.api.core.type.codec.TypeCodecs::vectorOf(int, com.datastax.oss.driver.api.core.type.codec.TypeCodec)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(===com.datastax.oss.driver.api.core.type.reflect.GenericType===)", + "new": "parameter com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(===com.datastax.oss.driver.api.core.type.reflect.GenericType===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(com.datastax.oss.driver.api.core.type.reflect.GenericType)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(===java.lang.Class===)", + "new": "parameter com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(===java.lang.Class===)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.method.returnTypeTypeParametersChanged", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.generics.formalTypeParameterChanged", + "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(java.lang.Class)", + "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(java.lang.Class)", + "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" } ] } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java index 911b6187f6d..8089d551750 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java @@ -18,11 +18,10 @@ package com.datastax.oss.driver.api.core.data; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import com.datastax.oss.driver.internal.core.type.codec.ParseUtils; import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import com.datastax.oss.driver.shaded.guava.common.base.Predicates; -import com.datastax.oss.driver.shaded.guava.common.base.Splitter; import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; -import com.datastax.oss.driver.shaded.guava.common.collect.Streams; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.IOException; import java.io.InvalidObjectException; @@ -35,7 +34,6 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -52,7 +50,7 @@ * where possible we've tried to make the API of this class similar to the equivalent methods on * {@link List}. */ -public class CqlVector implements Iterable, Serializable { +public class CqlVector implements Iterable, Serializable { /** * Create a new CqlVector containing the specified values. @@ -60,7 +58,7 @@ public class CqlVector implements Iterable, Serializable { * @param vals the collection of values to wrap. * @return a CqlVector wrapping those values */ - public static CqlVector newInstance(V... vals) { + public static CqlVector newInstance(V... vals) { // Note that Array.asList() guarantees the return of an array which implements RandomAccess return new CqlVector(Arrays.asList(vals)); @@ -73,29 +71,64 @@ public static CqlVector newInstance(V... vals) { * @param list the collection of values to wrap. * @return a CqlVector wrapping those values */ - public static CqlVector newInstance(List list) { + public static CqlVector newInstance(List list) { Preconditions.checkArgument(list != null, "Input list should not be null"); return new CqlVector(list); } /** - * Create a new CqlVector instance from the specified string representation. Note that this method - * is intended to mirror {@link #toString()}; passing this method the output from a toString - * call on some CqlVector should return a CqlVector that is equal to the origin instance. + * Create a new CqlVector instance from the specified string representation. * * @param str a String representation of a CqlVector * @param subtypeCodec * @return a new CqlVector built from the String representation */ - public static CqlVector from( - @NonNull String str, @NonNull TypeCodec subtypeCodec) { + public static CqlVector from(@NonNull String str, @NonNull TypeCodec subtypeCodec) { Preconditions.checkArgument(str != null, "Cannot create CqlVector from null string"); Preconditions.checkArgument(!str.isEmpty(), "Cannot create CqlVector from empty string"); - ArrayList vals = - Streams.stream(Splitter.on(", ").split(str.substring(1, str.length() - 1))) - .map(subtypeCodec::parse) - .collect(Collectors.toCollection(ArrayList::new)); - return new CqlVector(vals); + if (str.equalsIgnoreCase("NULL")) return null; + + int idx = ParseUtils.skipSpaces(str, 0); + if (str.charAt(idx++) != '[') + throw new IllegalArgumentException( + String.format( + "Cannot parse vector value from \"%s\", at character %d expecting '[' but got '%c'", + str, idx, str.charAt(idx))); + + idx = ParseUtils.skipSpaces(str, idx); + + if (str.charAt(idx) == ']') { + return new CqlVector<>(new ArrayList<>()); + } + + List list = new ArrayList<>(); + while (idx < str.length()) { + int n; + try { + n = ParseUtils.skipCQLValue(str, idx); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException( + String.format( + "Cannot parse vector value from \"%s\", invalid CQL value at character %d", + str, idx), + e); + } + + list.add(subtypeCodec.parse(str.substring(idx, n))); + idx = n; + + idx = ParseUtils.skipSpaces(str, idx); + if (str.charAt(idx) == ']') return new CqlVector<>(list); + if (str.charAt(idx++) != ',') + throw new IllegalArgumentException( + String.format( + "Cannot parse vector value from \"%s\", at character %d expecting ',' but got '%c'", + str, idx, str.charAt(idx))); + + idx = ParseUtils.skipSpaces(str, idx); + } + throw new IllegalArgumentException( + String.format("Malformed vector value \"%s\", missing closing ']'", str)); } private final List list; @@ -194,6 +227,11 @@ public int hashCode() { return Objects.hash(list); } + /** + * The string representation of the vector. Elements, like strings, may not be properly quoted. + * + * @return the string representation + */ @Override public String toString() { return Iterables.toString(this.list); @@ -205,7 +243,7 @@ public String toString() { * * @param inner type of CqlVector, assume Number is always Serializable. */ - private static class SerializationProxy implements Serializable { + private static class SerializationProxy implements Serializable { private static final long serialVersionUID = 1; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java index 0a24214b20a..8393bc9f758 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java @@ -531,7 +531,7 @@ default CqlDuration getCqlDuration(@NonNull CqlIdentifier id) { * @throws IllegalArgumentException if the id is invalid. */ @Nullable - default CqlVector getVector( + default CqlVector getVector( @NonNull CqlIdentifier id, @NonNull Class elementsClass) { return getVector(firstIndexOf(id), elementsClass); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java index 53541b0ac58..bb75bd9a2b4 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java @@ -446,8 +446,7 @@ default CqlDuration getCqlDuration(int i) { * @throws IndexOutOfBoundsException if the index is invalid. */ @Nullable - default CqlVector getVector( - int i, @NonNull Class elementsClass) { + default CqlVector getVector(int i, @NonNull Class elementsClass) { return get(i, GenericType.vectorOf(elementsClass)); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java index ec3ee362ca8..b0a4660033b 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java @@ -527,7 +527,7 @@ default CqlDuration getCqlDuration(@NonNull String name) { * @throws IllegalArgumentException if the name is invalid. */ @Nullable - default CqlVector getVector( + default CqlVector getVector( @NonNull String name, @NonNull Class elementsClass) { return getVector(firstIndexOf(name), elementsClass); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java index 8452446205e..0f5e3cd9daa 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java @@ -573,7 +573,7 @@ default SelfT setCqlDuration(@NonNull CqlIdentifier id, @Nullable CqlDuration v) */ @NonNull @CheckReturnValue - default SelfT setVector( + default SelfT setVector( @NonNull CqlIdentifier id, @Nullable CqlVector v, @NonNull Class elementsClass) { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java index bb55db3adde..4ecdf647590 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java @@ -425,7 +425,7 @@ default SelfT setCqlDuration(int i, @Nullable CqlDuration v) { */ @NonNull @CheckReturnValue - default SelfT setVector( + default SelfT setVector( int i, @Nullable CqlVector v, @NonNull Class elementsClass) { return set(i, v, GenericType.vectorOf(elementsClass)); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java index c25a7074373..afe9ba59f64 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java @@ -572,7 +572,7 @@ default SelfT setCqlDuration(@NonNull String name, @Nullable CqlDuration v) { */ @NonNull @CheckReturnValue - default SelfT setVector( + default SelfT setVector( @NonNull String name, @Nullable CqlVector v, @NonNull Class elementsClass) { diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java index 3a341eaa5aa..492fc121c71 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java @@ -27,12 +27,10 @@ import com.datastax.oss.driver.internal.core.type.DefaultTupleType; import com.datastax.oss.driver.internal.core.type.DefaultVectorType; import com.datastax.oss.driver.internal.core.type.PrimitiveType; -import com.datastax.oss.driver.shaded.guava.common.base.Splitter; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.protocol.internal.ProtocolConstants; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; -import java.util.List; /** Constants and factory methods to obtain data type instances. */ public class DataTypes { @@ -59,7 +57,6 @@ public class DataTypes { public static final DataType DURATION = new PrimitiveType(ProtocolConstants.DataType.DURATION); private static final DataTypeClassNameParser classNameParser = new DataTypeClassNameParser(); - private static final Splitter paramSplitter = Splitter.on(',').trimResults(); @NonNull public static DataType custom(@NonNull String className) { @@ -68,20 +65,8 @@ public static DataType custom(@NonNull String className) { if (className.equals("org.apache.cassandra.db.marshal.DurationType")) return DURATION; /* Vector support is currently implemented as a custom type but is also parameterized */ - if (className.startsWith(DefaultVectorType.VECTOR_CLASS_NAME)) { - List params = - paramSplitter.splitToList( - className.substring( - DefaultVectorType.VECTOR_CLASS_NAME.length() + 1, className.length() - 1)); - DataType subType = classNameParser.parse(params.get(0), AttachmentPoint.NONE); - int dimensions = Integer.parseInt(params.get(1)); - if (dimensions <= 0) { - throw new IllegalArgumentException( - String.format( - "Request to create vector of size %d, size must be positive", dimensions)); - } - return new DefaultVectorType(subType, dimensions); - } + if (className.startsWith(DefaultVectorType.VECTOR_CLASS_NAME)) + return classNameParser.parse(className, AttachmentPoint.NONE); return new DefaultCustomType(className); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodec.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodec.java index 05ae3980823..d6afbe0380a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodec.java @@ -28,6 +28,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; /** * Manages the two-way conversion between a CQL type and a Java type. @@ -234,4 +235,9 @@ default boolean accepts(@NonNull DataType cqlType) { */ @Nullable JavaTypeT parse(@Nullable String value); + + @NonNull + default Optional serializedSize() { + return Optional.empty(); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java index 9f2fd5cc69e..68f1b07b106 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodecs.java @@ -210,13 +210,13 @@ public static TypeCodec tupleOf(@NonNull TupleType cqlType) { return new TupleCodec(cqlType); } - public static TypeCodec> vectorOf( + public static TypeCodec> vectorOf( @NonNull VectorType type, @NonNull TypeCodec subtypeCodec) { return new VectorCodec( DataTypes.vectorOf(subtypeCodec.getCqlType(), type.getDimensions()), subtypeCodec); } - public static TypeCodec> vectorOf( + public static TypeCodec> vectorOf( int dimensions, @NonNull TypeCodec subtypeCodec) { return new VectorCodec(DataTypes.vectorOf(subtypeCodec.getCqlType(), dimensions), subtypeCodec); } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java index c6482d4f4d1..d22b6f1bfaf 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/type/reflect/GenericType.java @@ -151,8 +151,7 @@ public static GenericType> setOf(@NonNull GenericType elementType) } @NonNull - public static GenericType> vectorOf( - @NonNull Class elementType) { + public static GenericType> vectorOf(@NonNull Class elementType) { TypeToken> token = new TypeToken>() {}.where( new TypeParameter() {}, TypeToken.of(elementType)); @@ -160,8 +159,7 @@ public static GenericType> vectorOf( } @NonNull - public static GenericType> vectorOf( - @NonNull GenericType elementType) { + public static GenericType> vectorOf(@NonNull GenericType elementType) { TypeToken> token = new TypeToken>() {}.where(new TypeParameter() {}, elementType.token); return new GenericType<>(token); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParser.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParser.java index fd6f1a4bd51..bf252d0bc57 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParser.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/schema/parsing/DataTypeClassNameParser.java @@ -34,6 +34,7 @@ import com.datastax.oss.protocol.internal.util.Bytes; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -164,6 +165,13 @@ private DataType parse( return new DefaultTupleType(componentTypesBuilder.build(), attachmentPoint); } + if (next.startsWith("org.apache.cassandra.db.marshal.VectorType")) { + Iterator rawTypes = parser.getTypeParameters().iterator(); + DataType subtype = parse(rawTypes.next(), userTypes, attachmentPoint, logPrefix); + int dimensions = Integer.parseInt(rawTypes.next()); + return DataTypes.vectorOf(subtype, dimensions); + } + DataType type = NATIVE_TYPES_BY_CLASS_NAME.get(next); return type == null ? DataTypes.custom(toParse) : type; } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java index c9180d44edc..0b1ced94769 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/DefaultVectorType.java @@ -78,7 +78,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), subtype, dimensions); + return Objects.hash(DefaultVectorType.class, subtype, dimensions); } @Override diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodec.java index 2b3b8255cc1..8496da17fa6 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BigIntCodec.java @@ -25,6 +25,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -90,4 +91,10 @@ public Long parse(@Nullable String value) { String.format("Cannot parse 64-bits long value from \"%s\"", value)); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(8); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BooleanCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BooleanCodec.java index 7a982a9e6ca..af388982be9 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BooleanCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/BooleanCodec.java @@ -25,6 +25,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -98,4 +99,10 @@ public Boolean parse(@Nullable String value) { String.format("Cannot parse boolean value from \"%s\"", value)); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(1); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/DoubleCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/DoubleCodec.java index 28eff6f9463..b01847517d9 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/DoubleCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/DoubleCodec.java @@ -25,6 +25,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -90,4 +91,10 @@ public Double parse(@Nullable String value) { String.format("Cannot parse 64-bits double value from \"%s\"", value)); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(8); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/FloatCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/FloatCodec.java index 11786dbc77d..fd851edfad3 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/FloatCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/FloatCodec.java @@ -25,6 +25,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -90,4 +91,10 @@ public Float parse(@Nullable String value) { String.format("Cannot parse 32-bits float value from \"%s\"", value)); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(4); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/IntCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/IntCodec.java index e5bb530ba79..b11b164a445 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/IntCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/IntCodec.java @@ -25,6 +25,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; import net.jcip.annotations.ThreadSafe; @ThreadSafe @@ -90,4 +91,10 @@ public Integer parse(@Nullable String value) { String.format("Cannot parse 32-bits int value from \"%s\"", value)); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(4); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/TimestampCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/TimestampCodec.java index eeba3c7c66c..964f774c8d9 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/TimestampCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/TimestampCodec.java @@ -33,6 +33,7 @@ import java.time.Instant; import java.time.ZoneId; import java.util.Date; +import java.util.Optional; import java.util.TimeZone; import net.jcip.annotations.ThreadSafe; @@ -293,4 +294,10 @@ public Instant parse(@Nullable String value) { String.format("Cannot parse timestamp value from \"%s\"", value)); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(8); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UuidCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UuidCodec.java index 57feac4ae7e..cc5f48dbe52 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UuidCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/UuidCodec.java @@ -25,6 +25,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.Optional; import java.util.UUID; import net.jcip.annotations.ThreadSafe; @@ -95,4 +96,10 @@ public UUID parse(@Nullable String value) { String.format("Cannot parse UUID value from \"%s\"", value), e); } } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(16); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java index 2c4d2200b13..1f8ce1a7166 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodec.java @@ -24,7 +24,7 @@ import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import com.datastax.oss.driver.internal.core.type.DefaultVectorType; -import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; +import com.datastax.oss.driver.internal.core.type.util.VIntCoding; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.nio.ByteBuffer; @@ -32,8 +32,10 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.stream.Collectors; -public class VectorCodec implements TypeCodec> { +public class VectorCodec implements TypeCodec> { private final VectorType cqlType; private final GenericType> javaType; @@ -55,6 +57,14 @@ public GenericType> getJavaType() { return this.javaType; } + @NonNull + @Override + public Optional serializedSize() { + return subtypeCodec.serializedSize().isPresent() + ? Optional.of(subtypeCodec.serializedSize().get() * cqlType.getDimensions()) + : Optional.empty(); + } + @NonNull @Override public DataType getCqlType() { @@ -65,6 +75,7 @@ public DataType getCqlType() { @Override public ByteBuffer encode( @Nullable CqlVector value, @NonNull ProtocolVersion protocolVersion) { + boolean isVarSized = !subtypeCodec.serializedSize().isPresent(); if (value == null || cqlType.getDimensions() <= 0) { return null; } @@ -92,14 +103,28 @@ public ByteBuffer encode( if (valueBuff == null) { throw new NullPointerException("Vector elements cannot encode to CQL NULL"); } - allValueBuffsSize += valueBuff.limit(); + int elementSize = valueBuff.limit(); + if (isVarSized) { + allValueBuffsSize += VIntCoding.computeVIntSize(elementSize); + } + allValueBuffsSize += elementSize; valueBuff.rewind(); valueBuffs[i] = valueBuff; } + // if too many elements, throw + if (values.hasNext()) { + throw new IllegalArgumentException( + String.format( + "Too many elements; must provide elements for %d dimensions", + cqlType.getDimensions())); + } /* Since we already did an early return for <= 0 dimensions above */ assert valueBuffs.length > 0; ByteBuffer rv = ByteBuffer.allocate(allValueBuffsSize); for (int i = 0; i < cqlType.getDimensions(); ++i) { + if (isVarSized) { + VIntCoding.writeUnsignedVInt32(valueBuffs[i].remaining(), rv); + } rv.put(valueBuffs[i]); } rv.flip(); @@ -114,39 +139,58 @@ public CqlVector decode( return null; } - /* Determine element size by dividing count of remaining bytes by number of elements. This should have a remainder - of zero if we assume all elements are of uniform size (which is really a terrible assumption). - - TODO: We should probably tweak serialization format for vectors if we're going to allow them for arbitrary subtypes. - Elements should at least precede themselves with their size (along the lines of what lists do). */ - int elementSize = Math.floorDiv(bytes.remaining(), cqlType.getDimensions()); - if (!(bytes.remaining() % cqlType.getDimensions() == 0)) { - throw new IllegalArgumentException( - String.format( - "Expected elements of uniform size, observed %d elements with total bytes %d", - cqlType.getDimensions(), bytes.remaining())); - } - + // Upfront check for fixed-size types only + subtypeCodec + .serializedSize() + .ifPresent( + (fixed_size) -> { + if (bytes.remaining() != cqlType.getDimensions() * fixed_size) { + throw new IllegalArgumentException( + String.format( + "Expected elements of uniform size, observed %d elements with total bytes %d", + cqlType.getDimensions(), bytes.remaining())); + } + }); + ; ByteBuffer slice = bytes.slice(); List rv = new ArrayList(cqlType.getDimensions()); for (int i = 0; i < cqlType.getDimensions(); ++i) { - // Set the limit for the current element + + int size = + subtypeCodec + .serializedSize() + .orElseGet(() -> VIntCoding.getUnsignedVInt32(slice, slice.position())); + // If we aren't dealing with a fixed-size type we need to move the current slice position + // beyond the vint-encoded size of the current element. Ideally this would be + // serializedSize().ifNotPresent(Consumer) but the Optional API isn't doing us any favors + // there. + if (!subtypeCodec.serializedSize().isPresent()) + slice.position(slice.position() + VIntCoding.computeUnsignedVIntSize(size)); int originalPosition = slice.position(); - slice.limit(originalPosition + elementSize); + slice.limit(originalPosition + size); rv.add(this.subtypeCodec.decode(slice, protocolVersion)); // Move to the start of the next element - slice.position(originalPosition + elementSize); + slice.position(originalPosition + size); // Reset the limit to the end of the buffer slice.limit(slice.capacity()); } + // if too many elements, throw + if (slice.hasRemaining()) { + throw new IllegalArgumentException( + String.format( + "Too many elements; must provide elements for %d dimensions", + cqlType.getDimensions())); + } + return CqlVector.newInstance(rv); } @NonNull @Override - public String format(@Nullable CqlVector value) { - return value == null ? "NULL" : Iterables.toString(value); + public String format(CqlVector value) { + if (value == null) return "NULL"; + return value.stream().map(subtypeCodec::format).collect(Collectors.joining(", ", "[", "]")); } @Nullable diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/TimestampMillisCodec.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/TimestampMillisCodec.java index a15495a432d..12e3e839d2a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/TimestampMillisCodec.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/extras/time/TimestampMillisCodec.java @@ -31,6 +31,7 @@ import java.time.Instant; import java.time.ZoneId; import java.util.Objects; +import java.util.Optional; import net.jcip.annotations.Immutable; /** @@ -114,4 +115,10 @@ public String format(@Nullable Long value) { Instant instant = value == null ? null : Instant.ofEpochMilli(value); return timestampCodec.format(instant); } + + @NonNull + @Override + public Optional serializedSize() { + return Optional.of(8); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java index 495d6227d93..3af5a30ba27 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistry.java @@ -394,10 +394,9 @@ protected GenericType inspectType(@NonNull Object value, @Nullable DataType c "Can't infer vector codec because the first element is null " + "(note that CQL does not allow null values in collections)"); } - GenericType elementType = - (GenericType) - inspectType( - firstElement, cqlType == null ? null : ((VectorType) cqlType).getElementType()); + GenericType elementType = + inspectType( + firstElement, cqlType == null ? null : ((VectorType) cqlType).getElementType()); return GenericType.vectorOf(elementType); } } else { @@ -421,8 +420,7 @@ protected GenericType inferJavaTypeFromCqlType(@NonNull DataType cqlType) { inferJavaTypeFromCqlType(keyType), inferJavaTypeFromCqlType(valueType)); } else if (cqlType instanceof VectorType) { DataType elementType = ((VectorType) cqlType).getElementType(); - GenericType numberType = - (GenericType) inferJavaTypeFromCqlType(elementType); + GenericType numberType = inferJavaTypeFromCqlType(elementType); return GenericType.vectorOf(numberType); } switch (cqlType.getProtocolCode()) { @@ -657,7 +655,7 @@ protected TypeCodec createCodec( /* For a vector type we'll always get back an instance of TypeCodec due to the * type of CqlVector... but getElementCodecForCqlAndJavaType() is a generalized function that can't * return this more precise type. Thus the cast here. */ - TypeCodec elementCodec = + TypeCodec elementCodec = uncheckedCast(getElementCodecForCqlAndJavaType(vectorType, token, isJavaCovariant)); return TypeCodecs.vectorOf(vectorType, elementCodec); } else if (cqlType instanceof CustomType diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java index 5ee375a81e5..552f84f2ae1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/util/VIntCoding.java @@ -49,6 +49,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.nio.ByteBuffer; /** * Variable length encoding inspired from Google > 6; } + + public static void writeUnsignedVInt32(int value, ByteBuffer output) { + writeUnsignedVInt((long) value, output); + } + + public static void writeUnsignedVInt(long value, ByteBuffer output) { + int size = VIntCoding.computeUnsignedVIntSize(value); + if (size == 1) { + output.put((byte) value); + return; + } + + output.put(VIntCoding.encodeVInt(value, size), 0, size); + } + + /** + * Read up to a 32-bit integer back, using the unsigned (no zigzag) encoding. + * + *

    Note this method is the same as {@link #readUnsignedVInt(DataInput)}, except that we do + * *not* block if there are not enough bytes in the buffer to reconstruct the value. + * + * @throws VIntOutOfRangeException If the vint doesn't fit into a 32-bit integer + */ + public static int getUnsignedVInt32(ByteBuffer input, int readerIndex) { + return checkedCast(getUnsignedVInt(input, readerIndex)); + } + + public static long getUnsignedVInt(ByteBuffer input, int readerIndex) { + return getUnsignedVInt(input, readerIndex, input.limit()); + } + + public static long getUnsignedVInt(ByteBuffer input, int readerIndex, int readerLimit) { + if (readerIndex < 0) + throw new IllegalArgumentException( + "Reader index should be non-negative, but was " + readerIndex); + + if (readerIndex >= readerLimit) return -1; + + int firstByte = input.get(readerIndex++); + + // Bail out early if this is one byte, necessary or it fails later + if (firstByte >= 0) return firstByte; + + int size = numberOfExtraBytesToRead(firstByte); + if (readerIndex + size > readerLimit) return -1; + + long retval = firstByte & firstByteValueMask(size); + for (int ii = 0; ii < size; ii++) { + byte b = input.get(readerIndex++); + retval <<= 8; + retval |= b & 0xff; + } + + return retval; + } + + public static int checkedCast(long value) { + int result = (int) value; + if ((long) result != value) throw new VIntOutOfRangeException(value); + return result; + } + + /** + * Throw when attempting to decode a vint and the output type doesn't have enough space to fit the + * value that was decoded + */ + public static class VIntOutOfRangeException extends RuntimeException { + public final long value; + + private VIntOutOfRangeException(long value) { + super(value + " is out of range for a 32-bit integer"); + this.value = value; + } + } } diff --git a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java index 90f4cc6e776..3e0872cb946 100644 --- a/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/api/core/data/CqlVectorTest.java @@ -23,56 +23,60 @@ import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.internal.SerializationHelper; -import com.datastax.oss.driver.shaded.guava.common.collect.Iterators; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamException; +import java.time.LocalTime; import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.assertj.core.util.Lists; import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(DataProviderRunner.class) public class CqlVectorTest { - private static final Float[] VECTOR_ARGS = {1.0f, 2.5f}; - - private void validate_built_vector(CqlVector vec) { + @DataProvider + public static Object[][] dataProvider() { + return new Object[][] { + {new Float[] {1.0f, 2.5f}}, + {new LocalTime[] {LocalTime.of(1, 2), LocalTime.of(3, 4)}}, + {new List[] {Arrays.asList(1, 2), Arrays.asList(3, 4)}}, + {new CqlVector[] {CqlVector.newInstance("a", "bc"), CqlVector.newInstance("d", "ef")}} + }; + } + private void validate_built_vector(CqlVector vec, Object[] expectedVals) { assertThat(vec.size()).isEqualTo(2); assertThat(vec.isEmpty()).isFalse(); - assertThat(vec.get(0)).isEqualTo(VECTOR_ARGS[0]); - assertThat(vec.get(1)).isEqualTo(VECTOR_ARGS[1]); + assertThat(vec.get(0)).isEqualTo(expectedVals[0]); + assertThat(vec.get(1)).isEqualTo(expectedVals[1]); } + @UseDataProvider("dataProvider") @Test - public void should_build_vector_from_elements() { - - validate_built_vector(CqlVector.newInstance(VECTOR_ARGS)); + public void should_build_vector_from_elements(Object[] vals) { + validate_built_vector(CqlVector.newInstance(vals), vals); } @Test - public void should_build_vector_from_list() { - - validate_built_vector(CqlVector.newInstance(Lists.newArrayList(VECTOR_ARGS))); - } - - @Test - public void should_build_vector_from_tostring_output() { - - CqlVector vector1 = CqlVector.newInstance(VECTOR_ARGS); - CqlVector vector2 = CqlVector.from(vector1.toString(), TypeCodecs.FLOAT); - assertThat(vector2).isEqualTo(vector1); + @UseDataProvider("dataProvider") + public void should_build_vector_from_list(Object[] vals) { + validate_built_vector(CqlVector.newInstance(Lists.newArrayList(vals)), vals); } @Test public void should_throw_from_null_string() { - assertThatThrownBy( () -> { CqlVector.from(null, TypeCodecs.FLOAT); @@ -116,101 +120,97 @@ public void should_throw_when_building_with_nulls() { @Test public void should_build_empty_vector() { - CqlVector vector = CqlVector.newInstance(); assertThat(vector.isEmpty()).isTrue(); assertThat(vector.size()).isEqualTo(0); } @Test - public void should_behave_mostly_like_a_list() { - - CqlVector vector = CqlVector.newInstance(VECTOR_ARGS); - assertThat(vector.get(0)).isEqualTo(VECTOR_ARGS[0]); - Float newVal = VECTOR_ARGS[0] * 2; - vector.set(0, newVal); - assertThat(vector.get(0)).isEqualTo(newVal); + @UseDataProvider("dataProvider") + public void should_behave_mostly_like_a_list(T[] vals) { + T[] theArray = Arrays.copyOf(vals, vals.length); + CqlVector vector = CqlVector.newInstance(theArray); + assertThat(vector.get(0)).isEqualTo(theArray[0]); + vector.set(0, theArray[1]); + assertThat(vector.get(0)).isEqualTo(theArray[1]); assertThat(vector.isEmpty()).isFalse(); assertThat(vector.size()).isEqualTo(2); - assertThat(Iterators.toArray(vector.iterator(), Float.class)).isEqualTo(VECTOR_ARGS); + Iterator iterator = vector.iterator(); + assertThat(iterator.next()).isEqualTo(theArray[1]); + assertThat(iterator.next()).isEqualTo(theArray[1]); } @Test - public void should_play_nicely_with_streams() { - - CqlVector vector = CqlVector.newInstance(VECTOR_ARGS); - List results = + @UseDataProvider("dataProvider") + public void should_play_nicely_with_streams(T[] vals) { + CqlVector vector = CqlVector.newInstance(vals); + List results = vector.stream() - .map((f) -> f * 2) - .collect(Collectors.toCollection(() -> new ArrayList())); + .map(Object::toString) + .collect(Collectors.toCollection(() -> new ArrayList())); for (int i = 0; i < vector.size(); ++i) { - assertThat(results.get(i)).isEqualTo(vector.get(i) * 2); + assertThat(results.get(i)).isEqualTo(vector.get(i).toString()); } } @Test - public void should_reflect_changes_to_mutable_list() { - - List theList = Lists.newArrayList(1.1f, 2.2f, 3.3f); - CqlVector vector = CqlVector.newInstance(theList); - assertThat(vector.size()).isEqualTo(3); - assertThat(vector.get(2)).isEqualTo(3.3f); - - float newVal1 = 4.4f; - theList.set(2, newVal1); - assertThat(vector.size()).isEqualTo(3); - assertThat(vector.get(2)).isEqualTo(newVal1); + @UseDataProvider("dataProvider") + public void should_reflect_changes_to_mutable_list(T[] vals) { + List theList = Lists.newArrayList(vals); + CqlVector vector = CqlVector.newInstance(theList); + assertThat(vector.size()).isEqualTo(2); + assertThat(vector.get(1)).isEqualTo(vals[1]); - float newVal2 = 5.5f; - theList.add(newVal2); - assertThat(vector.size()).isEqualTo(4); - assertThat(vector.get(3)).isEqualTo(newVal2); + T newVal = vals[0]; + theList.set(1, newVal); + assertThat(vector.size()).isEqualTo(2); + assertThat(vector.get(1)).isEqualTo(newVal); } @Test - public void should_reflect_changes_to_array() { - - Float[] theArray = new Float[] {1.1f, 2.2f, 3.3f}; - CqlVector vector = CqlVector.newInstance(theArray); - assertThat(vector.size()).isEqualTo(3); - assertThat(vector.get(2)).isEqualTo(3.3f); + @UseDataProvider("dataProvider") + public void should_reflect_changes_to_array(T[] vals) { + T[] theArray = Arrays.copyOf(vals, vals.length); + CqlVector vector = CqlVector.newInstance(theArray); + assertThat(vector.size()).isEqualTo(2); + assertThat(vector.get(1)).isEqualTo(theArray[1]); - float newVal1 = 4.4f; - theArray[2] = newVal1; - assertThat(vector.size()).isEqualTo(3); - assertThat(vector.get(2)).isEqualTo(newVal1); + T newVal = theArray[0]; + theArray[1] = newVal; + assertThat(vector.size()).isEqualTo(2); + assertThat(vector.get(1)).isEqualTo(newVal); } @Test - public void should_correctly_compare_vectors() { - - Float[] args = VECTOR_ARGS.clone(); - CqlVector vector1 = CqlVector.newInstance(args); - CqlVector vector2 = CqlVector.newInstance(args); - CqlVector vector3 = CqlVector.newInstance(Lists.newArrayList(args)); + @UseDataProvider("dataProvider") + public void should_correctly_compare_vectors(T[] vals) { + CqlVector vector1 = CqlVector.newInstance(vals); + CqlVector vector2 = CqlVector.newInstance(vals); + CqlVector vector3 = CqlVector.newInstance(Lists.newArrayList(vals)); assertThat(vector1).isNotSameAs(vector2); assertThat(vector1).isEqualTo(vector2); assertThat(vector1).isNotSameAs(vector3); assertThat(vector1).isEqualTo(vector3); - Float[] differentArgs = args.clone(); - float newVal = differentArgs[0] * 2; + T[] differentArgs = Arrays.copyOf(vals, vals.length); + T newVal = differentArgs[1]; differentArgs[0] = newVal; - CqlVector vector4 = CqlVector.newInstance(differentArgs); + CqlVector vector4 = CqlVector.newInstance(differentArgs); assertThat(vector1).isNotSameAs(vector4); assertThat(vector1).isNotEqualTo(vector4); - Float[] biggerArgs = Arrays.copyOf(args, args.length + 1); + T[] biggerArgs = Arrays.copyOf(vals, vals.length + 1); biggerArgs[biggerArgs.length - 1] = newVal; - CqlVector vector5 = CqlVector.newInstance(biggerArgs); + CqlVector vector5 = CqlVector.newInstance(biggerArgs); assertThat(vector1).isNotSameAs(vector5); assertThat(vector1).isNotEqualTo(vector5); } @Test - public void should_serialize_and_deserialize() throws Exception { - CqlVector initial = CqlVector.newInstance(VECTOR_ARGS); - CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); + @UseDataProvider("dataProvider") + public void should_serialize_and_deserialize(T[] vals) throws Exception { + CqlVector initial = CqlVector.newInstance(vals); + CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); assertThat(deserialized).isEqualTo(initial); } @@ -222,21 +222,22 @@ public void should_serialize_and_deserialize_empty_vector() throws Exception { } @Test - public void should_serialize_and_deserialize_unserializable_list() throws Exception { - CqlVector initial = + @UseDataProvider("dataProvider") + public void should_serialize_and_deserialize_unserializable_list(T[] vals) throws Exception { + CqlVector initial = CqlVector.newInstance( - new AbstractList() { + new AbstractList() { @Override - public Float get(int index) { - return VECTOR_ARGS[index]; + public T get(int index) { + return vals[index]; } @Override public int size() { - return VECTOR_ARGS.length; + return vals.length; } }); - CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); + CqlVector deserialized = SerializationHelper.serializeAndDeserialize(initial); assertThat(deserialized).isEqualTo(initial); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java index 969d35cbbbe..17c78514127 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/VectorCodecTest.java @@ -20,122 +20,255 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.datastax.oss.driver.api.core.ProtocolVersion; import com.datastax.oss.driver.api.core.data.CqlVector; +import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; -import com.datastax.oss.driver.api.core.type.VectorType; +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; -import com.datastax.oss.driver.api.core.type.reflect.GenericType; +import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; import com.datastax.oss.driver.internal.core.type.DefaultVectorType; -import java.util.Arrays; +import com.datastax.oss.protocol.internal.util.Bytes; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.nio.ByteBuffer; +import java.time.LocalTime; +import java.util.HashMap; +import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; +import org.junit.runner.RunWith; -public class VectorCodecTest extends CodecTestBase> { +@RunWith(DataProviderRunner.class) +public class VectorCodecTest { - private static final Float[] VECTOR_ARGS = {1.0f, 2.5f}; - - private static final CqlVector VECTOR = CqlVector.newInstance(VECTOR_ARGS); - - private static final String VECTOR_HEX_STRING = "0x" + "3f800000" + "40200000"; - - private static final String FORMATTED_VECTOR = "[1.0, 2.5]"; - - public VectorCodecTest() { - VectorType vectorType = DataTypes.vectorOf(DataTypes.FLOAT, 2); - this.codec = TypeCodecs.vectorOf(vectorType, TypeCodecs.FLOAT); + @DataProvider + public static Object[] dataProvider() { + HashMap map1 = new HashMap<>(); + map1.put(1, "a"); + HashMap map2 = new HashMap<>(); + map2.put(2, "b"); + return new TestDataContainer[] { + new TestDataContainer( + DataTypes.FLOAT, + new Float[] {1.0f, 2.5f}, + "[1.0, 2.5]", + Bytes.fromHexString("0x3f80000040200000")), + new TestDataContainer( + DataTypes.ASCII, + new String[] {"ab", "cde"}, + "['ab', 'cde']", + Bytes.fromHexString("0x02616203636465")), + new TestDataContainer( + DataTypes.BIGINT, + new Long[] {1L, 2L}, + "[1, 2]", + Bytes.fromHexString("0x00000000000000010000000000000002")), + new TestDataContainer( + DataTypes.BLOB, + new ByteBuffer[] {Bytes.fromHexString("0xCAFE"), Bytes.fromHexString("0xABCD")}, + "[0xcafe, 0xabcd]", + Bytes.fromHexString("0x02cafe02abcd")), + new TestDataContainer( + DataTypes.BOOLEAN, + new Boolean[] {true, false}, + "[true, false]", + Bytes.fromHexString("0x0100")), + new TestDataContainer( + DataTypes.TIME, + new LocalTime[] {LocalTime.ofNanoOfDay(1), LocalTime.ofNanoOfDay(2)}, + "['00:00:00.000000001', '00:00:00.000000002']", + Bytes.fromHexString("0x080000000000000001080000000000000002")), + new TestDataContainer( + DataTypes.mapOf(DataTypes.INT, DataTypes.ASCII), + new HashMap[] {map1, map2}, + "[{1:'a'}, {2:'b'}]", + Bytes.fromHexString( + "0x110000000100000004000000010000000161110000000100000004000000020000000162")), + new TestDataContainer( + DataTypes.vectorOf(DataTypes.INT, 1), + new CqlVector[] {CqlVector.newInstance(1), CqlVector.newInstance(2)}, + "[[1], [2]]", + Bytes.fromHexString("0x0000000100000002")), + new TestDataContainer( + DataTypes.vectorOf(DataTypes.TEXT, 1), + new CqlVector[] {CqlVector.newInstance("ab"), CqlVector.newInstance("cdef")}, + "[['ab'], ['cdef']]", + Bytes.fromHexString("0x03026162050463646566")), + new TestDataContainer( + DataTypes.vectorOf(DataTypes.vectorOf(DataTypes.FLOAT, 2), 1), + new CqlVector[] { + CqlVector.newInstance(CqlVector.newInstance(1.0f, 2.5f)), + CqlVector.newInstance(CqlVector.newInstance(3.0f, 4.5f)) + }, + "[[[1.0, 2.5]], [[3.0, 4.5]]]", + Bytes.fromHexString("0x3f800000402000004040000040900000")) + }; } + @UseDataProvider("dataProvider") @Test - public void should_encode() { - assertThat(encode(VECTOR)).isEqualTo(VECTOR_HEX_STRING); - assertThat(encode(null)).isNull(); + public void should_encode(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + CqlVector vector = CqlVector.newInstance(testData.getValues()); + assertThat(codec.encode(vector, ProtocolVersion.DEFAULT)).isEqualTo(testData.getBytes()); } - /** Too few eleements will cause an exception, extra elements will be silently ignored */ @Test - public void should_throw_on_encode_with_too_few_elements() { - assertThatThrownBy(() -> encode(VECTOR.subVector(0, 1))) + @UseDataProvider("dataProvider") + public void should_throw_on_encode_with_too_few_elements(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + assertThatThrownBy( + () -> + codec.encode( + CqlVector.newInstance(testData.getValues()[0]), ProtocolVersion.DEFAULT)) .isInstanceOf(IllegalArgumentException.class); } @Test - public void should_throw_on_encode_with_empty_list() { - assertThatThrownBy(() -> encode(CqlVector.newInstance())) + @UseDataProvider("dataProvider") + public void should_throw_on_encode_with_too_many_elements(TestDataContainer testData) { + Object[] doubled = ArrayUtils.addAll(testData.getValues(), testData.getValues()); + TypeCodec> codec = getCodec(testData.getDataType()); + assertThatThrownBy(() -> codec.encode(CqlVector.newInstance(doubled), ProtocolVersion.DEFAULT)) .isInstanceOf(IllegalArgumentException.class); } @Test - public void should_encode_with_too_many_elements() { - Float[] doubledVectorContents = Arrays.copyOf(VECTOR_ARGS, VECTOR_ARGS.length * 2); - System.arraycopy(VECTOR_ARGS, 0, doubledVectorContents, VECTOR_ARGS.length, VECTOR_ARGS.length); - assertThat(encode(CqlVector.newInstance(doubledVectorContents))).isEqualTo(VECTOR_HEX_STRING); + @UseDataProvider("dataProvider") + public void should_decode(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + assertThat(codec.decode(testData.getBytes(), ProtocolVersion.DEFAULT)) + .isEqualTo(CqlVector.newInstance(testData.getValues())); } @Test - public void should_decode() { - assertThat(decode(VECTOR_HEX_STRING)).isEqualTo(VECTOR); - assertThat(decode("0x")).isNull(); - assertThat(decode(null)).isNull(); + @UseDataProvider("dataProvider") + public void should_throw_on_decode_if_too_few_bytes(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + int lastIndex = testData.getBytes().remaining() - 1; + assertThatThrownBy( + () -> + codec.decode( + (ByteBuffer) testData.getBytes().duplicate().limit(lastIndex), + ProtocolVersion.DEFAULT)) + .isInstanceOf(IllegalArgumentException.class); } @Test - public void should_throw_on_decode_if_too_few_bytes() { - // Dropping 4 bytes would knock off exactly 1 float, anything less than that would be something - // we couldn't parse a float out of - for (int i = 1; i <= 3; ++i) { - // 2 chars of hex encoded string = 1 byte - int lastIndex = VECTOR_HEX_STRING.length() - (2 * i); - assertThatThrownBy(() -> decode(VECTOR_HEX_STRING.substring(0, lastIndex))) - .isInstanceOf(IllegalArgumentException.class); - } + @UseDataProvider("dataProvider") + public void should_throw_on_decode_if_too_many_bytes(TestDataContainer testData) { + ByteBuffer doubled = ByteBuffer.allocate(testData.getBytes().remaining() * 2); + doubled.put(testData.getBytes().duplicate()).put(testData.getBytes().duplicate()).flip(); + TypeCodec> codec = getCodec(testData.getDataType()); + assertThatThrownBy(() -> codec.decode(doubled, ProtocolVersion.DEFAULT)) + .isInstanceOf(IllegalArgumentException.class); } @Test - public void should_format() { - assertThat(format(VECTOR)).isEqualTo(FORMATTED_VECTOR); - assertThat(format(null)).isEqualTo("NULL"); + @UseDataProvider("dataProvider") + public void should_format(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + CqlVector vector = CqlVector.newInstance(testData.getValues()); + assertThat(codec.format(vector)).isEqualTo(testData.getFormatted()); } @Test - public void should_parse() { - assertThat(parse(FORMATTED_VECTOR)).isEqualTo(VECTOR); - assertThat(parse("NULL")).isNull(); - assertThat(parse("null")).isNull(); - assertThat(parse("")).isNull(); - assertThat(parse(null)).isNull(); + @UseDataProvider("dataProvider") + public void should_parse(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + assertThat(codec.parse(testData.getFormatted())) + .isEqualTo(CqlVector.newInstance(testData.getValues())); } @Test - public void should_accept_data_type() { - assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 2))).isTrue(); - assertThat(codec.accepts(DataTypes.INT)).isFalse(); + @UseDataProvider("dataProvider") + public void should_accept_data_type(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + assertThat(codec.accepts(new DefaultVectorType(testData.getDataType(), 2))).isTrue(); + assertThat(codec.accepts(new DefaultVectorType(DataTypes.custom("non-existent"), 2))).isFalse(); } @Test - public void should_accept_vector_type_correct_dimension_only() { - assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 0))).isFalse(); - assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 1))).isFalse(); - assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, 2))).isTrue(); - for (int i = 3; i < 1000; ++i) { - assertThat(codec.accepts(new DefaultVectorType(DataTypes.FLOAT, i))).isFalse(); - } + @UseDataProvider("dataProvider") + public void should_accept_vector_type_correct_dimension_only(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + assertThat(codec.accepts(new DefaultVectorType(testData.getDataType(), 0))).isFalse(); + assertThat(codec.accepts(new DefaultVectorType(testData.getDataType(), 1))).isFalse(); + assertThat(codec.accepts(new DefaultVectorType(testData.getDataType(), 3))).isFalse(); } @Test - public void should_accept_generic_type() { - assertThat(codec.accepts(GenericType.vectorOf(GenericType.FLOAT))).isTrue(); - assertThat(codec.accepts(GenericType.vectorOf(GenericType.INTEGER))).isFalse(); - assertThat(codec.accepts(GenericType.of(Integer.class))).isFalse(); + @UseDataProvider("dataProvider") + public void should_accept_generic_type(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + assertThat(codec.accepts(codec.getJavaType())).isTrue(); } @Test - public void should_accept_raw_type() { + @UseDataProvider("dataProvider") + public void should_accept_raw_type(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); assertThat(codec.accepts(CqlVector.class)).isTrue(); assertThat(codec.accepts(Integer.class)).isFalse(); } @Test - public void should_accept_object() { - assertThat(codec.accepts(VECTOR)).isTrue(); + @UseDataProvider("dataProvider") + public void should_accept_object(TestDataContainer testData) { + TypeCodec> codec = getCodec(testData.getDataType()); + CqlVector vector = CqlVector.newInstance(testData.getValues()); + assertThat(codec.accepts(vector)).isTrue(); assertThat(codec.accepts(Integer.MIN_VALUE)).isFalse(); } + + @Test + public void should_handle_null_and_empty() { + TypeCodec> codec = getCodec(DataTypes.FLOAT); + assertThat(codec.encode(null, ProtocolVersion.DEFAULT)).isNull(); + assertThat(codec.decode(Bytes.fromHexString("0x"), ProtocolVersion.DEFAULT)).isNull(); + assertThat(codec.format(null)).isEqualTo("NULL"); + assertThat(codec.parse("NULL")).isNull(); + assertThat(codec.parse("null")).isNull(); + assertThat(codec.parse("")).isNull(); + assertThat(codec.parse(null)).isNull(); + assertThatThrownBy(() -> codec.encode(CqlVector.newInstance(), ProtocolVersion.DEFAULT)) + .isInstanceOf(IllegalArgumentException.class); + } + + private static TypeCodec> getCodec(DataType dataType) { + return TypeCodecs.vectorOf( + DataTypes.vectorOf(dataType, 2), CodecRegistry.DEFAULT.codecFor(dataType)); + } + + private static class TestDataContainer { + private final DataType dataType; + private final Object[] values; + private final String formatted; + private final ByteBuffer bytes; + + public TestDataContainer( + DataType dataType, Object[] values, String formatted, ByteBuffer bytes) { + this.dataType = dataType; + this.values = values; + this.formatted = formatted; + this.bytes = bytes; + } + + public DataType getDataType() { + return dataType; + } + + public Object[] getValues() { + return values; + } + + public String getFormatted() { + return formatted; + } + + public ByteBuffer getBytes() { + return bytes; + } + } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java index 1f3f6bbff97..4c0298bafad 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/codec/registry/CachingCodecRegistryTestDataProviders.java @@ -337,6 +337,26 @@ public static Object[][] collectionsWithCqlAndJavaTypes() GenericType.vectorOf(BigInteger.class), CqlVector.newInstance(BigInteger.ONE) }, + // vector with arbitrary types + { + DataTypes.vectorOf(DataTypes.TEXT, 2), + GenericType.vectorOf(String.class), + GenericType.vectorOf(String.class), + CqlVector.newInstance("abc", "de") + }, + { + DataTypes.vectorOf(DataTypes.TIME, 2), + GenericType.vectorOf(LocalTime.class), + GenericType.vectorOf(LocalTime.class), + CqlVector.newInstance(LocalTime.MIDNIGHT, LocalTime.NOON) + }, + { + DataTypes.vectorOf(DataTypes.vectorOf(DataTypes.TINYINT, 2), 2), + GenericType.vectorOf(GenericType.vectorOf(Byte.class)), + GenericType.vectorOf(GenericType.vectorOf(Byte.class)), + CqlVector.newInstance( + CqlVector.newInstance((byte) 1, (byte) 2), CqlVector.newInstance((byte) 3, (byte) 4)) + }, }; } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/type/util/VIntCodingTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/type/util/VIntCodingTest.java new file mode 100644 index 00000000000..b85d6d66844 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/type/util/VIntCodingTest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.type.util; + +import static org.junit.Assert.assertEquals; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.nio.ByteBuffer; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DataProviderRunner.class) +public class VIntCodingTest { + @DataProvider + public static Object[] roundTripTestValues() { + return new Integer[] { + Integer.MAX_VALUE + 1, + Integer.MAX_VALUE, + Integer.MAX_VALUE - 1, + Integer.MIN_VALUE, + Integer.MIN_VALUE + 1, + Integer.MIN_VALUE - 1, + 0, + -1, + 1 + }; + }; + + private static final long[] LONGS = + new long[] { + 53L, + 10201L, + 1097151L, + 168435455L, + 33251130335L, + 3281283447775L, + 417672546086779L, + 52057592037927932L, + 72057594037927937L + }; + + @Test + public void should_compute_unsigned_vint_size() { + for (int i = 0; i < LONGS.length; i++) { + long val = LONGS[i]; + assertEquals(i + 1, VIntCoding.computeUnsignedVIntSize(val)); + } + } + + @Test + @UseDataProvider("roundTripTestValues") + public void should_write_and_read_unsigned_vint_32(int value) { + ByteBuffer bb = ByteBuffer.allocate(9); + + VIntCoding.writeUnsignedVInt32(value, bb); + bb.flip(); + assertEquals(value, VIntCoding.getUnsignedVInt32(bb, 0)); + } + + @Test + @UseDataProvider("roundTripTestValues") + public void should_write_and_read_unsigned_vint(int value) { + ByteBuffer bb = ByteBuffer.allocate(9); + + VIntCoding.writeUnsignedVInt(value, bb); + bb.flip(); + assertEquals(value, VIntCoding.getUnsignedVInt(bb, 0)); + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/data/DataTypeIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/data/DataTypeIT.java index a33c8704876..e3d891454de 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/data/DataTypeIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/data/DataTypeIT.java @@ -32,6 +32,7 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.data.CqlDuration; +import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.data.SettableByIndex; import com.datastax.oss.driver.api.core.data.SettableByName; import com.datastax.oss.driver.api.core.data.TupleValue; @@ -183,6 +184,7 @@ public static Object[][] typeSamples() { // 5) include map // 6) include tuple // 7) include udt + // 8) include vector return Arrays.stream(primitiveSamples) .flatMap( o -> { @@ -263,6 +265,30 @@ public static Object[][] typeSamples() { UdtValue udtValue2 = udt.newValue(1, o[1]); samples.add(new Object[] {udt, udtValue2}); + if (CCM_RULE.getCassandraVersion().compareTo(Version.parse("5.0")) >= 0) { + // vector of type + CqlVector vector = CqlVector.newInstance(o[1]); + samples.add(new Object[] {DataTypes.vectorOf(dataType, 1), vector}); + } + + return samples.stream(); + }) + .toArray(Object[][]::new); + } + + @DataProvider + public static Object[][] addVectors() { + Object[][] previousSamples = typeSamples(); + if (CCM_RULE.getCassandraVersion().compareTo(Version.parse("5.0")) < 0) return previousSamples; + return Arrays.stream(previousSamples) + .flatMap( + o -> { + List samples = new ArrayList<>(); + samples.add(o); + if (o[1] == null) return samples.stream(); + DataType dataType = (DataType) o[0]; + CqlVector vector = CqlVector.newInstance(o[1]); + samples.add(new Object[] {DataTypes.vectorOf(dataType, 1), vector}); return samples.stream(); }) .toArray(Object[][]::new); @@ -278,7 +304,7 @@ public static void createTable() { List columnData = new ArrayList<>(); - for (Object[] sample : typeSamples()) { + for (Object[] sample : addVectors()) { DataType dataType = (DataType) sample[0]; if (!typeToColumnName.containsKey(dataType)) { @@ -308,7 +334,7 @@ private static int nextKey() { return keyCounter.incrementAndGet(); } - @UseDataProvider("typeSamples") + @UseDataProvider("addVectors") @Test public void should_insert_non_primary_key_column_simple_statement_using_format( DataType dataType, K value, K expectedPrimitiveValue) { @@ -335,7 +361,7 @@ public void should_insert_non_primary_key_column_simple_statement_using_form readValue(select, dataType, value, expectedPrimitiveValue); } - @UseDataProvider("typeSamples") + @UseDataProvider("addVectors") @Test public void should_insert_non_primary_key_column_simple_statement_positional_value( DataType dataType, K value, K expectedPrimitiveValue) { @@ -358,7 +384,7 @@ public void should_insert_non_primary_key_column_simple_statement_positional readValue(select, dataType, value, expectedPrimitiveValue); } - @UseDataProvider("typeSamples") + @UseDataProvider("addVectors") @Test public void should_insert_non_primary_key_column_simple_statement_named_value( DataType dataType, K value, K expectedPrimitiveValue) { @@ -382,7 +408,7 @@ public void should_insert_non_primary_key_column_simple_statement_named_valu readValue(select, dataType, value, expectedPrimitiveValue); } - @UseDataProvider("typeSamples") + @UseDataProvider("addVectors") @Test public void should_insert_non_primary_key_column_bound_statement_positional_value( DataType dataType, K value, K expectedPrimitiveValue) { @@ -411,7 +437,7 @@ public void should_insert_non_primary_key_column_bound_statement_positional_ readValue(boundSelect, dataType, value, expectedPrimitiveValue); } - @UseDataProvider("typeSamples") + @UseDataProvider("addVectors") @Test public void should_insert_non_primary_key_column_bound_statement_named_value( DataType dataType, K value, K expectedPrimitiveValue) { From 04d34a8989b89c1addaab7f248b1fa9aa535da5e Mon Sep 17 00:00:00 2001 From: Alex Sasnouskikh Date: Thu, 30 Jan 2025 22:36:29 +0000 Subject: [PATCH 354/395] JAVA-3168 Copy node info for contact points on initial node refresh only from first match by endpoint patch by Alex Sasnouskikh; reviewed by Andy Tolbert and Alexandre Dura for JAVA-3168 --- .../core/metadata/InitialNodeListRefresh.java | 36 +++++++++++-------- .../metadata/InitialNodeListRefreshTest.java | 34 ++++++++++++++++-- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefresh.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefresh.java index c21d5d8171e..517bfca27fa 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefresh.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefresh.java @@ -18,14 +18,16 @@ package com.datastax.oss.driver.internal.core.metadata; import com.datastax.oss.driver.api.core.metadata.EndPoint; -import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metadata.token.TokenFactory; import com.datastax.oss.driver.internal.core.metadata.token.TokenFactoryRegistry; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -63,22 +65,31 @@ public Result compute( TokenFactory tokenFactory = null; Map newNodes = new HashMap<>(); + // Contact point nodes don't have host ID as well as other info yet, so we fill them with node + // info found on first match by endpoint + Set matchedContactPoints = new HashSet<>(); + List addedNodes = new ArrayList<>(); for (NodeInfo nodeInfo : nodeInfos) { UUID hostId = nodeInfo.getHostId(); if (newNodes.containsKey(hostId)) { LOG.warn( "[{}] Found duplicate entries with host_id {} in system.peers, " - + "keeping only the first one", + + "keeping only the first one {}", logPrefix, - hostId); + hostId, + newNodes.get(hostId)); } else { EndPoint endPoint = nodeInfo.getEndPoint(); - DefaultNode node = findIn(contactPoints, endPoint); - if (node == null) { + DefaultNode contactPointNode = findContactPointNode(endPoint); + DefaultNode node; + if (contactPointNode == null || matchedContactPoints.contains(endPoint)) { node = new DefaultNode(endPoint, context); + addedNodes.add(node); LOG.debug("[{}] Adding new node {}", logPrefix, node); } else { + matchedContactPoints.add(contactPointNode.getEndPoint()); + node = contactPointNode; LOG.debug("[{}] Copying contact point {}", logPrefix, node); } if (tokenMapEnabled && tokenFactory == null && nodeInfo.getPartitioner() != null) { @@ -90,14 +101,11 @@ public Result compute( } ImmutableList.Builder eventsBuilder = ImmutableList.builder(); - - for (DefaultNode newNode : newNodes.values()) { - if (findIn(contactPoints, newNode.getEndPoint()) == null) { - eventsBuilder.add(NodeStateEvent.added(newNode)); - } + for (DefaultNode addedNode : addedNodes) { + eventsBuilder.add(NodeStateEvent.added(addedNode)); } for (DefaultNode contactPoint : contactPoints) { - if (findIn(newNodes.values(), contactPoint.getEndPoint()) == null) { + if (!matchedContactPoints.contains(contactPoint.getEndPoint())) { eventsBuilder.add(NodeStateEvent.removed(contactPoint)); } } @@ -108,10 +116,10 @@ public Result compute( eventsBuilder.build()); } - private DefaultNode findIn(Iterable nodes, EndPoint endPoint) { - for (Node node : nodes) { + private DefaultNode findContactPointNode(EndPoint endPoint) { + for (DefaultNode node : contactPoints) { if (node.getEndPoint().equals(endPoint)) { - return (DefaultNode) node; + return node; } } return null; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefreshTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefreshTest.java index 095662257f6..3787bf8fe10 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefreshTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/metadata/InitialNodeListRefreshTest.java @@ -48,6 +48,8 @@ public class InitialNodeListRefreshTest { private UUID hostId1; private UUID hostId2; private UUID hostId3; + private UUID hostId4; + private UUID hostId5; @Before public void setup() { @@ -61,10 +63,12 @@ public void setup() { hostId1 = UUID.randomUUID(); hostId2 = UUID.randomUUID(); hostId3 = UUID.randomUUID(); + hostId4 = UUID.randomUUID(); + hostId5 = UUID.randomUUID(); } @Test - public void should_copy_contact_points() { + public void should_copy_contact_points_on_first_endpoint_match_only() { // Given Iterable newInfos = ImmutableList.of( @@ -76,6 +80,17 @@ public void should_copy_contact_points() { DefaultNodeInfo.builder() .withEndPoint(contactPoint2.getEndPoint()) .withHostId(hostId2) + .build(), + DefaultNodeInfo.builder().withEndPoint(endPoint3).withHostId(hostId3).build(), + DefaultNodeInfo.builder() + // address translator can translate node addresses to the same endpoints + .withEndPoint(contactPoint2.getEndPoint()) + .withHostId(hostId4) + .build(), + DefaultNodeInfo.builder() + // address translator can translate node addresses to the same endpoints + .withEndPoint(endPoint3) + .withHostId(hostId5) .build()); InitialNodeListRefresh refresh = new InitialNodeListRefresh(newInfos, ImmutableSet.of(contactPoint1, contactPoint2)); @@ -86,11 +101,26 @@ public void should_copy_contact_points() { // Then // contact points have been copied to the metadata, and completed with missing information Map newNodes = result.newMetadata.getNodes(); - assertThat(newNodes).containsOnlyKeys(hostId1, hostId2); + assertThat(newNodes).containsOnlyKeys(hostId1, hostId2, hostId3, hostId4, hostId5); assertThat(newNodes.get(hostId1)).isEqualTo(contactPoint1); assertThat(contactPoint1.getHostId()).isEqualTo(hostId1); assertThat(newNodes.get(hostId2)).isEqualTo(contactPoint2); assertThat(contactPoint2.getHostId()).isEqualTo(hostId2); + // And + // node has been added for the new endpoint + assertThat(newNodes.get(hostId3).getEndPoint()).isEqualTo(endPoint3); + assertThat(newNodes.get(hostId3).getHostId()).isEqualTo(hostId3); + // And + // nodes have been added for duplicated endpoints + assertThat(newNodes.get(hostId4).getEndPoint()).isEqualTo(contactPoint2.getEndPoint()); + assertThat(newNodes.get(hostId4).getHostId()).isEqualTo(hostId4); + assertThat(newNodes.get(hostId5).getEndPoint()).isEqualTo(endPoint3); + assertThat(newNodes.get(hostId5).getHostId()).isEqualTo(hostId5); + assertThat(result.events) + .containsExactlyInAnyOrder( + NodeStateEvent.added((DefaultNode) newNodes.get(hostId3)), + NodeStateEvent.added((DefaultNode) newNodes.get(hostId4)), + NodeStateEvent.added((DefaultNode) newNodes.get(hostId5))); } @Test From eac7b24d60d87e912ea70ba3ddee2755a6fa28cf Mon Sep 17 00:00:00 2001 From: Luc Boutier Date: Fri, 3 Nov 2023 10:13:13 +0100 Subject: [PATCH 355/395] JAVA-3055: Prevent PreparedStatement cache to be polluted if a request is cancelled. There was a critical issue when the external code cancels a request, indeed the cached CompletableFuture will then always throw a CancellationException. This may happens, for example, when used by reactive like Mono.zip or Mono.firstWithValue. patch by Luc Boutier; reviewed by Alexandre Dutra and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1757 --- .../driver/internal/core/cql/CqlPrepareAsyncProcessor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java index ffbc8ee046a..d777e35e50f 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java @@ -159,7 +159,9 @@ public CompletionStage process( }); } } - return result; + // Return a defensive copy. So if a client cancels its request, the cache won't be impacted + // nor a potential concurrent request. + return result.thenApply(x -> x); // copy() is available only since Java 9 } catch (ExecutionException e) { return CompletableFutures.failedFuture(e.getCause()); } From 64b3568dfa6dd58e8c16d28cafbe8dbf16f1e622 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 3 Feb 2025 17:56:54 -0600 Subject: [PATCH 356/395] Expose a decorator for CqlPrepareAsyncProcessor cache rather than the ability to specify an arbitrary cache from scratch. Also bringing tests from https://github.com/apache/cassandra-java-driver/pull/2003 forward with a few minor changes due to this implementation patch by Bret McGuire; reviewed by Bret McGuire and Andy Tolbert reference: #2008 --- .../core/cql/CqlPrepareAsyncProcessor.java | 11 +- .../core/cql/PreparedStatementCachingIT.java | 13 +- .../cql/PreparedStatementCancellationIT.java | 166 ++++++++++++++++++ 3 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCancellationIT.java diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java index d777e35e50f..918d75e9ecb 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java @@ -38,6 +38,7 @@ import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; import com.datastax.oss.protocol.internal.ProtocolConstants; +import com.google.common.base.Functions; import edu.umd.cs.findbugs.annotations.NonNull; import io.netty.util.concurrent.EventExecutor; import java.util.Map; @@ -45,6 +46,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutionException; +import java.util.function.Function; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,14 +64,15 @@ public CqlPrepareAsyncProcessor() { } public CqlPrepareAsyncProcessor(@NonNull Optional context) { - this(CacheBuilder.newBuilder().weakValues().build(), context); + this(context, Functions.identity()); } protected CqlPrepareAsyncProcessor( - Cache> cache, - Optional context) { + Optional context, + Function, CacheBuilder> decorator) { - this.cache = cache; + CacheBuilder baseCache = CacheBuilder.newBuilder().weakValues(); + this.cache = decorator.apply(baseCache).build(); context.ifPresent( (ctx) -> { LOG.info("Adding handler to invalidate cached prepared statements on type changes"); diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java index 05ac3bd0e92..617d489fb95 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCachingIT.java @@ -24,7 +24,6 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.cql.PrepareRequest; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.metrics.DefaultSessionMetric; import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; @@ -41,7 +40,6 @@ import com.datastax.oss.driver.internal.core.session.BuiltInRequestProcessors; import com.datastax.oss.driver.internal.core.session.RequestProcessor; import com.datastax.oss.driver.internal.core.session.RequestProcessorRegistry; -import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; import com.datastax.oss.driver.shaded.guava.common.cache.RemovalListener; import com.datastax.oss.driver.shaded.guava.common.util.concurrent.Uninterruptibles; import com.google.common.collect.ImmutableList; @@ -119,11 +117,12 @@ private static class TestCqlPrepareAsyncProcessor extends CqlPrepareAsyncProcess private static final Logger LOG = LoggerFactory.getLogger(PreparedStatementCachingIT.TestCqlPrepareAsyncProcessor.class); - private static RemovalListener> - buildCacheRemoveCallback(@NonNull Optional context) { + private static RemovalListener buildCacheRemoveCallback( + @NonNull Optional context) { return (evt) -> { try { - CompletableFuture future = evt.getValue(); + CompletableFuture future = + (CompletableFuture) evt.getValue(); ByteBuffer queryId = Uninterruptibles.getUninterruptibly(future).getId(); context.ifPresent( ctx -> ctx.getEventBus().fire(new PreparedStatementRemovalEvent(queryId))); @@ -136,9 +135,7 @@ private static class TestCqlPrepareAsyncProcessor extends CqlPrepareAsyncProcess public TestCqlPrepareAsyncProcessor(@NonNull Optional context) { // Default CqlPrepareAsyncProcessor uses weak values here as well. We avoid doing so // to prevent cache entries from unexpectedly disappearing mid-test. - super( - CacheBuilder.newBuilder().removalListener(buildCacheRemoveCallback(context)).build(), - context); + super(context, builder -> builder.removalListener(buildCacheRemoveCallback(context))); } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCancellationIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCancellationIT.java new file mode 100644 index 00000000000..d7e581e4606 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementCancellationIT.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.cql; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PrepareRequest; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.categories.IsolatedTests; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor; +import com.datastax.oss.driver.shaded.guava.common.base.Predicates; +import com.datastax.oss.driver.shaded.guava.common.cache.Cache; +import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; +import java.util.concurrent.CompletableFuture; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; + +@Category(IsolatedTests.class) +public class PreparedStatementCancellationIT { + + private CustomCcmRule ccmRule = CustomCcmRule.builder().build(); + + private SessionRule sessionRule = SessionRule.builder(ccmRule).build(); + + @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); + + @Before + public void setup() { + + CqlSession session = SessionUtils.newSession(ccmRule, sessionRule.keyspace()); + session.execute("DROP TABLE IF EXISTS test_table_1"); + session.execute("CREATE TABLE test_table_1 (k int primary key, v int)"); + session.execute("INSERT INTO test_table_1 (k,v) VALUES (1, 100)"); + session.execute("INSERT INTO test_table_1 (k,v) VALUES (2, 200)"); + session.execute("INSERT INTO test_table_1 (k,v) VALUES (3, 300)"); + session.close(); + } + + @After + public void teardown() { + + CqlSession session = SessionUtils.newSession(ccmRule, sessionRule.keyspace()); + session.execute("DROP TABLE test_table_1"); + session.close(); + } + + private CompletableFuture toCompletableFuture(CqlSession session, String cql) { + + return session.prepareAsync(cql).toCompletableFuture(); + } + + private CqlPrepareAsyncProcessor findProcessor(CqlSession session) { + + DefaultDriverContext context = (DefaultDriverContext) session.getContext(); + return (CqlPrepareAsyncProcessor) + Iterables.find( + context.getRequestProcessorRegistry().getProcessors(), + Predicates.instanceOf(CqlPrepareAsyncProcessor.class)); + } + + @Test + public void should_cache_valid_cql() throws Exception { + + CqlSession session = SessionUtils.newSession(ccmRule, sessionRule.keyspace()); + CqlPrepareAsyncProcessor processor = findProcessor(session); + Cache> cache = processor.getCache(); + assertThat(cache.size()).isEqualTo(0); + + // Make multiple CompletableFuture requests for the specified CQL, then wait until + // the cached request finishes and confirm that all futures got the same values + String cql = "select v from test_table_1 where k = ?"; + CompletableFuture cf1 = toCompletableFuture(session, cql); + CompletableFuture cf2 = toCompletableFuture(session, cql); + assertThat(cache.size()).isEqualTo(1); + + CompletableFuture future = Iterables.get(cache.asMap().values(), 0); + PreparedStatement stmt = future.get(); + + assertThat(cf1.isDone()).isTrue(); + assertThat(cf2.isDone()).isTrue(); + + assertThat(cf1.join()).isEqualTo(stmt); + assertThat(cf2.join()).isEqualTo(stmt); + } + + // A holdover from work done on JAVA-3055. This probably isn't _desired_ behaviour but this test + // documents the fact that the current driver impl will behave in this way. We should probably + // consider changing this in a future release, although it's worthwhile fully considering the + // implications of such a change. + @Test + public void will_cache_invalid_cql() throws Exception { + + CqlSession session = SessionUtils.newSession(ccmRule, sessionRule.keyspace()); + CqlPrepareAsyncProcessor processor = findProcessor(session); + Cache> cache = processor.getCache(); + assertThat(cache.size()).isEqualTo(0); + + // Verify that we get the CompletableFuture even if the CQL is invalid but that nothing is + // cached + String cql = "select v fromfrom test_table_1 where k = ?"; + CompletableFuture cf = toCompletableFuture(session, cql); + + // join() here should throw exceptions due to the invalid syntax... for purposes of this test we + // can ignore this + try { + cf.join(); + fail(); + } catch (Exception e) { + } + + assertThat(cache.size()).isEqualTo(1); + } + + @Test + public void should_not_affect_cache_if_returned_futures_are_cancelled() throws Exception { + + CqlSession session = SessionUtils.newSession(ccmRule, sessionRule.keyspace()); + CqlPrepareAsyncProcessor processor = findProcessor(session); + Cache> cache = processor.getCache(); + assertThat(cache.size()).isEqualTo(0); + + String cql = "select v from test_table_1 where k = ?"; + CompletableFuture cf = toCompletableFuture(session, cql); + + assertThat(cf.isCancelled()).isFalse(); + assertThat(cf.cancel(false)).isTrue(); + assertThat(cf.isCancelled()).isTrue(); + assertThat(cf.isCompletedExceptionally()).isTrue(); + + // Confirm that cancelling the CompletableFuture returned to the user does _not_ cancel the + // future used within the cache. CacheEntry very deliberately doesn't maintain a reference + // to it's contained CompletableFuture so we have to get at this by secondary effects. + assertThat(cache.size()).isEqualTo(1); + CompletableFuture future = Iterables.get(cache.asMap().values(), 0); + PreparedStatement rv = future.get(); + assertThat(rv).isNotNull(); + assertThat(rv.getQuery()).isEqualTo(cql); + assertThat(cache.size()).isEqualTo(1); + } +} From 94e73d9f4e95cd74b319495663862ad50c63f589 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Wed, 5 Feb 2025 15:33:46 -0600 Subject: [PATCH 357/395] ninja-fix Using shaded Guava classes for import in order to make OSGi class paths happy. Major hat tip to Dmitry Konstantinov for the find here! --- .../oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java index 918d75e9ecb..a3d11cff054 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlPrepareAsyncProcessor.java @@ -34,11 +34,11 @@ import com.datastax.oss.driver.internal.core.session.RequestProcessor; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; import com.datastax.oss.driver.internal.core.util.concurrent.RunOrSchedule; +import com.datastax.oss.driver.shaded.guava.common.base.Functions; import com.datastax.oss.driver.shaded.guava.common.cache.Cache; import com.datastax.oss.driver.shaded.guava.common.cache.CacheBuilder; import com.datastax.oss.driver.shaded.guava.common.collect.Iterables; import com.datastax.oss.protocol.internal.ProtocolConstants; -import com.google.common.base.Functions; import edu.umd.cs.findbugs.annotations.NonNull; import io.netty.util.concurrent.EventExecutor; import java.util.Map; From 610b91b160948c96c2d61aa34021db3cdac73aa2 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Tue, 4 Feb 2025 15:22:14 -0600 Subject: [PATCH 358/395] Changelog updates for 4.19.0 --- changelog/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 83ebb44239f..08634bcb834 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -21,6 +21,30 @@ under the License. +### 4.19.0 + +- [bug] JAVA-3055: Prevent PreparedStatement cache to be polluted if a request is cancelled. +- [bug] JAVA-3168: Copy node info for contact points on initial node refresh only from first match by endpoint +- [improvement] JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0) +- [improvement] CASSJAVA-53: Update Guava version used in cassandra-java-driver +- [improvement] JAVA-3118: Add support for vector data type in Schema Builder, QueryBuilder +- [bug] CASSJAVA-55: Remove setting "Host" header for metadata requests +- [bug] JAVA-3057: Allow decoding a UDT that has more fields than expected +- [improvement] CASSJAVA-52: Bring java-driver-shaded-guava into the repo as a submodule +- [bug] CASSJAVA-2: TableMetadata#describe produces invalid CQL when a type of a column is a vector +- [bug] JAVA-3051: Memory leak in DefaultLoadBalancingPolicy measurement of response times +- [improvement] CASSJAVA-14: Query builder support for NOT CQL syntax +- [bug] CASSJAVA-12: DefaultSslEngineFactory missing null check on close +- [improvement] CASSJAVA-46: Expose table extensions via schema builders +- [bug] PR 1938: Fix uncaught exception during graceful channel shutdown after exceeding max orphan ids +- [improvement] PR 1607: Annotate BatchStatement, Statement, SimpleStatement methods with CheckReturnValue +- [improvement] CASSJAVA-41: Reduce lock held duration in ConcurrencyLimitingRequestThrottler +- [bug] JAVA-3149: Async Query Cancellation Not Propagated To RequestThrottler +- [bug] JAVA-3167: CompletableFutures.allSuccessful() may return never completed future +- [bug] PR 1620: Don't return empty routing key when partition key is unbound +- [improvement] PR 1623: Limit calls to Conversions.resolveExecutionProfile +- [improvement] CASSJAVA-29: Update target Cassandra versions for integration tests, support new 5.0.x + ### 4.18.1 - [improvement] JAVA-3142: Ability to specify ordering of remote local dc's via new configuration for graceful automatic failovers From 46444eaabdbd23e9231123198536d070e99aca27 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 6 Feb 2025 15:51:51 -0600 Subject: [PATCH 359/395] [maven-release-plugin] prepare release 4.19.0 --- bom/pom.xml | 20 ++++++++++---------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- guava-shaded/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 08f212f6157..bb39a484f71 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-bom pom @@ -33,47 +33,47 @@ org.apache.cassandra java-driver-core - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-core-shaded - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-mapper-processor - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-mapper-runtime - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-query-builder - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-guava-shaded - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-test-infra - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-metrics-micrometer - 4.18.2-SNAPSHOT + 4.19.0 org.apache.cassandra java-driver-metrics-microprofile - 4.18.2-SNAPSHOT + 4.19.0 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 9a708beb2a7..82f45050098 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 2a48e8bf9ce..ea0efdddc08 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index ee5b52958c3..d3275565827 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index fafd8c4678b..0bb2ccef386 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index dfc406baf43..4edc44d2131 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index a76cc8d2bf1..ee90d5c2c65 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.18.2-SNAPSHOT + 4.19.0 java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index ca8f0161b04..a0627c376ff 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-guava-shaded Apache Cassandra Java Driver - guava shaded dep diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index d1b0a736bb0..1052f96ae35 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 6588f17d5f7..0b201db2473 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 28483ee93ff..f846fc68dec 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 8ab939cbb37..80ec51605ab 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 521a67f9075..955160dd621 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index f0e66b656ca..7b761aa12a0 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index c61e6485fd3..ecb800b7ebb 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1029,7 +1029,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.19.0 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 4e09a10e584..144906adecb 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 262627e5536..0252683ca2b 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.18.2-SNAPSHOT + 4.19.0 java-driver-test-infra bundle From 90612f6758eb0f0ba964daf054f397a47a90a736 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 6 Feb 2025 15:51:54 -0600 Subject: [PATCH 360/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 20 ++++++++++---------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- guava-shaded/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index bb39a484f71..8e7bc467fe7 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-bom pom @@ -33,47 +33,47 @@ org.apache.cassandra java-driver-core - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-core-shaded - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-mapper-processor - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-mapper-runtime - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-query-builder - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-guava-shaded - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-test-infra - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-metrics-micrometer - 4.19.0 + 4.19.1-SNAPSHOT org.apache.cassandra java-driver-metrics-microprofile - 4.19.0 + 4.19.1-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 82f45050098..451db1dcd1b 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index ea0efdddc08..b8d7d5c2d3b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index d3275565827..e930f4c0610 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index 0bb2ccef386..1c762074673 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 4edc44d2131..8f7740e148f 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index ee90d5c2c65..15f082e6864 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.19.0 + 4.19.1-SNAPSHOT java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index a0627c376ff..8053af94911 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-guava-shaded Apache Cassandra Java Driver - guava shaded dep diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 1052f96ae35..b489076c257 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 0b201db2473..519f1411ce9 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index f846fc68dec..3a767c2a352 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 80ec51605ab..091bb5f3e93 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 955160dd621..5163b5366f4 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 7b761aa12a0..4b41f790145 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index ecb800b7ebb..3fd2d1347c2 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1029,7 +1029,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.19.0 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 144906adecb..0bc46f9bb91 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 0252683ca2b..b0808757ce4 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.0 + 4.19.1-SNAPSHOT java-driver-test-infra bundle From 3bb5b18903636976279506308c60f1911b7b8ed5 Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Thu, 13 Feb 2025 17:11:36 -0500 Subject: [PATCH 361/395] CASSJAVA-80: Support configuration to disable DNS reverse-lookups for SAN validation patch by Abe Ratnofsky; reviewed by Alexandre Dutra, Andy Tolbert, and Francisco Guerrero for CASSJAVA-80 --- .../api/core/config/DefaultDriverOption.java | 6 ++ .../api/core/config/TypedDriverOption.java | 4 ++ .../ssl/ProgrammaticSslEngineFactory.java | 27 +++++++- .../core/ssl/DefaultSslEngineFactory.java | 26 +++++++- .../core/ssl/SniSslEngineFactory.java | 10 ++- core/src/main/resources/reference.conf | 6 ++ .../core/ssl/DefaultSslEngineFactoryIT.java | 66 +++++++++++++++++++ 7 files changed, 141 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 11f2702c3cf..acd4bb9cc1d 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -243,6 +243,12 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: boolean */ SSL_HOSTNAME_VALIDATION("advanced.ssl-engine-factory.hostname-validation"), + /** + * Whether or not to do a DNS reverse-lookup of provided server addresses for SAN addresses. + * + *

    Value-type: boolean + */ + SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN("advanced.ssl-engine-factory.allow-dns-reverse-lookup-san"), /** * The location of the keystore file. * diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index ca60b67f0ba..93e2b468461 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -229,6 +229,10 @@ public String toString() { */ public static final TypedDriverOption SSL_HOSTNAME_VALIDATION = new TypedDriverOption<>(DefaultDriverOption.SSL_HOSTNAME_VALIDATION, GenericType.BOOLEAN); + + public static final TypedDriverOption SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN = + new TypedDriverOption<>( + DefaultDriverOption.SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN, GenericType.BOOLEAN); /** The location of the keystore file. */ public static final TypedDriverOption SSL_KEYSTORE_PATH = new TypedDriverOption<>(DefaultDriverOption.SSL_KEYSTORE_PATH, GenericType.STRING); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.java index 6dfe4087b91..d65eaa864aa 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/ssl/ProgrammaticSslEngineFactory.java @@ -45,6 +45,7 @@ public class ProgrammaticSslEngineFactory implements SslEngineFactory { protected final SSLContext sslContext; protected final String[] cipherSuites; protected final boolean requireHostnameValidation; + protected final boolean allowDnsReverseLookupSan; /** * Creates an instance with the given {@link SSLContext}, default cipher suites and no host name @@ -80,9 +81,28 @@ public ProgrammaticSslEngineFactory( @NonNull SSLContext sslContext, @Nullable String[] cipherSuites, boolean requireHostnameValidation) { + this(sslContext, cipherSuites, requireHostnameValidation, true); + } + + /** + * Creates an instance with the given {@link SSLContext}, cipher suites and host name validation. + * + * @param sslContext the {@link SSLContext} to use. + * @param cipherSuites the cipher suites to use, or null to use the default ones. + * @param requireHostnameValidation whether to enable host name validation. If enabled, host name + * validation will be done using HTTPS algorithm. + * @param allowDnsReverseLookupSan whether to allow raw server IPs to be DNS reverse-resolved to + * choose the appropriate Subject Alternative Name. + */ + public ProgrammaticSslEngineFactory( + @NonNull SSLContext sslContext, + @Nullable String[] cipherSuites, + boolean requireHostnameValidation, + boolean allowDnsReverseLookupSan) { this.sslContext = sslContext; this.cipherSuites = cipherSuites; this.requireHostnameValidation = requireHostnameValidation; + this.allowDnsReverseLookupSan = allowDnsReverseLookupSan; } @NonNull @@ -92,7 +112,12 @@ public SSLEngine newSslEngine(@NonNull EndPoint remoteEndpoint) { SocketAddress remoteAddress = remoteEndpoint.resolve(); if (remoteAddress instanceof InetSocketAddress) { InetSocketAddress socketAddress = (InetSocketAddress) remoteAddress; - engine = sslContext.createSSLEngine(socketAddress.getHostName(), socketAddress.getPort()); + engine = + sslContext.createSSLEngine( + allowDnsReverseLookupSan + ? socketAddress.getHostName() + : socketAddress.getHostString(), + socketAddress.getPort()); } else { engine = sslContext.createSSLEngine(); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java index 475ec38d578..343d3f9e4e7 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/DefaultSslEngineFactory.java @@ -22,6 +22,7 @@ import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.api.core.ssl.SslEngineFactory; +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.InputStream; import java.net.InetSocketAddress; @@ -69,6 +70,7 @@ public class DefaultSslEngineFactory implements SslEngineFactory { private final SSLContext sslContext; private final String[] cipherSuites; private final boolean requireHostnameValidation; + private final boolean allowDnsReverseLookupSan; private ReloadingKeyManagerFactory kmf; /** Builds a new instance from the driver configuration. */ @@ -88,6 +90,28 @@ public DefaultSslEngineFactory(DriverContext driverContext) { } this.requireHostnameValidation = config.getBoolean(DefaultDriverOption.SSL_HOSTNAME_VALIDATION, true); + this.allowDnsReverseLookupSan = + config.getBoolean(DefaultDriverOption.SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN, true); + } + + @VisibleForTesting + protected String hostname(InetSocketAddress addr) { + return allowDnsReverseLookupSan ? hostMaybeFromDnsReverseLookup(addr) : hostNoLookup(addr); + } + + @VisibleForTesting + protected String hostMaybeFromDnsReverseLookup(InetSocketAddress addr) { + // See java.net.InetSocketAddress.getHostName: + // "This method may trigger a name service reverse lookup if the address was created with a + // literal IP address." + return addr.getHostName(); + } + + @VisibleForTesting + protected String hostNoLookup(InetSocketAddress addr) { + // See java.net.InetSocketAddress.getHostString: + // "This has the benefit of not attempting a reverse lookup" + return addr.getHostString(); } @NonNull @@ -97,7 +121,7 @@ public SSLEngine newSslEngine(@NonNull EndPoint remoteEndpoint) { SocketAddress remoteAddress = remoteEndpoint.resolve(); if (remoteAddress instanceof InetSocketAddress) { InetSocketAddress socketAddress = (InetSocketAddress) remoteAddress; - engine = sslContext.createSSLEngine(socketAddress.getHostName(), socketAddress.getPort()); + engine = sslContext.createSSLEngine(hostname(socketAddress), socketAddress.getPort()); } else { engine = sslContext.createSSLEngine(); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/SniSslEngineFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/SniSslEngineFactory.java index 98af19045dc..4d2cb69fbfc 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/SniSslEngineFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ssl/SniSslEngineFactory.java @@ -38,9 +38,15 @@ public class SniSslEngineFactory implements SslEngineFactory { private final SSLContext sslContext; private final CopyOnWriteArrayList fakePorts = new CopyOnWriteArrayList<>(); + private final boolean allowDnsReverseLookupSan; public SniSslEngineFactory(SSLContext sslContext) { + this(sslContext, true); + } + + public SniSslEngineFactory(SSLContext sslContext, boolean allowDnsReverseLookupSan) { this.sslContext = sslContext; + this.allowDnsReverseLookupSan = allowDnsReverseLookupSan; } @NonNull @@ -71,8 +77,8 @@ public SSLEngine newSslEngine(@NonNull EndPoint remoteEndpoint) { // To avoid that, we create a unique "fake" port for every node. We still get session reuse for // a given node, but not across nodes. This is safe because the advisory port is only used for // session caching. - SSLEngine engine = - sslContext.createSSLEngine(address.getHostName(), getFakePort(sniServerName)); + String peerHost = allowDnsReverseLookupSan ? address.getHostName() : address.getHostString(); + SSLEngine engine = sslContext.createSSLEngine(peerHost, getFakePort(sniServerName)); engine.setUseClientMode(true); SSLParameters parameters = engine.getSSLParameters(); parameters.setServerNames(ImmutableList.of(new SNIHostName(sniServerName))); diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 7b1c43f8bea..f09ffd18a10 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -789,6 +789,12 @@ datastax-java-driver { # name matches the hostname of the server being connected to. If not set, defaults to true. // hostname-validation = true + # Whether or not to allow a DNS reverse-lookup of provided server addresses for SAN addresses, + # if cluster endpoints are specified as literal IPs. + # This is left as true for compatibility, but in most environments a DNS reverse-lookup should + # not be necessary to get an address that matches the server certificate SANs. + // allow-dns-reverse-lookup-san = true + # The locations and passwords used to access truststore and keystore contents. # These properties are optional. If either truststore-path or keystore-path are specified, # the driver builds an SSLContext from these files. If neither option is specified, the diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/ssl/DefaultSslEngineFactoryIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/ssl/DefaultSslEngineFactoryIT.java index 5f97e661eb1..a2afeade3ce 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/ssl/DefaultSslEngineFactoryIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/ssl/DefaultSslEngineFactoryIT.java @@ -21,10 +21,13 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.context.DriverContext; import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule; import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.assertions.Assertions; import com.datastax.oss.driver.internal.core.ssl.DefaultSslEngineFactory; +import java.net.InetSocketAddress; import org.junit.ClassRule; import org.junit.Test; @@ -88,4 +91,67 @@ public void should_not_connect_if_not_using_ssl() { session.execute("select * from system.local"); } } + + public static class InstrumentedSslEngineFactory extends DefaultSslEngineFactory { + int countReverseLookups = 0; + int countNoLookups = 0; + + public InstrumentedSslEngineFactory(DriverContext driverContext) { + super(driverContext); + } + + @Override + protected String hostMaybeFromDnsReverseLookup(InetSocketAddress addr) { + countReverseLookups++; + return super.hostMaybeFromDnsReverseLookup(addr); + } + + @Override + protected String hostNoLookup(InetSocketAddress addr) { + countNoLookups++; + return super.hostNoLookup(addr); + } + }; + + @Test + public void should_respect_config_for_san_resolution() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withClass( + DefaultDriverOption.SSL_ENGINE_FACTORY_CLASS, InstrumentedSslEngineFactory.class) + .withBoolean(DefaultDriverOption.SSL_HOSTNAME_VALIDATION, false) + .withString( + DefaultDriverOption.SSL_TRUSTSTORE_PATH, + CcmBridge.DEFAULT_CLIENT_TRUSTSTORE_FILE.getAbsolutePath()) + .withString( + DefaultDriverOption.SSL_TRUSTSTORE_PASSWORD, + CcmBridge.DEFAULT_CLIENT_TRUSTSTORE_PASSWORD) + .build(); + try (CqlSession session = SessionUtils.newSession(CCM_RULE, loader)) { + InstrumentedSslEngineFactory ssl = + (InstrumentedSslEngineFactory) session.getContext().getSslEngineFactory().get(); + Assertions.assertThat(ssl.countReverseLookups).isGreaterThan(0); + Assertions.assertThat(ssl.countNoLookups).isEqualTo(0); + } + + loader = + SessionUtils.configLoaderBuilder() + .withClass( + DefaultDriverOption.SSL_ENGINE_FACTORY_CLASS, InstrumentedSslEngineFactory.class) + .withBoolean(DefaultDriverOption.SSL_HOSTNAME_VALIDATION, false) + .withString( + DefaultDriverOption.SSL_TRUSTSTORE_PATH, + CcmBridge.DEFAULT_CLIENT_TRUSTSTORE_FILE.getAbsolutePath()) + .withString( + DefaultDriverOption.SSL_TRUSTSTORE_PASSWORD, + CcmBridge.DEFAULT_CLIENT_TRUSTSTORE_PASSWORD) + .withBoolean(DefaultDriverOption.SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN, false) + .build(); + try (CqlSession session = SessionUtils.newSession(CCM_RULE, loader)) { + InstrumentedSslEngineFactory ssl = + (InstrumentedSslEngineFactory) session.getContext().getSslEngineFactory().get(); + Assertions.assertThat(ssl.countReverseLookups).isEqualTo(0); + Assertions.assertThat(ssl.countNoLookups).isGreaterThan(0); + } + } } From 7982f413a90935a91549aa3ee7cc64fa25d7c113 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 3 Mar 2025 11:46:42 -0600 Subject: [PATCH 362/395] ninja-fix Minor fix to CASSJAVA-80 change. Adding new entries to DefaultDriverOption anywhere other than at the end messes with the ordinal guarantees for exisitng apps. We have a check for such a thing in the build; moving this around avoids that concern. --- .../api/core/config/DefaultDriverOption.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index acd4bb9cc1d..6ffd51d86ef 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -243,12 +243,6 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: boolean */ SSL_HOSTNAME_VALIDATION("advanced.ssl-engine-factory.hostname-validation"), - /** - * Whether or not to do a DNS reverse-lookup of provided server addresses for SAN addresses. - * - *

    Value-type: boolean - */ - SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN("advanced.ssl-engine-factory.allow-dns-reverse-lookup-san"), /** * The location of the keystore file. * @@ -994,7 +988,13 @@ public enum DefaultDriverOption implements DriverOption { *

    Value type: {@link java.util.List List}<{@link String}> */ LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS( - "advanced.load-balancing-policy.dc-failover.preferred-remote-dcs"); + "advanced.load-balancing-policy.dc-failover.preferred-remote-dcs"), + /** + * Whether or not to do a DNS reverse-lookup of provided server addresses for SAN addresses. + * + *

    Value-type: boolean + */ + SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN("advanced.ssl-engine-factory.allow-dns-reverse-lookup-san"); private final String path; From c0cae9bf76024f8004abaa1ddb871b7351fc253e Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Tue, 25 Mar 2025 15:27:55 -0500 Subject: [PATCH 363/395] CASSJAVA-90 Update native-protocol version patch by Bret McGuire; reviewed by Abe Ratnofsky and Bret McGuire for CASSJAVA-90 --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 8e7bc467fe7..f03317edc03 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -78,7 +78,7 @@ com.datastax.oss native-protocol - 1.5.1 + 1.5.2 From 204dd09329a073043b5b7cc170a9850e270c5a63 Mon Sep 17 00:00:00 2001 From: janehe Date: Mon, 31 Mar 2025 13:24:31 -0700 Subject: [PATCH 364/395] CASSJAVA-40: Driver testing against Java 21 patch by Jane He; reviewed by Bret McGuire for CASSJAVA-40 --- Jenkinsfile-asf | 4 ++-- .../oss/driver/internal/core/util/ArrayUtils.java | 3 ++- .../internal/core/cql/QueryTraceFetcherTest.java | 2 +- .../driver/internal/core/util/ArrayUtilsTest.java | 4 ++-- pom.xml | 13 +++++++++++++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile-asf b/Jenkinsfile-asf index 0217d0455d6..d6318585489 100644 --- a/Jenkinsfile-asf +++ b/Jenkinsfile-asf @@ -35,7 +35,7 @@ pipeline { axes { axis { name 'TEST_JAVA_VERSION' - values 'openjdk@1.8.0-292', 'openjdk@1.11.0-9', 'openjdk@17' + values 'openjdk@1.8.0-292', 'openjdk@1.11.0-9', 'openjdk@17', 'openjdk@1.21.0' } axis { name 'SERVER_VERSION' @@ -67,7 +67,7 @@ pipeline { def executeTests() { def testJavaMajorVersion = (TEST_JAVA_VERSION =~ /@(?:1\.)?(\d+)/)[0][1] sh """ - container_id=\$(docker run -td -e TEST_JAVA_VERSION=${TEST_JAVA_VERSION} -e SERVER_VERSION=${SERVER_VERSION} -e TEST_JAVA_MAJOR_VERSION=${testJavaMajorVersion} -v \$(pwd):/home/docker/cassandra-java-driver apache.jfrog.io/cassan-docker/apache/cassandra-java-driver-testing-ubuntu2204 'sleep 2h') + container_id=\$(docker run -td -e TEST_JAVA_VERSION=${TEST_JAVA_VERSION} -e SERVER_VERSION=${SERVER_VERSION} -e TEST_JAVA_MAJOR_VERSION=${testJavaMajorVersion} -v \$(pwd):/home/docker/cassandra-java-driver janehe158/cassandra-java-driver-dev-env 'sleep 2h') docker exec --user root \$container_id bash -c \"sudo bash /home/docker/cassandra-java-driver/ci/create-user.sh docker \$(id -u) \$(id -g) /home/docker/cassandra-java-driver\" docker exec --user docker \$container_id './cassandra-java-driver/ci/run-tests.sh' ( nohup docker stop \$container_id >/dev/null 2>/dev/null & ) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/ArrayUtils.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/ArrayUtils.java index f5fcb98e8b7..490b1dc7d17 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/util/ArrayUtils.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/ArrayUtils.java @@ -18,6 +18,7 @@ package com.datastax.oss.driver.internal.core.util; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Random; import java.util.concurrent.ThreadLocalRandom; public class ArrayUtils { @@ -77,7 +78,7 @@ public static void shuffleHead(@NonNull ElementT[] elements, int n) { * Fisher-Yates shuffle */ public static void shuffleHead( - @NonNull ElementT[] elements, int n, @NonNull ThreadLocalRandom random) { + @NonNull ElementT[] elements, int n, @NonNull Random random) { if (n > elements.length) { throw new ArrayIndexOutOfBoundsException( String.format( diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/QueryTraceFetcherTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/QueryTraceFetcherTest.java index b355e0fc9f0..dc238775bc1 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/QueryTraceFetcherTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/QueryTraceFetcherTest.java @@ -79,7 +79,7 @@ public class QueryTraceFetcherTest { @Mock private NettyOptions nettyOptions; @Mock private EventExecutorGroup adminEventExecutorGroup; @Mock private EventExecutor eventExecutor; - @Mock private InetAddress address; + private InetAddress address = InetAddress.getLoopbackAddress(); @Captor private ArgumentCaptor statementCaptor; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/util/ArrayUtilsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/util/ArrayUtilsTest.java index c2a7fb70304..c2df6449fdb 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/util/ArrayUtilsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/util/ArrayUtilsTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.util.concurrent.ThreadLocalRandom; +import java.util.Random; import org.junit.Test; public class ArrayUtilsTest { @@ -86,7 +86,7 @@ public void should_not_bubble_down_when_target_index_lower() { @Test public void should_shuffle_head() { String[] array = {"a", "b", "c", "d", "e"}; - ThreadLocalRandom random = mock(ThreadLocalRandom.class); + Random random = mock(Random.class); when(random.nextInt(anyInt())) .thenAnswer( (invocation) -> { diff --git a/pom.xml b/pom.xml index 3fd2d1347c2..088d7b07532 100644 --- a/pom.xml +++ b/pom.xml @@ -1016,6 +1016,19 @@ limitations under the License.]]> --add-opens java.base/jdk.internal.util.random=ALL-UNNAMED + + + test-jdk-21 + + [21,) + + + + -XX:+AllowRedefinitionToAddDeleteMethods + + --add-opens=java.base/jdk.internal.util.random=ALL-UNNAMED + + From 529d56e1742dcd1df3ca55c00fd8e02c0e484c68 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 31 Mar 2025 16:00:18 -0500 Subject: [PATCH 365/395] Add support for Java21 builds to test runs (plus a few other small cleanups) patch by Bret McGuire; reviewed by Joao Reis for CASSJAVA-40 --- Jenkinsfile-datastax | 50 ++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/Jenkinsfile-datastax b/Jenkinsfile-datastax index cd48f325a29..af1aab6e0f4 100644 --- a/Jenkinsfile-datastax +++ b/Jenkinsfile-datastax @@ -19,22 +19,15 @@ */ def initializeEnvironment() { - env.DRIVER_DISPLAY_NAME = 'CassandraⓇ Java Driver' + env.DRIVER_DISPLAY_NAME = 'Java Driver for Apache CassandraⓇ' env.DRIVER_METRIC_TYPE = 'oss' - if (env.GIT_URL.contains('riptano/java-driver')) { - env.DRIVER_DISPLAY_NAME = 'private ' + env.DRIVER_DISPLAY_NAME - env.DRIVER_METRIC_TYPE = 'oss-private' - } else if (env.GIT_URL.contains('java-dse-driver')) { - env.DRIVER_DISPLAY_NAME = 'DSE Java Driver' - env.DRIVER_METRIC_TYPE = 'dse' - } env.GIT_SHA = "${env.GIT_COMMIT.take(7)}" env.GITHUB_PROJECT_URL = "https://${GIT_URL.replaceFirst(/(git@|http:\/\/|https:\/\/)/, '').replace(':', '/').replace('.git', '')}" env.GITHUB_BRANCH_URL = "${GITHUB_PROJECT_URL}/tree/${env.BRANCH_NAME}" env.GITHUB_COMMIT_URL = "${GITHUB_PROJECT_URL}/commit/${env.GIT_COMMIT}" - env.MAVEN_HOME = "${env.HOME}/.mvn/apache-maven-3.3.9" + env.MAVEN_HOME = "${env.HOME}/.mvn/apache-maven-3.6.3" env.PATH = "${env.MAVEN_HOME}/bin:${env.PATH}" /* @@ -335,14 +328,12 @@ pipeline { ''') choice( name: 'ADHOC_BUILD_AND_EXECUTE_TESTS_JABBA_VERSION', - choices: ['1.8', // Oracle JDK version 1.8 (current default) - 'openjdk@1.9', // OpenJDK version 9 - 'openjdk@1.10', // OpenJDK version 10 + choices: [ + '1.8', // Oracle JDK version 1.8 (current default) 'openjdk@1.11', // OpenJDK version 11 - 'openjdk@1.12', // OpenJDK version 12 - 'openjdk@1.13', // OpenJDK version 13 - 'openjdk@1.14', // OpenJDK version 14 - 'openjdk@1.17'], // OpenJDK version 17 + 'openjdk@1.17', // OpenJDK version 17 + 'openjdk@1.21' // OpenJDK version 21 + ], description: '''JDK version to use for TESTING when running adhoc BUILD-AND-EXECUTE-TESTS builds. All builds will use JDK8 for building the driver @@ -355,34 +346,18 @@ pipeline { - - - - - - - - - - - - - - - - - - - - + + + +
    1.8 Oracle JDK version 1.8 (Used for compiling regardless of choice)
    openjdk@1.9OpenJDK version 9
    openjdk@1.10OpenJDK version 10
    openjdk@1.11 OpenJDK version 11
    openjdk@1.12OpenJDK version 12
    openjdk@1.13OpenJDK version 13
    openjdk@1.14OpenJDK version 14
    openjdk@1.17 OpenJDK version 17
    openjdk@1.21OpenJDK version 21
    ''') booleanParam( name: 'SKIP_SERIAL_ITS', @@ -466,7 +441,8 @@ pipeline { name 'JABBA_VERSION' values '1.8', // jdk8 'openjdk@1.11', // jdk11 - 'openjdk@1.17' // jdk17 + 'openjdk@1.17', // jdk17 + 'openjdk@1.21' // jdk21 } } From f42ab99ccc031bca7db6cf69aec70771d65799e1 Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Mon, 10 Feb 2025 13:11:06 -0500 Subject: [PATCH 366/395] Upgrade Netty to 4.1.119 patch by Abe Ratnofsky; reviewed by Bret McGuire for CASSJAVA-77 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 088d7b07532..a8841a9caca 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 2.1.12 4.1.18 - 4.1.94.Final + 4.1.119.Final 1.2.1 - com.datastax.oss:${project.artifactId}:RELEASE + ${project.groupId}:${project.artifactId}:RELEASE From 0115cd67c18835b89d8888d405d455045737a630 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Fri, 11 Apr 2025 13:19:45 +0200 Subject: [PATCH 368/395] Prevent long overflow in SNI address resolution patch by Lukasz Antoniak and Alexandre Dutra; reviewed by Bret McGuire --- .../oss/driver/internal/core/metadata/SniEndPoint.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java index ace4e82617d..d1ab8eec98d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java @@ -26,10 +26,10 @@ import java.util.Arrays; import java.util.Comparator; import java.util.Objects; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicInteger; public class SniEndPoint implements EndPoint { - private static final AtomicLong OFFSET = new AtomicLong(); + private static final AtomicInteger OFFSET = new AtomicInteger(); private final InetSocketAddress proxyAddress; private final String serverName; @@ -64,7 +64,10 @@ public InetSocketAddress resolve() { // The order of the returned address is unspecified. Sort by IP to make sure we get a true // round-robin Arrays.sort(aRecords, IP_COMPARATOR); - int index = (aRecords.length == 1) ? 0 : (int) OFFSET.getAndIncrement() % aRecords.length; + int index = + (aRecords.length == 1) + ? 0 + : OFFSET.getAndUpdate(x -> x == Integer.MAX_VALUE ? 0 : x + 1) % aRecords.length; return new InetSocketAddress(aRecords[index], proxyAddress.getPort()); } catch (UnknownHostException e) { throw new IllegalArgumentException( From 7161d12fb28d16e2928cfe98bbada151ff6ae058 Mon Sep 17 00:00:00 2001 From: janehe Date: Wed, 23 Apr 2025 22:25:03 -0700 Subject: [PATCH 369/395] ninja-fix Revert docker image name (CASSJAVA-40) --- Jenkinsfile-asf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile-asf b/Jenkinsfile-asf index d6318585489..24800ba9051 100644 --- a/Jenkinsfile-asf +++ b/Jenkinsfile-asf @@ -67,7 +67,7 @@ pipeline { def executeTests() { def testJavaMajorVersion = (TEST_JAVA_VERSION =~ /@(?:1\.)?(\d+)/)[0][1] sh """ - container_id=\$(docker run -td -e TEST_JAVA_VERSION=${TEST_JAVA_VERSION} -e SERVER_VERSION=${SERVER_VERSION} -e TEST_JAVA_MAJOR_VERSION=${testJavaMajorVersion} -v \$(pwd):/home/docker/cassandra-java-driver janehe158/cassandra-java-driver-dev-env 'sleep 2h') + container_id=\$(docker run -td -e TEST_JAVA_VERSION=${TEST_JAVA_VERSION} -e SERVER_VERSION=${SERVER_VERSION} -e TEST_JAVA_MAJOR_VERSION=${testJavaMajorVersion} -v \$(pwd):/home/docker/cassandra-java-driver apache.jfrog.io/cassan-docker/apache/cassandra-java-driver-testing-ubuntu2204 'sleep 2h') docker exec --user root \$container_id bash -c \"sudo bash /home/docker/cassandra-java-driver/ci/create-user.sh docker \$(id -u) \$(id -g) /home/docker/cassandra-java-driver\" docker exec --user docker \$container_id './cassandra-java-driver/ci/run-tests.sh' ( nohup docker stop \$container_id >/dev/null 2>/dev/null & ) From d7e829775c4956d10c888c86b653f7ac2d10fa4b Mon Sep 17 00:00:00 2001 From: Andy Tolbert <6889771+tolbertam@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:57:52 -0600 Subject: [PATCH 370/395] Make guava an optional dependency of java-driver-guava-shaded With CASSJAVA-52, the java-driver-guava-shaded is now in tree. This appears to work great, but there is a slight issue with the dependency tree that allows unshaded guava packages to be imported within the project. It looks like marking guava as an optional dependency in java-driver-guava-shaded resolves this. patch by Andy Tolbert; reviewed by Alexandre Dutra and Dmitry Konstantinov for CASSJAVA-76 --- guava-shaded/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index 8053af94911..ed37e861a96 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -46,6 +46,7 @@ error_prone_annotations + true org.graalvm.nativeimage From eb54934d5d2f38757da3a94a8ad4960f66eb4bd6 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Nov 2024 19:01:32 -0800 Subject: [PATCH 371/395] Bump Jackson version to la(te)st 2.13, 2.13.5 patch by Tatu Saloranta; reviewed by Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1989 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c69dabb84ce..e5cfb58f94d 100644 --- a/pom.xml +++ b/pom.xml @@ -69,8 +69,8 @@ 1.0.3 20230227 - 2.13.4 - 2.13.4.2 + 2.13.5 + ${jackson.version} 1.1.10.1 1.7.1 From 53bb5c8b6580c5797e4f148cdc818885327cd19e Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Nov 2024 18:41:50 -0800 Subject: [PATCH 372/395] CASSJAVA-68 Improve DefaultCodecRegisry.CacheKey#hashCode() to eliminate Object[] allocation (found via profiler) patch by Tatu Saloranta; reviewed by Dmitry Konstantinov and Bret McGuire for CASSJAVA-68 --- .../core/type/codec/registry/DefaultCodecRegistry.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java index cfd053ea56e..4334f22b63d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java @@ -159,7 +159,10 @@ public boolean equals(Object other) { @Override public int hashCode() { - return Objects.hash(cqlType, javaType, isJavaCovariant); + // NOTE: inlined Objects.hash for performance reasons (avoid Object[] allocation + // seen in profiler allocation traces) + return ((31 + Objects.hashCode(cqlType)) * 31 + Objects.hashCode(javaType)) * 31 + + Boolean.hashCode(isJavaCovariant); } } } From c9facc3c36e7ba0b1d30fb9b10de69f879d34fb5 Mon Sep 17 00:00:00 2001 From: janehe Date: Mon, 5 May 2025 19:37:32 -0700 Subject: [PATCH 373/395] ninja-fix Format fix for previous commit --- .../internal/core/type/codec/registry/DefaultCodecRegistry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java index 4334f22b63d..cc14740e180 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/type/codec/registry/DefaultCodecRegistry.java @@ -162,7 +162,7 @@ public int hashCode() { // NOTE: inlined Objects.hash for performance reasons (avoid Object[] allocation // seen in profiler allocation traces) return ((31 + Objects.hashCode(cqlType)) * 31 + Objects.hashCode(javaType)) * 31 - + Boolean.hashCode(isJavaCovariant); + + Boolean.hashCode(isJavaCovariant); } } } From bb9bb11e573258e12e4272379f88e4d8b5f103a0 Mon Sep 17 00:00:00 2001 From: alexsa Date: Thu, 12 Jun 2025 10:02:09 +0200 Subject: [PATCH 374/395] Add SubnetAddressTranslator to translate Cassandra node IPs from private network based on its subnet mask patch by Alex Sasnouskikh; reviewed by Bret McGuire and Andy Tolbert reference: https://github.com/apache/cassandra-java-driver/pull/2013 --- .../api/core/config/DefaultDriverOption.java | 43 ++++- .../api/core/config/TypedDriverOption.java | 14 ++ .../driver/internal/core/ContactPoints.java | 61 ++---- .../FixedHostNameAddressTranslator.java | 20 +- .../core/addresstranslation/Subnet.java | 176 ++++++++++++++++++ .../addresstranslation/SubnetAddress.java | 65 +++++++ .../SubnetAddressTranslator.java | 148 +++++++++++++++ .../internal/core/util/AddressUtils.java | 59 ++++++ core/src/main/resources/reference.conf | 18 +- .../internal/core/ContactPointsTest.java | 4 +- .../FixedHostNameAddressTranslatorTest.java | 5 +- .../addresstranslation/SubnetAddressTest.java | 44 +++++ .../SubnetAddressTranslatorTest.java | 153 +++++++++++++++ .../core/addresstranslation/SubnetTest.java | 118 ++++++++++++ .../internal/core/config/MockOptions.java | 1 + .../typesafe/TypesafeDriverConfigTest.java | 14 +- manual/core/address_resolution/README.md | 49 +++++ 17 files changed, 923 insertions(+), 69 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Subnet.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddress.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslator.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/util/AddressUtils.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetTest.java diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 6ffd51d86ef..4e45bf7b117 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -994,7 +994,48 @@ public enum DefaultDriverOption implements DriverOption { * *

    Value-type: boolean */ - SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN("advanced.ssl-engine-factory.allow-dns-reverse-lookup-san"); + SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN("advanced.ssl-engine-factory.allow-dns-reverse-lookup-san"), + /** + * An address to always translate all node addresses to that same proxy hostname no matter what IP + * address a node has, but still using its native transport port. + * + *

    Value-Type: {@link String} + */ + ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME("advanced.address-translator.advertised-hostname"), + /** + * A map of Cassandra node subnets (CIDR notations) to target addresses, for example (note quoted + * keys): + * + *

    +   * advanced.address-translator.subnet-addresses {
    +   *   "100.64.0.0/15" = "cassandra.datacenter1.com:9042"
    +   *   "100.66.0.0/15" = "cassandra.datacenter2.com:9042"
    +   *   # IPv6 example:
    +   *   # "::ffff:6440:0/111" = "cassandra.datacenter1.com:9042"
    +   *   # "::ffff:6442:0/111" = "cassandra.datacenter2.com:9042"
    +   * }
    +   * 
    + * + * Note: subnets must be represented as prefix blocks, see {@link + * inet.ipaddr.Address#isPrefixBlock()}. + * + *

    Value type: {@link java.util.Map Map}<{@link String},{@link String}> + */ + ADDRESS_TRANSLATOR_SUBNET_ADDRESSES("advanced.address-translator.subnet-addresses"), + /** + * A default address to fallback to if Cassandra node IP isn't contained in any of the configured + * subnets. + * + *

    Value-Type: {@link String} + */ + ADDRESS_TRANSLATOR_DEFAULT_ADDRESS("advanced.address-translator.default-address"), + /** + * Whether to resolve the addresses on initialization (if true) or on each node (re-)connection + * (if false). Defaults to false. + * + *

    Value-Type: boolean + */ + ADDRESS_TRANSLATOR_RESOLVE_ADDRESSES("advanced.address-translator.resolve-addresses"); private final String path; diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index 93e2b468461..aa4e4af12dc 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -896,6 +896,20 @@ public String toString() { DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS, GenericType.BOOLEAN); + public static final TypedDriverOption ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME = + new TypedDriverOption<>( + DefaultDriverOption.ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME, GenericType.STRING); + public static final TypedDriverOption> ADDRESS_TRANSLATOR_SUBNET_ADDRESSES = + new TypedDriverOption<>( + DefaultDriverOption.ADDRESS_TRANSLATOR_SUBNET_ADDRESSES, + GenericType.mapOf(GenericType.STRING, GenericType.STRING)); + public static final TypedDriverOption ADDRESS_TRANSLATOR_DEFAULT_ADDRESS = + new TypedDriverOption<>( + DefaultDriverOption.ADDRESS_TRANSLATOR_DEFAULT_ADDRESS, GenericType.STRING); + public static final TypedDriverOption ADDRESS_TRANSLATOR_RESOLVE_ADDRESSES = + new TypedDriverOption<>( + DefaultDriverOption.ADDRESS_TRANSLATOR_RESOLVE_ADDRESSES, GenericType.BOOLEAN); + /** * Ordered preference list of remote dcs optionally supplied for automatic failover and included * in query plan. This feature is enabled only when max-nodes-per-remote-dc is greater than 0. diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java index 1ed2a1cebf3..bb65661b72f 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java @@ -19,14 +19,11 @@ import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.internal.core.metadata.DefaultEndPoint; +import com.datastax.oss.driver.internal.core.util.AddressUtils; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import com.datastax.oss.driver.shaded.guava.common.collect.Sets; -import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; import org.slf4j.Logger; @@ -41,7 +38,22 @@ public static Set merge( Set result = Sets.newHashSet(programmaticContactPoints); for (String spec : configContactPoints) { - for (InetSocketAddress address : extract(spec, resolve)) { + + Set addresses = Collections.emptySet(); + try { + addresses = AddressUtils.extract(spec, resolve); + } catch (RuntimeException e) { + LOG.warn("Ignoring invalid contact point {} ({})", spec, e.getMessage(), e); + } + + if (addresses.size() > 1) { + LOG.info( + "Contact point {} resolves to multiple addresses, will use them all ({})", + spec, + addresses); + } + + for (InetSocketAddress address : addresses) { DefaultEndPoint endPoint = new DefaultEndPoint(address); boolean wasNew = result.add(endPoint); if (!wasNew) { @@ -51,43 +63,4 @@ public static Set merge( } return ImmutableSet.copyOf(result); } - - private static Set extract(String spec, boolean resolve) { - int separator = spec.lastIndexOf(':'); - if (separator < 0) { - LOG.warn("Ignoring invalid contact point {} (expecting host:port)", spec); - return Collections.emptySet(); - } - - String host = spec.substring(0, separator); - String portSpec = spec.substring(separator + 1); - int port; - try { - port = Integer.parseInt(portSpec); - } catch (NumberFormatException e) { - LOG.warn("Ignoring invalid contact point {} (expecting a number, got {})", spec, portSpec); - return Collections.emptySet(); - } - if (!resolve) { - return ImmutableSet.of(InetSocketAddress.createUnresolved(host, port)); - } else { - try { - InetAddress[] inetAddresses = InetAddress.getAllByName(host); - if (inetAddresses.length > 1) { - LOG.info( - "Contact point {} resolves to multiple addresses, will use them all ({})", - spec, - Arrays.deepToString(inetAddresses)); - } - Set result = new HashSet<>(); - for (InetAddress inetAddress : inetAddresses) { - result.add(new InetSocketAddress(inetAddress, port)); - } - return result; - } catch (UnknownHostException e) { - LOG.warn("Ignoring invalid contact point {} (unknown host {})", spec, host); - return Collections.emptySet(); - } - } - } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java index 4fb9782f566..5cc6c2518fb 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslator.java @@ -17,8 +17,9 @@ */ package com.datastax.oss.driver.internal.core.addresstranslation; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME; + import com.datastax.oss.driver.api.core.addresstranslation.AddressTranslator; -import com.datastax.oss.driver.api.core.config.DriverOption; import com.datastax.oss.driver.api.core.context.DriverContext; import edu.umd.cs.findbugs.annotations.NonNull; import java.net.InetSocketAddress; @@ -37,28 +38,13 @@ public class FixedHostNameAddressTranslator implements AddressTranslator { private static final Logger LOG = LoggerFactory.getLogger(FixedHostNameAddressTranslator.class); - public static final String ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME = - "advanced.address-translator.advertised-hostname"; - - public static DriverOption ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME_OPTION = - new DriverOption() { - @NonNull - @Override - public String getPath() { - return ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME; - } - }; - private final String advertisedHostname; private final String logPrefix; public FixedHostNameAddressTranslator(@NonNull DriverContext context) { logPrefix = context.getSessionName(); advertisedHostname = - context - .getConfig() - .getDefaultProfile() - .getString(ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME_OPTION); + context.getConfig().getDefaultProfile().getString(ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME); } @NonNull diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Subnet.java b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Subnet.java new file mode 100644 index 00000000000..7c25e94e2f9 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Subnet.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import com.datastax.oss.driver.shaded.guava.common.base.Splitter; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; + +class Subnet { + private final byte[] subnet; + private final byte[] networkMask; + private final byte[] upper; + private final byte[] lower; + + private Subnet(byte[] subnet, byte[] networkMask) { + this.subnet = subnet; + this.networkMask = networkMask; + + byte[] upper = new byte[subnet.length]; + byte[] lower = new byte[subnet.length]; + for (int i = 0; i < subnet.length; i++) { + upper[i] = (byte) (subnet[i] | ~networkMask[i]); + lower[i] = (byte) (subnet[i] & networkMask[i]); + } + this.upper = upper; + this.lower = lower; + } + + static Subnet parse(String subnetCIDR) throws UnknownHostException { + List parts = Splitter.on("/").splitToList(subnetCIDR); + if (parts.size() != 2) { + throw new IllegalArgumentException("Invalid subnet: " + subnetCIDR); + } + + boolean isIPv6 = parts.get(0).contains(":"); + byte[] subnet = InetAddress.getByName(parts.get(0)).getAddress(); + if (isIPv4(subnet) && isIPv6) { + subnet = toIPv6(subnet); + } + int prefixLength = Integer.parseInt(parts.get(1)); + validatePrefixLength(subnet, prefixLength); + + byte[] networkMask = toNetworkMask(subnet, prefixLength); + validateSubnetIsPrefixBlock(subnet, networkMask, subnetCIDR); + return new Subnet(subnet, networkMask); + } + + private static byte[] toNetworkMask(byte[] subnet, int prefixLength) { + int fullBytes = prefixLength / 8; + int remainingBits = prefixLength % 8; + byte[] mask = new byte[subnet.length]; + Arrays.fill(mask, 0, fullBytes, (byte) 0xFF); + if (remainingBits > 0) { + mask[fullBytes] = (byte) (0xFF << (8 - remainingBits)); + } + return mask; + } + + private static void validatePrefixLength(byte[] subnet, int prefixLength) { + int max_prefix_length = subnet.length * 8; + if (prefixLength < 0 || max_prefix_length < prefixLength) { + throw new IllegalArgumentException( + String.format( + "Prefix length %s must be within [0; %s]", prefixLength, max_prefix_length)); + } + } + + private static void validateSubnetIsPrefixBlock( + byte[] subnet, byte[] networkMask, String subnetCIDR) { + byte[] prefixBlock = toPrefixBlock(subnet, networkMask); + if (!Arrays.equals(subnet, prefixBlock)) { + throw new IllegalArgumentException( + String.format("Subnet %s must be represented as a network prefix block", subnetCIDR)); + } + } + + private static byte[] toPrefixBlock(byte[] subnet, byte[] networkMask) { + byte[] prefixBlock = new byte[subnet.length]; + for (int i = 0; i < subnet.length; i++) { + prefixBlock[i] = (byte) (subnet[i] & networkMask[i]); + } + return prefixBlock; + } + + @VisibleForTesting + byte[] getSubnet() { + return Arrays.copyOf(subnet, subnet.length); + } + + @VisibleForTesting + byte[] getNetworkMask() { + return Arrays.copyOf(networkMask, networkMask.length); + } + + byte[] getUpper() { + return Arrays.copyOf(upper, upper.length); + } + + byte[] getLower() { + return Arrays.copyOf(lower, lower.length); + } + + boolean isIPv4() { + return isIPv4(subnet); + } + + boolean isIPv6() { + return isIPv6(subnet); + } + + boolean contains(byte[] ip) { + if (isIPv4() && !isIPv4(ip)) { + return false; + } + if (isIPv6() && isIPv4(ip)) { + ip = toIPv6(ip); + } + if (subnet.length != ip.length) { + throw new IllegalArgumentException( + "IP version is unknown: " + Arrays.toString(toZeroBasedByteArray(ip))); + } + for (int i = 0; i < subnet.length; i++) { + if (subnet[i] != (byte) (ip[i] & networkMask[i])) { + return false; + } + } + return true; + } + + private static boolean isIPv4(byte[] ip) { + return ip.length == 4; + } + + private static boolean isIPv6(byte[] ip) { + return ip.length == 16; + } + + private static byte[] toIPv6(byte[] ipv4) { + byte[] ipv6 = new byte[16]; + ipv6[10] = (byte) 0xFF; + ipv6[11] = (byte) 0xFF; + System.arraycopy(ipv4, 0, ipv6, 12, 4); + return ipv6; + } + + @Override + public String toString() { + return Arrays.toString(toZeroBasedByteArray(subnet)); + } + + private static int[] toZeroBasedByteArray(byte[] bytes) { + int[] res = new int[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + res[i] = bytes[i] & 0xFF; + } + return res; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddress.java b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddress.java new file mode 100644 index 00000000000..105e776a507 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddress.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +class SubnetAddress { + private final Subnet subnet; + private final InetSocketAddress address; + + SubnetAddress(String subnetCIDR, InetSocketAddress address) { + try { + this.subnet = Subnet.parse(subnetCIDR); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + this.address = address; + } + + InetSocketAddress getAddress() { + return this.address; + } + + boolean isOverlapping(SubnetAddress other) { + Subnet thisSubnet = this.subnet; + Subnet otherSubnet = other.subnet; + return thisSubnet.contains(otherSubnet.getLower()) + || thisSubnet.contains(otherSubnet.getUpper()) + || otherSubnet.contains(thisSubnet.getLower()) + || otherSubnet.contains(thisSubnet.getUpper()); + } + + boolean contains(InetSocketAddress address) { + return subnet.contains(address.getAddress().getAddress()); + } + + boolean isIPv4() { + return subnet.isIPv4(); + } + + boolean isIPv6() { + return subnet.isIPv6(); + } + + @Override + public String toString() { + return "SubnetAddress[subnet=" + subnet + ", address=" + address + "]"; + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslator.java new file mode 100644 index 00000000000..85f29e3fadd --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslator.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_DEFAULT_ADDRESS; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_RESOLVE_ADDRESSES; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_SUBNET_ADDRESSES; + +import com.datastax.oss.driver.api.core.addresstranslation.AddressTranslator; +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.internal.core.util.AddressUtils; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This translator returns the proxy address of the private subnet containing the Cassandra node IP, + * or default address if no matching subnets, or passes through the original node address if no + * default configured. + * + *

    The translator can be used for scenarios when all nodes are behind some kind of proxy, and + * that proxy is different for nodes located in different subnets (eg. when Cassandra is deployed in + * multiple datacenters/regions). One can use this, for example, for Cassandra on Kubernetes with + * different Cassandra datacenters deployed to different Kubernetes clusters. + */ +public class SubnetAddressTranslator implements AddressTranslator { + private static final Logger LOG = LoggerFactory.getLogger(SubnetAddressTranslator.class); + + private final List subnetAddresses; + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private final Optional defaultAddress; + + private final String logPrefix; + + public SubnetAddressTranslator(@NonNull DriverContext context) { + logPrefix = context.getSessionName(); + boolean resolveAddresses = + context + .getConfig() + .getDefaultProfile() + .getBoolean(ADDRESS_TRANSLATOR_RESOLVE_ADDRESSES, false); + this.subnetAddresses = + context.getConfig().getDefaultProfile().getStringMap(ADDRESS_TRANSLATOR_SUBNET_ADDRESSES) + .entrySet().stream() + .map( + e -> { + // Quoted and/or containing forward slashes map keys in reference.conf are read to + // strings with additional quotes, eg. 100.64.0.0/15 -> '100.64.0."0/15"' or + // "100.64.0.0/15" -> '"100.64.0.0/15"' + String subnetCIDR = e.getKey().replaceAll("\"", ""); + String address = e.getValue(); + return new SubnetAddress(subnetCIDR, parseAddress(address, resolveAddresses)); + }) + .collect(Collectors.toList()); + this.defaultAddress = + Optional.ofNullable( + context + .getConfig() + .getDefaultProfile() + .getString(ADDRESS_TRANSLATOR_DEFAULT_ADDRESS, null)) + .map(address -> parseAddress(address, resolveAddresses)); + + validateSubnetsAreOfSameProtocol(this.subnetAddresses); + validateSubnetsAreNotOverlapping(this.subnetAddresses); + } + + private static void validateSubnetsAreOfSameProtocol(List subnets) { + for (int i = 0; i < subnets.size() - 1; i++) { + for (int j = i + 1; j < subnets.size(); j++) { + SubnetAddress subnet1 = subnets.get(i); + SubnetAddress subnet2 = subnets.get(j); + if (subnet1.isIPv4() != subnet2.isIPv4() && subnet1.isIPv6() != subnet2.isIPv6()) { + throw new IllegalArgumentException( + String.format( + "Configured subnets are of the different protocols: %s, %s", subnet1, subnet2)); + } + } + } + } + + private static void validateSubnetsAreNotOverlapping(List subnets) { + for (int i = 0; i < subnets.size() - 1; i++) { + for (int j = i + 1; j < subnets.size(); j++) { + SubnetAddress subnet1 = subnets.get(i); + SubnetAddress subnet2 = subnets.get(j); + if (subnet1.isOverlapping(subnet2)) { + throw new IllegalArgumentException( + String.format("Configured subnets are overlapping: %s, %s", subnet1, subnet2)); + } + } + } + } + + @NonNull + @Override + public InetSocketAddress translate(@NonNull InetSocketAddress address) { + InetSocketAddress translatedAddress = null; + for (SubnetAddress subnetAddress : subnetAddresses) { + if (subnetAddress.contains(address)) { + translatedAddress = subnetAddress.getAddress(); + } + } + if (translatedAddress == null && defaultAddress.isPresent()) { + translatedAddress = defaultAddress.get(); + } + if (translatedAddress == null) { + translatedAddress = address; + } + LOG.debug("[{}] Translated {} to {}", logPrefix, address, translatedAddress); + return translatedAddress; + } + + @Override + public void close() {} + + @Nullable + private InetSocketAddress parseAddress(String address, boolean resolve) { + try { + InetSocketAddress parsedAddress = AddressUtils.extract(address, resolve).iterator().next(); + LOG.debug("[{}] Parsed {} to {}", logPrefix, address, parsedAddress); + return parsedAddress; + } catch (RuntimeException e) { + throw new IllegalArgumentException( + String.format("Invalid address %s (%s)", address, e.getMessage()), e); + } + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/util/AddressUtils.java b/core/src/main/java/com/datastax/oss/driver/internal/core/util/AddressUtils.java new file mode 100644 index 00000000000..8905edb9192 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/util/AddressUtils.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.util; + +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.HashSet; +import java.util.Set; + +public class AddressUtils { + + public static Set extract(String address, boolean resolve) { + int separator = address.lastIndexOf(':'); + if (separator < 0) { + throw new IllegalArgumentException("expecting format host:port"); + } + + String host = address.substring(0, separator); + String portString = address.substring(separator + 1); + int port; + try { + port = Integer.parseInt(portString); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("expecting port to be a number, got " + portString, e); + } + if (!resolve) { + return ImmutableSet.of(InetSocketAddress.createUnresolved(host, port)); + } else { + InetAddress[] inetAddresses; + try { + inetAddresses = InetAddress.getAllByName(host); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + Set result = new HashSet<>(); + for (InetAddress inetAddress : inetAddresses) { + result.add(new InetSocketAddress(inetAddress, port)); + } + return result; + } + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index f09ffd18a10..3c6851a48ee 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1026,8 +1026,9 @@ datastax-java-driver { # the package com.datastax.oss.driver.internal.core.addresstranslation. # # The driver provides the following implementations out of the box: - # - PassThroughAddressTranslator: returns all addresses unchanged + # - PassThroughAddressTranslator: returns all addresses unchanged. # - FixedHostNameAddressTranslator: translates all addresses to a specific hostname. + # - SubnetAddressTranslator: translates addresses to hostname based on the subnet match. # - Ec2MultiRegionAddressTranslator: suitable for an Amazon multi-region EC2 deployment where # clients are also deployed in EC2. It optimizes network costs by favoring private IPs over # public ones whenever possible. @@ -1035,8 +1036,23 @@ datastax-java-driver { # You can also specify a custom class that implements AddressTranslator and has a public # constructor with a DriverContext argument. class = PassThroughAddressTranslator + # # This property has to be set only in case you use FixedHostNameAddressTranslator. # advertised-hostname = mycustomhostname + # + # These properties are only applicable in case you use SubnetAddressTranslator. + # subnet-addresses { + # "100.64.0.0/15" = "cassandra.datacenter1.com:9042" + # "100.66.0.0/15" = "cassandra.datacenter2.com:9042" + # # IPv6 example: + # # "::ffff:6440:0/111" = "cassandra.datacenter1.com:9042" + # # "::ffff:6442:0/111" = "cassandra.datacenter2.com:9042" + # } + # Optional. When configured, addresses not matching the configured subnets are translated to this address. + # default-address = "cassandra.datacenter1.com:9042" + # Whether to resolve the addresses once on initialization (if true) or on each node (re-)connection (if false). + # If not configured, defaults to false. + # resolve-addresses = false } # Whether to resolve the addresses passed to `basic.contact-points`. diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/ContactPointsTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/ContactPointsTest.java index 9e0d8737619..72b875b8602 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/ContactPointsTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/ContactPointsTest.java @@ -121,7 +121,7 @@ public void should_ignore_malformed_host_and_port_and_warn() { ContactPoints.merge(Collections.emptySet(), ImmutableList.of("foobar"), true); assertThat(endPoints).isEmpty(); - assertLog(Level.WARN, "Ignoring invalid contact point foobar (expecting host:port)"); + assertLog(Level.WARN, "Ignoring invalid contact point foobar (expecting format host:port)"); } @Test @@ -132,7 +132,7 @@ public void should_ignore_malformed_port_and_warn() { assertThat(endPoints).isEmpty(); assertLog( Level.WARN, - "Ignoring invalid contact point 127.0.0.1:foobar (expecting a number, got foobar)"); + "Ignoring invalid contact point 127.0.0.1:foobar (expecting port to be a number, got foobar)"); } @Test diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java index c5e864b4bae..92800998056 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java @@ -17,6 +17,7 @@ */ package com.datastax.oss.driver.internal.core.addresstranslation; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -33,9 +34,7 @@ public class FixedHostNameAddressTranslatorTest { @Test public void should_translate_address() { DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class); - when(defaultProfile.getString( - FixedHostNameAddressTranslator.ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME_OPTION)) - .thenReturn("myaddress"); + when(defaultProfile.getString(ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME)).thenReturn("myaddress"); DefaultDriverContext defaultDriverContext = MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile)); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTest.java new file mode 100644 index 00000000000..bd505f5dd44 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +import java.net.InetSocketAddress; +import org.junit.Test; + +public class SubnetAddressTest { + @Test + public void should_return_return_true_on_overlapping_with_another_subnet_address() { + SubnetAddress subnetAddress1 = + new SubnetAddress("100.64.0.0/15", mock(InetSocketAddress.class)); + SubnetAddress subnetAddress2 = + new SubnetAddress("100.65.0.0/16", mock(InetSocketAddress.class)); + assertThat(subnetAddress1.isOverlapping(subnetAddress2)).isTrue(); + } + + @Test + public void should_return_return_false_on_not_overlapping_with_another_subnet_address() { + SubnetAddress subnetAddress1 = + new SubnetAddress("100.64.0.0/15", mock(InetSocketAddress.class)); + SubnetAddress subnetAddress2 = + new SubnetAddress("100.66.0.0/15", mock(InetSocketAddress.class)); + assertThat(subnetAddress1.isOverlapping(subnetAddress2)).isFalse(); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java new file mode 100644 index 00000000000..2aa6ae75bc2 --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_DEFAULT_ADDRESS; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.ADDRESS_TRANSLATOR_SUBNET_ADDRESSES; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; +import com.datastax.oss.driver.internal.core.context.MockedDriverContextFactory; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.Optional; +import org.junit.Test; + +@SuppressWarnings("resource") +public class SubnetAddressTranslatorTest { + + @Test + public void should_translate_to_correct_subnet_address_ipv4() { + Map subnetAddresses = + ImmutableMap.of( + "\"100.64.0.0/15\"", "cassandra.datacenter1.com:19042", + "100.66.0.\"0/15\"", "cassandra.datacenter2.com:19042"); + DefaultDriverContext context = context(subnetAddresses); + SubnetAddressTranslator translator = new SubnetAddressTranslator(context); + InetSocketAddress address = new InetSocketAddress("100.64.0.1", 9042); + assertThat(translator.translate(address)) + .isEqualTo(InetSocketAddress.createUnresolved("cassandra.datacenter1.com", 19042)); + } + + @Test + public void should_translate_to_correct_subnet_address_ipv6() { + Map subnetAddresses = + ImmutableMap.of( + "\"::ffff:6440:0/111\"", "cassandra.datacenter1.com:19042", + "\"::ffff:6442:0/111\"", "cassandra.datacenter2.com:19042"); + DefaultDriverContext context = context(subnetAddresses); + SubnetAddressTranslator translator = new SubnetAddressTranslator(context); + InetSocketAddress address = new InetSocketAddress("::ffff:6440:1", 9042); + assertThat(translator.translate(address)) + .isEqualTo(InetSocketAddress.createUnresolved("cassandra.datacenter1.com", 19042)); + } + + @Test + public void should_translate_to_default_address() { + DefaultDriverContext context = context(ImmutableMap.of()); + when(context + .getConfig() + .getDefaultProfile() + .getString(ADDRESS_TRANSLATOR_DEFAULT_ADDRESS, null)) + .thenReturn("cassandra.com:19042"); + SubnetAddressTranslator translator = new SubnetAddressTranslator(context); + InetSocketAddress address = new InetSocketAddress("100.68.0.1", 9042); + assertThat(translator.translate(address)) + .isEqualTo(InetSocketAddress.createUnresolved("cassandra.com", 19042)); + } + + @Test + public void should_pass_through_not_matched_address() { + DefaultDriverContext context = context(ImmutableMap.of()); + SubnetAddressTranslator translator = new SubnetAddressTranslator(context); + InetSocketAddress address = new InetSocketAddress("100.68.0.1", 9042); + assertThat(translator.translate(address)).isEqualTo(address); + } + + @Test + public void should_fail_on_intersecting_subnets_ipv4() { + Map subnetAddresses = + ImmutableMap.of( + "\"100.64.0.0/15\"", "cassandra.datacenter1.com:19042", + "100.65.0.\"0/16\"", "cassandra.datacenter2.com:19042"); + DefaultDriverContext context = context(subnetAddresses); + assertThatIllegalArgumentException() + .isThrownBy(() -> new SubnetAddressTranslator(context)) + .withMessage( + "Configured subnets are overlapping: " + + String.format( + "SubnetAddress[subnet=[100, 64, 0, 0], address=%s], ", + InetSocketAddress.createUnresolved("cassandra.datacenter1.com", 19042)) + + String.format( + "SubnetAddress[subnet=[100, 65, 0, 0], address=%s]", + InetSocketAddress.createUnresolved("cassandra.datacenter2.com", 19042))); + } + + @Test + public void should_fail_on_intersecting_subnets_ipv6() { + Map subnetAddresses = + ImmutableMap.of( + "\"::ffff:6440:0/111\"", "cassandra.datacenter1.com:19042", + "\"::ffff:6441:0/112\"", "cassandra.datacenter2.com:19042"); + DefaultDriverContext context = context(subnetAddresses); + assertThatIllegalArgumentException() + .isThrownBy(() -> new SubnetAddressTranslator(context)) + .withMessage( + "Configured subnets are overlapping: " + + String.format( + "SubnetAddress[subnet=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 64, 0, 0], address=%s], ", + InetSocketAddress.createUnresolved("cassandra.datacenter1.com", 19042)) + + String.format( + "SubnetAddress[subnet=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 65, 0, 0], address=%s]", + InetSocketAddress.createUnresolved("cassandra.datacenter2.com", 19042))); + } + + @Test + public void should_fail_on_subnet_address_without_port() { + Map subnetAddresses = + ImmutableMap.of("\"100.64.0.0/15\"", "cassandra.datacenter1.com"); + DefaultDriverContext context = context(subnetAddresses); + assertThatIllegalArgumentException() + .isThrownBy(() -> new SubnetAddressTranslator(context)) + .withMessage("Invalid address cassandra.datacenter1.com (expecting format host:port)"); + } + + @Test + public void should_fail_on_default_address_without_port() { + DefaultDriverContext context = context(ImmutableMap.of()); + when(context + .getConfig() + .getDefaultProfile() + .getString(ADDRESS_TRANSLATOR_DEFAULT_ADDRESS, null)) + .thenReturn("cassandra.com"); + assertThatIllegalArgumentException() + .isThrownBy(() -> new SubnetAddressTranslator(context)) + .withMessage("Invalid address cassandra.com (expecting format host:port)"); + } + + private static DefaultDriverContext context(Map subnetAddresses) { + DriverExecutionProfile profile = mock(DriverExecutionProfile.class); + when(profile.getStringMap(ADDRESS_TRANSLATOR_SUBNET_ADDRESSES)).thenReturn(subnetAddresses); + return MockedDriverContextFactory.defaultDriverContext(Optional.of(profile)); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetTest.java new file mode 100644 index 00000000000..f8ba8929e9e --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetTest.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.addresstranslation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.net.UnknownHostException; +import org.junit.Test; + +public class SubnetTest { + @Test + public void should_parse_to_correct_ipv4_subnet() throws UnknownHostException { + Subnet subnet = Subnet.parse("100.64.0.0/15"); + assertThat(subnet.getSubnet()).containsExactly(100, 64, 0, 0); + assertThat(subnet.getNetworkMask()).containsExactly(255, 254, 0, 0); + assertThat(subnet.getUpper()).containsExactly(100, 65, 255, 255); + assertThat(subnet.getLower()).containsExactly(100, 64, 0, 0); + } + + @Test + public void should_parse_to_correct_ipv6_subnet() throws UnknownHostException { + Subnet subnet = Subnet.parse("2001:db8:85a3::8a2e:370:0/111"); + assertThat(subnet.getSubnet()) + .containsExactly(32, 1, 13, 184, 133, 163, 0, 0, 0, 0, 138, 46, 3, 112, 0, 0); + assertThat(subnet.getNetworkMask()) + .containsExactly( + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 0, 0); + assertThat(subnet.getUpper()) + .containsExactly(32, 1, 13, 184, 133, 163, 0, 0, 0, 0, 138, 46, 3, 113, 255, 255); + assertThat(subnet.getLower()) + .containsExactly(32, 1, 13, 184, 133, 163, 0, 0, 0, 0, 138, 46, 3, 112, 0, 0); + } + + @Test + public void should_parse_to_correct_ipv6_subnet_ipv4_convertible() throws UnknownHostException { + Subnet subnet = Subnet.parse("::ffff:6440:0/111"); + assertThat(subnet.getSubnet()) + .containsExactly(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 64, 0, 0); + assertThat(subnet.getNetworkMask()) + .containsExactly( + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 0, 0); + assertThat(subnet.getUpper()) + .containsExactly(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 65, 255, 255); + assertThat(subnet.getLower()) + .containsExactly(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 64, 0, 0); + } + + @Test + public void should_fail_on_invalid_cidr_format() { + assertThatIllegalArgumentException() + .isThrownBy(() -> Subnet.parse("invalid")) + .withMessage("Invalid subnet: invalid"); + } + + @Test + public void should_parse_bounding_prefix_lengths_correctly() { + assertThatNoException().isThrownBy(() -> Subnet.parse("0.0.0.0/0")); + assertThatNoException().isThrownBy(() -> Subnet.parse("100.64.0.0/32")); + } + + @Test + public void should_fail_on_invalid_prefix_length() { + assertThatIllegalArgumentException() + .isThrownBy(() -> Subnet.parse("100.64.0.0/-1")) + .withMessage("Prefix length -1 must be within [0; 32]"); + assertThatIllegalArgumentException() + .isThrownBy(() -> Subnet.parse("100.64.0.0/33")) + .withMessage("Prefix length 33 must be within [0; 32]"); + } + + @Test + public void should_fail_on_not_prefix_block_subnet_ipv4() { + assertThatIllegalArgumentException() + .isThrownBy(() -> Subnet.parse("100.65.0.0/15")) + .withMessage("Subnet 100.65.0.0/15 must be represented as a network prefix block"); + } + + @Test + public void should_fail_on_not_prefix_block_subnet_ipv6() { + assertThatIllegalArgumentException() + .isThrownBy(() -> Subnet.parse("::ffff:6441:0/111")) + .withMessage("Subnet ::ffff:6441:0/111 must be represented as a network prefix block"); + } + + @Test + public void should_return_true_on_containing_address() throws UnknownHostException { + Subnet subnet = Subnet.parse("100.64.0.0/15"); + assertThat(subnet.contains(new byte[] {100, 64, 0, 0})).isTrue(); + assertThat(subnet.contains(new byte[] {100, 65, (byte) 255, (byte) 255})).isTrue(); + assertThat(subnet.contains(new byte[] {100, 65, 100, 100})).isTrue(); + } + + @Test + public void should_return_false_on_not_containing_address() throws UnknownHostException { + Subnet subnet = Subnet.parse("100.64.0.0/15"); + assertThat(subnet.contains(new byte[] {100, 63, (byte) 255, (byte) 255})).isFalse(); + assertThat(subnet.contains(new byte[] {100, 66, 0, 0})).isFalse(); + // IPv6 cannot be contained by IPv4 subnet. + assertThat(subnet.contains(new byte[16])).isFalse(); + } +} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/MockOptions.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/MockOptions.java index 25c1e8b26fd..cee57abbfdf 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/MockOptions.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/MockOptions.java @@ -24,6 +24,7 @@ public enum MockOptions implements DriverOption { INT1("int1"), INT2("int2"), AUTH_PROVIDER("auth_provider"), + SUBNET_ADDRESSES("subnet_addresses"), ; private final String path; diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java index 16ccb73da9f..4a78c3ccb03 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/config/typesafe/TypesafeDriverConfigTest.java @@ -101,7 +101,6 @@ public void should_fetch_string_map() { parse( "int1 = 42 \n auth_provider { auth_thing_one= one \n auth_thing_two = two \n auth_thing_three = three}"); DriverExecutionProfile base = config.getDefaultProfile(); - base.getStringMap(MockOptions.AUTH_PROVIDER); Map map = base.getStringMap(MockOptions.AUTH_PROVIDER); assertThat(map.entrySet().size()).isEqualTo(3); assertThat(map.get("auth_thing_one")).isEqualTo("one"); @@ -109,6 +108,19 @@ public void should_fetch_string_map() { assertThat(map.get("auth_thing_three")).isEqualTo("three"); } + @Test + public void should_fetch_string_map_with_forward_slash_in_keys() { + TypesafeDriverConfig config = + parse( + "subnet_addresses { 100.64.0.0/15 = \"cassandra.datacenter1.com:9042\" \n \"100.66.0.0/15\" = \"cassandra.datacenter2.com\" \n \"::ffff:6440:0/111\" = \"cassandra.datacenter3.com:19042\" }"); + DriverExecutionProfile base = config.getDefaultProfile(); + Map map = base.getStringMap(MockOptions.SUBNET_ADDRESSES); + assertThat(map.entrySet().size()).isEqualTo(3); + assertThat(map.get("100.64.0.\"0/15\"")).isEqualTo("cassandra.datacenter1.com:9042"); + assertThat(map.get("\"100.66.0.0/15\"")).isEqualTo("cassandra.datacenter2.com"); + assertThat(map.get("\"::ffff:6440:0/111\"")).isEqualTo("cassandra.datacenter3.com:19042"); + } + @Test public void should_create_derived_profile_with_string_map() { TypesafeDriverConfig config = parse("int1 = 42"); diff --git a/manual/core/address_resolution/README.md b/manual/core/address_resolution/README.md index 84efb4a796c..5b2536feb18 100644 --- a/manual/core/address_resolution/README.md +++ b/manual/core/address_resolution/README.md @@ -118,6 +118,55 @@ datastax-java-driver.advanced.address-translator.class = com.mycompany.MyAddress Note: the contact points provided while creating the `CqlSession` are not translated, only addresses retrieved from or sent by Cassandra nodes are. +### Fixed proxy hostname + +If your client applications access Cassandra through some kind of proxy (eg. with AWS PrivateLink when all Cassandra +nodes are exposed via one hostname pointing to AWS Endpoint), you can configure driver with +`FixedHostNameAddressTranslator` to always translate all node addresses to that same proxy hostname, no matter what IP +address a node has but still using its native transport port. + +To use it, specify the following in the [configuration](../configuration): + +``` +datastax-java-driver.advanced.address-translator.class = FixedHostNameAddressTranslator +advertised-hostname = proxyhostname +``` + +### Fixed proxy hostname per subnet + +When running Cassandra in a private network and accessing it from outside of that private network via some kind of +proxy, we have an option to use `FixedHostNameAddressTranslator`. But for multi-datacenter Cassandra deployments, we +want to have more control over routing queries to a specific datacenter (eg. for optimizing latencies), which requires +setting up a separate proxy per datacenter. + +Normally, each Cassandra datacenter nodes are deployed to a different subnet to support internode communications in the +cluster and avoid IP address collisions. So when Cassandra broadcasts its nodes IP addresses, we can determine which +datacenter that node belongs to by checking its IP address against the given datacenter subnet. + +For such scenarios you can use `SubnetAddressTranslator` to translate node IPs to the datacenter proxy address +associated with it. + +To use it, specify the following in the [configuration](../configuration): +``` +datastax-java-driver.advanced.address-translator { + class = SubnetAddressTranslator + subnet-addresses { + "100.64.0.0/15" = "cassandra.datacenter1.com:9042" + "100.66.0.0/15" = "cassandra.datacenter2.com:9042" + # IPv6 example: + # "::ffff:6440:0/111" = "cassandra.datacenter1.com:9042" + # "::ffff:6442:0/111" = "cassandra.datacenter2.com:9042" + } + # Optional. When configured, addresses not matching the configured subnets are translated to this address. + default-address = "cassandra.datacenter1.com:9042" + # Whether to resolve the addresses once on initialization (if true) or on each node (re-)connection (if false). + # If not configured, defaults to false. + resolve-addresses = false +} +``` + +Such setup is common for running Cassandra on Kubernetes with [k8ssandra](https://docs.k8ssandra.io/). + ### EC2 multi-region If you deploy both Cassandra and client applications on Amazon EC2, and your cluster spans multiple regions, you'll have From 29d3531202895fb9866bdd72720202c78a7eaa9b Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Tue, 20 May 2025 19:06:14 -0400 Subject: [PATCH 375/395] Fix revapi surious complaints about optional dependencies patch by Abe Ratnofsky; reviewed by Bret McGuire for CASSJAVA-102 --- Jenkinsfile-datastax | 2 +- core/revapi.json | 25 +++++++++++++++++++-- mapper-runtime/revapi.json | 6 ++--- pom.xml | 45 ++++++++++++++++++++++++-------------- query-builder/revapi.json | 9 ++++---- test-infra/revapi.json | 4 +--- 6 files changed, 61 insertions(+), 30 deletions(-) diff --git a/Jenkinsfile-datastax b/Jenkinsfile-datastax index af1aab6e0f4..73b977bdf9f 100644 --- a/Jenkinsfile-datastax +++ b/Jenkinsfile-datastax @@ -27,7 +27,7 @@ def initializeEnvironment() { env.GITHUB_BRANCH_URL = "${GITHUB_PROJECT_URL}/tree/${env.BRANCH_NAME}" env.GITHUB_COMMIT_URL = "${GITHUB_PROJECT_URL}/commit/${env.GIT_COMMIT}" - env.MAVEN_HOME = "${env.HOME}/.mvn/apache-maven-3.6.3" + env.MAVEN_HOME = "${env.HOME}/.mvn/apache-maven-3.8.8" env.PATH = "${env.MAVEN_HOME}/bin:${env.PATH}" /* diff --git a/core/revapi.json b/core/revapi.json index 5aa46a3ccad..f39c7d4a7c0 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -1,5 +1,3 @@ -// Configures Revapi (https://revapi.org/getting-started.html) to check API compatibility between -// successive driver versions. { "revapi": { "java": { @@ -7386,6 +7384,29 @@ "old": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(java.lang.Class)", "new": "method com.datastax.oss.driver.api.core.type.reflect.GenericType> com.datastax.oss.driver.api.core.type.reflect.GenericType::vectorOf(java.lang.Class)", "justification": "JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)" + }, + { + "code": "java.class.nonPublicPartOfAPI", + "old": "class com.datastax.oss.driver.internal.core.config.typesafe.TypesafeDriverExecutionProfile.Base", + "justification": "CASSJAVA-102: Fix spurious complaints about optional dependencies" + }, + { + "code": "java.class.nonPublicPartOfAPI", + "old": "class com.fasterxml.jackson.databind.type.TypeParser.MyTokenizer", + "justification": "CASSJAVA-102: Fix spurious complaints about optional dependencies" + }, + { + "code": "java.class.nonPublicPartOfAPI", + "old": "class org.apache.tinkerpop.shaded.jackson.databind.type.TypeParser.MyTokenizer", + "justification": "CASSJAVA-102: Fix spurious complaints about optional dependencies" + }, + { + "code": "java.class.externalClassExposedInAPI", + "justification": "CASSJAVA-102: Migrate revapi config into dedicated config files, ported from pom.xml" + }, + { + "code": "java.method.varargOverloadsOnlyDifferInVarargParameter", + "justification": "CASSJAVA-102: Migrate revapi config into dedicated config files, ported from pom.xml" } ] } diff --git a/mapper-runtime/revapi.json b/mapper-runtime/revapi.json index 18d26a7f7e9..3dc2ea21671 100644 --- a/mapper-runtime/revapi.json +++ b/mapper-runtime/revapi.json @@ -1,5 +1,3 @@ -// Configures Revapi (https://revapi.org/getting-started.html) to check API compatibility between -// successive driver versions. { "revapi": { "java": { @@ -11,7 +9,7 @@ "com\\.datastax\\.(oss|dse)\\.driver\\.internal(\\..+)?", "com\\.datastax\\.oss\\.driver\\.shaded(\\..+)?", "com\\.datastax\\.oss\\.simulacron(\\..+)?", - // Don't re-check sibling modules that this module depends on + "// Don't re-check sibling modules that this module depends on", "com\\.datastax\\.(oss|dse)\\.driver\\.api\\.core(\\..+)?", "com\\.datastax\\.(oss|dse)\\.driver\\.api\\.querybuilder(\\..+)?" ] @@ -22,7 +20,7 @@ { "regex": true, "code": "java.annotation.attributeValueChanged", - "old": "@interface com\.datastax\.oss\.driver\.api\.mapper\.annotations\..*", + "old": "@interface com\\.datastax\\.oss\\.driver\\.api\\.mapper\\.annotations\\..*", "annotationType": "java.lang.annotation.Retention", "attribute": "value", "oldValue": "java.lang.annotation.RetentionPolicy.CLASS", diff --git a/pom.xml b/pom.xml index e5cfb58f94d..2cfeb65e757 100644 --- a/pom.xml +++ b/pom.xml @@ -561,28 +561,23 @@ org.revapi revapi-maven-plugin - 0.10.5 + 0.15.1 false \d+\.\d+\.\d+ - - - - - java.class.externalClassExposedInAPI - - - ${project.groupId}:${project.artifactId}:RELEASE + + revapi.json + org.revapi revapi-java - 0.22.1 + 0.28.4 @@ -596,9 +591,33 @@ flatten-maven-plugin 1.2.1 + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + maven-enforcer-plugin + + + enforce-maven + + enforce + + + + + + [3.8.1,) + + + + + + maven-compiler-plugin @@ -901,12 +920,6 @@ limitations under the License.]]> check - - - - revapi.json - - diff --git a/query-builder/revapi.json b/query-builder/revapi.json index c4d8aa27212..ed97379332c 100644 --- a/query-builder/revapi.json +++ b/query-builder/revapi.json @@ -1,5 +1,3 @@ -// Configures Revapi (https://revapi.org/getting-started.html) to check API compatibility between -// successive driver versions. { "revapi": { "java": { @@ -11,7 +9,7 @@ "com\\.datastax\\.(oss|dse)\\.driver\\.internal(\\..+)?", "com\\.datastax\\.oss\\.driver\\.shaded(\\..+)?", "org\\.assertj(\\..+)?", - // Don't re-check sibling modules that this module depends on + "// Don't re-check sibling modules that this module depends on", "com\\.datastax\\.(oss|dse)\\.driver\\.api\\.core(\\..+)?" ] } @@ -2782,8 +2780,11 @@ "code": "java.method.addedToInterface", "new": "method com.datastax.oss.driver.api.querybuilder.select.Select com.datastax.oss.driver.api.querybuilder.select.Select::orderByAnnOf(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.data.CqlVector)", "justification": "JAVA-3118: Add support for vector data type in Schema Builder, QueryBuilder" + }, + { + "code": "java.method.varargOverloadsOnlyDifferInVarargParameter", + "justification": "CASSJAVA-102: Suppress newly-supported varargs check" } ] } } - diff --git a/test-infra/revapi.json b/test-infra/revapi.json index c75a98cb4af..293d9f4d142 100644 --- a/test-infra/revapi.json +++ b/test-infra/revapi.json @@ -1,5 +1,3 @@ -// Configures Revapi (https://revapi.org/getting-started.html) to check API compatibility between -// successive driver versions. { "revapi": { "java": { @@ -12,7 +10,7 @@ "com\\.datastax\\.oss\\.driver\\.shaded(\\..+)?", "com\\.datastax\\.oss\\.simulacron(\\..+)?", "org\\.assertj(\\..+)?", - // Don't re-check sibling modules that this module depends on + "// Don't re-check sibling modules that this module depends on", "com\\.datastax\\.(oss|dse)\\.driver\\.api\\.core(\\..+)?" ] } From f49e19b8c7e3bff6e5e4e8003484427c95bde027 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Mon, 7 Jul 2025 10:05:15 -0500 Subject: [PATCH 376/395] ninja-fix: updating OS label in Jenkinsfile after upgrade to Focal for runner --- Jenkinsfile-datastax | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile-datastax b/Jenkinsfile-datastax index 73b977bdf9f..602f33101ca 100644 --- a/Jenkinsfile-datastax +++ b/Jenkinsfile-datastax @@ -402,7 +402,7 @@ pipeline { } environment { - OS_VERSION = 'ubuntu/bionic64/java-driver' + OS_VERSION = 'ubuntu/focal64/java-driver' JABBA_SHELL = '/usr/lib/jabba/jabba.sh' CCM_ENVIRONMENT_SHELL = '/usr/local/bin/ccm_environment.sh' SERIAL_ITS_ARGUMENT = "-DskipSerialITs=${params.SKIP_SERIAL_ITS}" From 17ebe6092e2877d8c524e07489c4c3d005cfeea5 Mon Sep 17 00:00:00 2001 From: janehe Date: Mon, 14 Jul 2025 15:09:25 -0700 Subject: [PATCH 377/395] ninja-fix: openjdk@1.17.0 instead of openjdk@17 for ASF CI patch by Jane He; reviewed by Bret McGuire and Alexandre Dutra --- Jenkinsfile-asf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile-asf b/Jenkinsfile-asf index 24800ba9051..4b5041903c1 100644 --- a/Jenkinsfile-asf +++ b/Jenkinsfile-asf @@ -35,7 +35,7 @@ pipeline { axes { axis { name 'TEST_JAVA_VERSION' - values 'openjdk@1.8.0-292', 'openjdk@1.11.0-9', 'openjdk@17', 'openjdk@1.21.0' + values 'openjdk@1.8.0-292', 'openjdk@1.11.0-9', 'openjdk@1.17.0', 'openjdk@1.21.0' } axis { name 'SERVER_VERSION' From ddd6f03d7107df03e6e96e9fe37f434e4c742a9d Mon Sep 17 00:00:00 2001 From: Jason Koch Date: Mon, 17 Mar 2025 10:17:06 -0700 Subject: [PATCH 378/395] Remove unnecessary locking in DefaultNettyOptions This value is initialized at constructor time and marked final, so it can never change. There is no need to have access to this reference synchronized. Patch by Jason Koch; reviewed by Alexandre Dutra, Andy Tolbert and Jane He --- .../oss/driver/internal/core/context/DefaultNettyOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java index c5d3b3670f0..763a71f8b12 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultNettyOptions.java @@ -200,7 +200,7 @@ public Future onClose() { } @Override - public synchronized Timer getTimer() { + public Timer getTimer() { return timer; } } From f32069bd8abfae75f451ff4f47c44c1cca8dbd1e Mon Sep 17 00:00:00 2001 From: Michael Karsten Date: Fri, 21 Mar 2025 12:09:31 -0700 Subject: [PATCH 379/395] CASSJAVA-89 fix: support schema options that changed in Cassandra 5.0 Patch by Michael Karsten; reviewed by Abe Ratnofsky and Andy Tolbert for CASSJAVA-89 --- .../querybuilder/RelationOptionsIT.java | 131 ++++++++++++++++++ .../querybuilder/schema/RelationOptions.java | 126 ++++++++++++++--- .../schema/CreateDseTableTest.java | 65 +++++++++ .../querybuilder/schema/CreateTableTest.java | 55 ++++++++ 4 files changed, 355 insertions(+), 22 deletions(-) create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/RelationOptionsIT.java diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/RelationOptionsIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/RelationOptionsIT.java new file mode 100644 index 00000000000..fc571ccf44d --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/querybuilder/RelationOptionsIT.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.querybuilder; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.driver.api.querybuilder.SchemaBuilder; +import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement; +import com.datastax.oss.driver.api.testinfra.requirement.BackendType; +import com.datastax.oss.driver.api.testinfra.session.SessionRule; +import com.datastax.oss.driver.categories.ParallelizableTests; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestName; +import org.junit.rules.TestRule; + +@Category(ParallelizableTests.class) +public class RelationOptionsIT { + + private CcmRule ccmRule = CcmRule.getInstance(); + + private SessionRule sessionRule = SessionRule.builder(ccmRule).build(); + + @Rule public TestRule chain = RuleChain.outerRule(ccmRule).around(sessionRule); + + @Rule public TestName name = new TestName(); + + @Test + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.0", + description = "CRC check chance was moved to top level table in Cassandra 3.0") + public void should_create_table_with_crc_check_chance() { + sessionRule + .session() + .execute( + SchemaBuilder.createTable(name.getMethodName()) + .withPartitionKey("id", DataTypes.INT) + .withColumn("name", DataTypes.TEXT) + .withColumn("age", DataTypes.INT) + .withCRCCheckChance(0.8) + .build()); + KeyspaceMetadata keyspaceMetadata = + sessionRule + .session() + .getMetadata() + .getKeyspace(sessionRule.keyspace()) + .orElseThrow(AssertionError::new); + String describeOutput = keyspaceMetadata.describeWithChildren(true).trim(); + + assertThat(describeOutput).contains("crc_check_chance = 0.8"); + } + + @Test + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "5.0", + description = "chunk_length_kb was renamed to chunk_length_in_kb in Cassandra 5.0") + public void should_create_table_with_chunk_length_in_kb() { + sessionRule + .session() + .execute( + SchemaBuilder.createTable(name.getMethodName()) + .withPartitionKey("id", DataTypes.INT) + .withColumn("name", DataTypes.TEXT) + .withColumn("age", DataTypes.INT) + .withLZ4Compression(4096) + .build()); + KeyspaceMetadata keyspaceMetadata = + sessionRule + .session() + .getMetadata() + .getKeyspace(sessionRule.keyspace()) + .orElseThrow(AssertionError::new); + String describeOutput = keyspaceMetadata.describeWithChildren(true).trim(); + + assertThat(describeOutput).contains("'class':'org.apache.cassandra.io.compress.LZ4Compressor'"); + assertThat(describeOutput).contains("'chunk_length_in_kb':'4096'"); + } + + @Test + @BackendRequirement( + type = BackendType.CASSANDRA, + minInclusive = "3.0", + maxExclusive = "5.0", + description = + "Deprecated compression options should still work with Cassandra >= 3.0 & < 5.0") + public void should_create_table_with_deprecated_options() { + sessionRule + .session() + .execute( + SchemaBuilder.createTable(name.getMethodName()) + .withPartitionKey("id", DataTypes.INT) + .withColumn("name", DataTypes.TEXT) + .withColumn("age", DataTypes.INT) + .withLZ4Compression(4096, 0.8) + .build()); + KeyspaceMetadata keyspaceMetadata = + sessionRule + .session() + .getMetadata() + .getKeyspace(sessionRule.keyspace()) + .orElseThrow(AssertionError::new); + String describeOutput = keyspaceMetadata.describeWithChildren(true).trim(); + + assertThat(describeOutput).contains("'class':'org.apache.cassandra.io.compress.LZ4Compressor'"); + assertThat(describeOutput).contains("'chunk_length_in_kb':'4096'"); + assertThat(describeOutput).contains("crc_check_chance = 0.8"); + } +} diff --git a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/RelationOptions.java b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/RelationOptions.java index 022562def81..49b342acb7f 100644 --- a/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/RelationOptions.java +++ b/query-builder/src/main/java/com/datastax/oss/driver/api/querybuilder/schema/RelationOptions.java @@ -58,6 +58,18 @@ default SelfT withCDC(boolean enabled) { return withOption("cdc", enabled); } + /** + * Defines the crc check chance. + * + *

    Note that using this option with a version of Apache Cassandra less than 3.0 will raise a + * syntax error. + */ + @NonNull + @CheckReturnValue + default SelfT withCRCCheckChance(double crcCheckChance) { + return withOption("crc_check_chance", crcCheckChance); + } + /** * Defines the caching criteria. * @@ -97,22 +109,32 @@ default SelfT withCompaction(@NonNull CompactionStrategy compactionStrategy) } /** - * Configures compression using the LZ4 algorithm with the given chunk length and crc check - * chance. - * - * @see #withCompression(String, int, double) + * @deprecated This method only exists for backward compatibility. Will not work with Apache + * Cassandra 5.0 or later. Use {@link #withLZ4Compression(int)} instead. */ + @Deprecated @NonNull @CheckReturnValue default SelfT withLZ4Compression(int chunkLengthKB, double crcCheckChance) { return withCompression("LZ4Compressor", chunkLengthKB, crcCheckChance); } + /** + * Configures compression using the LZ4 algorithm with the given chunk length. + * + * @see #withCompression(String, int) + */ + @NonNull + @CheckReturnValue + default SelfT withLZ4Compression(int chunkLengthKB) { + return withCompression("LZ4Compressor", chunkLengthKB); + } + /** * Configures compression using the LZ4 algorithm using the default configuration (64kb - * chunk_length, and 1.0 crc_check_chance). + * chunk_length). * - * @see #withCompression(String, int, double) + * @see #withCompression(String, int) */ @NonNull @CheckReturnValue @@ -121,22 +143,57 @@ default SelfT withLZ4Compression() { } /** - * Configures compression using the Snappy algorithm with the given chunk length and crc check - * chance. + * Configures compression using the Zstd algorithm with the given chunk length. * - * @see #withCompression(String, int, double) + * @see #withCompression(String, int) */ @NonNull @CheckReturnValue + default SelfT withZstdCompression(int chunkLengthKB) { + return withCompression("ZstdCompressor", chunkLengthKB); + } + + /** + * Configures compression using the Zstd algorithm using the default configuration (64kb + * chunk_length). + * + * @see #withCompression(String, int) + */ + @NonNull + @CheckReturnValue + default SelfT withZstdCompression() { + return withCompression("ZstdCompressor"); + } + + /** + * @deprecated This method only exists for backward compatibility. Will not work with Apache + * Cassandra 5.0 or later due to removal of deprecated table properties (CASSANDRA-18742). Use + * {@link #withSnappyCompression(int)} instead. + */ + @Deprecated + @NonNull + @CheckReturnValue default SelfT withSnappyCompression(int chunkLengthKB, double crcCheckChance) { return withCompression("SnappyCompressor", chunkLengthKB, crcCheckChance); } + /** + * Configures compression using the Snappy algorithm with the given chunk length. + * + * @see #withCompression(String, int) + */ + @NonNull + @CheckReturnValue + default SelfT withSnappyCompression(int chunkLengthKB) { + return withCompression("SnappyCompressor", chunkLengthKB); + } + /** * Configures compression using the Snappy algorithm using the default configuration (64kb - * chunk_length, and 1.0 crc_check_chance). + * chunk_length). * - * @see #withCompression(String, int, double) + * @see #withCompression(String, int) */ @NonNull @CheckReturnValue @@ -145,22 +202,34 @@ default SelfT withSnappyCompression() { } /** - * Configures compression using the Deflate algorithm with the given chunk length and crc check - * chance. - * - * @see #withCompression(String, int, double) + * @deprecated This method only exists for backward compatibility. Will not work with Apache + * Cassandra 5.0 or later due to removal of deprecated table properties (CASSANDRA-18742). Use + * {@link #withDeflateCompression(int)} instead. */ + @Deprecated @NonNull @CheckReturnValue default SelfT withDeflateCompression(int chunkLengthKB, double crcCheckChance) { return withCompression("DeflateCompressor", chunkLengthKB, crcCheckChance); } + /** + * Configures compression using the Deflate algorithm with the given chunk length. + * + * @see #withCompression(String, int) + */ + @NonNull + @CheckReturnValue + default SelfT withDeflateCompression(int chunkLengthKB) { + return withCompression("DeflateCompressor", chunkLengthKB); + } + /** * Configures compression using the Deflate algorithm using the default configuration (64kb - * chunk_length, and 1.0 crc_check_chance). + * chunk_length). * - * @see #withCompression(String, int, double) + * @see #withCompression(String, int) */ @NonNull @CheckReturnValue @@ -170,13 +239,13 @@ default SelfT withDeflateCompression() { /** * Configures compression using the given algorithm using the default configuration (64kb - * chunk_length, and 1.0 crc_check_chance). + * chunk_length). * *

    Unless specifying a custom compression algorithm implementation, it is recommended to use * {@link #withLZ4Compression()}, {@link #withSnappyCompression()}, or {@link * #withDeflateCompression()}. * - * @see #withCompression(String, int, double) + * @see #withCompression(String, int) */ @NonNull @CheckReturnValue @@ -185,7 +254,7 @@ default SelfT withCompression(@NonNull String compressionAlgorithmName) { } /** - * Configures compression using the given algorithm, chunk length and crc check chance. + * Configures compression using the given algorithm, chunk length. * *

    Unless specifying a custom compression algorithm implementation, it is recommended to use * {@link #withLZ4Compression()}, {@link #withSnappyCompression()}, or {@link @@ -193,11 +262,24 @@ default SelfT withCompression(@NonNull String compressionAlgorithmName) { * * @param compressionAlgorithmName The class name of the compression algorithm. * @param chunkLengthKB The chunk length in KB of compression blocks. Defaults to 64. - * @param crcCheckChance The probability (0.0 to 1.0) that checksum will be checked on each read. - * Defaults to 1.0. */ @NonNull @CheckReturnValue + default SelfT withCompression(@NonNull String compressionAlgorithmName, int chunkLengthKB) { + return withOption( + "compression", + ImmutableMap.of("class", compressionAlgorithmName, "chunk_length_in_kb", chunkLengthKB)); + } + + /** + * @deprecated This method only exists for backward compatibility. Will not work with Apache + * Cassandra 5.0 or later due to removal of deprecated table properties (CASSANDRA-18742). Use + * {@link #withCompression(String, int)} instead. + */ + @NonNull + @CheckReturnValue + @Deprecated default SelfT withCompression( @NonNull String compressionAlgorithmName, int chunkLengthKB, double crcCheckChance) { return withOption( diff --git a/query-builder/src/test/java/com/datastax/dse/driver/api/querybuilder/schema/CreateDseTableTest.java b/query-builder/src/test/java/com/datastax/dse/driver/api/querybuilder/schema/CreateDseTableTest.java index 7fec9674628..d8ee1c4e380 100644 --- a/query-builder/src/test/java/com/datastax/dse/driver/api/querybuilder/schema/CreateDseTableTest.java +++ b/query-builder/src/test/java/com/datastax/dse/driver/api/querybuilder/schema/CreateDseTableTest.java @@ -195,6 +195,17 @@ public void should_generate_create_table_lz4_compression() { @Test public void should_generate_create_table_lz4_compression_options() { + assertThat( + createDseTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withLZ4Compression(1024)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'LZ4Compressor','chunk_length_in_kb':1024}"); + } + + @Test + public void should_generate_create_table_lz4_compression_options_crc() { assertThat( createDseTable("bar") .withPartitionKey("k", DataTypes.INT) @@ -204,6 +215,28 @@ public void should_generate_create_table_lz4_compression_options() { "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'LZ4Compressor','chunk_length_kb':1024,'crc_check_chance':0.5}"); } + @Test + public void should_generate_create_table_zstd_compression() { + assertThat( + createDseTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withZstdCompression()) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'ZstdCompressor'}"); + } + + @Test + public void should_generate_create_table_zstd_compression_options() { + assertThat( + createDseTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withZstdCompression(1024)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'ZstdCompressor','chunk_length_in_kb':1024}"); + } + @Test public void should_generate_create_table_snappy_compression() { assertThat( @@ -217,6 +250,17 @@ public void should_generate_create_table_snappy_compression() { @Test public void should_generate_create_table_snappy_compression_options() { + assertThat( + createDseTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withSnappyCompression(2048)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'SnappyCompressor','chunk_length_in_kb':2048}"); + } + + @Test + public void should_generate_create_table_snappy_compression_options_crc() { assertThat( createDseTable("bar") .withPartitionKey("k", DataTypes.INT) @@ -239,6 +283,17 @@ public void should_generate_create_table_deflate_compression() { @Test public void should_generate_create_table_deflate_compression_options() { + assertThat( + createDseTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withDeflateCompression(4096)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'DeflateCompressor','chunk_length_in_kb':4096}"); + } + + @Test + public void should_generate_create_table_deflate_compression_options_crc() { assertThat( createDseTable("bar") .withPartitionKey("k", DataTypes.INT) @@ -389,4 +444,14 @@ public void should_generate_create_table_with_named_edge() { + "FROM person(contributor) " + "TO soft((company_name,software_name),software_version)"); } + + @Test + public void should_generate_create_table_crc_check_chance() { + assertThat( + createDseTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withCRCCheckChance(0.8)) + .hasCql("CREATE TABLE bar (k int PRIMARY KEY,v text) WITH crc_check_chance=0.8"); + } } diff --git a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java index 15cd12c75eb..31efc278472 100644 --- a/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java +++ b/query-builder/src/test/java/com/datastax/oss/driver/api/querybuilder/schema/CreateTableTest.java @@ -199,6 +199,17 @@ public void should_generate_create_table_lz4_compression() { @Test public void should_generate_create_table_lz4_compression_options() { + assertThat( + createTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withLZ4Compression(1024)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'LZ4Compressor','chunk_length_in_kb':1024}"); + } + + @Test + public void should_generate_create_table_lz4_compression_options_crc() { assertThat( createTable("bar") .withPartitionKey("k", DataTypes.INT) @@ -208,6 +219,28 @@ public void should_generate_create_table_lz4_compression_options() { "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'LZ4Compressor','chunk_length_kb':1024,'crc_check_chance':0.5}"); } + @Test + public void should_generate_create_table_zstd_compression() { + assertThat( + createTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withZstdCompression()) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'ZstdCompressor'}"); + } + + @Test + public void should_generate_create_table_zstd_compression_options() { + assertThat( + createTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withZstdCompression(1024)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'ZstdCompressor','chunk_length_in_kb':1024}"); + } + @Test public void should_generate_create_table_snappy_compression() { assertThat( @@ -221,6 +254,17 @@ public void should_generate_create_table_snappy_compression() { @Test public void should_generate_create_table_snappy_compression_options() { + assertThat( + createTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withSnappyCompression(2048)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'SnappyCompressor','chunk_length_in_kb':2048}"); + } + + @Test + public void should_generate_create_table_snappy_compression_options_crc() { assertThat( createTable("bar") .withPartitionKey("k", DataTypes.INT) @@ -243,6 +287,17 @@ public void should_generate_create_table_deflate_compression() { @Test public void should_generate_create_table_deflate_compression_options() { + assertThat( + createTable("bar") + .withPartitionKey("k", DataTypes.INT) + .withColumn("v", DataTypes.TEXT) + .withDeflateCompression(4096)) + .hasCql( + "CREATE TABLE bar (k int PRIMARY KEY,v text) WITH compression={'class':'DeflateCompressor','chunk_length_in_kb':4096}"); + } + + @Test + public void should_generate_create_table_deflate_compression_options_crc() { assertThat( createTable("bar") .withPartitionKey("k", DataTypes.INT) From 7e21eb20283f3781a0a748741b768d0adf0fc85b Mon Sep 17 00:00:00 2001 From: Jason Koch Date: Mon, 3 Feb 2025 13:46:32 -0800 Subject: [PATCH 380/395] Eliminate lock in ConcurrencyLimitingRequestThrottler Following from 6d3ba47 this changes the throttler to a complete lock-free implementation. Update the related comments and README now that it is lock-free. Patch by Jason Koch; reviewed by Alexandre Dutra and Andy Tolbert --- .../session/throttling/RequestThrottler.java | 8 +- .../ConcurrencyLimitingRequestThrottler.java | 180 ++++++++---------- manual/core/non_blocking/README.md | 14 +- 3 files changed, 90 insertions(+), 112 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java index 7e2b41ebbdb..73d347d533e 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.java @@ -23,10 +23,10 @@ /** * Limits the number of concurrent requests executed by the driver. * - *

    Usage in non-blocking applications: beware that all built-in implementations of this interface - * use locks for internal coordination, and do not qualify as lock-free, with the obvious exception - * of {@code PassThroughRequestThrottler}. If your application enforces strict lock-freedom, then - * request throttling should not be enabled. + *

    Usage in non-blocking applications: beware that some implementations of this interface use + * locks for internal coordination, and do not qualify as lock-free. If your application enforces + * strict lock-freedom, then you should use the {@code PassThroughRequestThrottler} or the {@code + * ConcurrencyLimitingRequestThrottler}. */ public interface RequestThrottler extends Closeable { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java index ffe0ffe9650..8146c5b113a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/session/throttling/ConcurrencyLimitingRequestThrottler.java @@ -26,10 +26,9 @@ import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.util.ArrayDeque; import java.util.Deque; -import java.util.concurrent.locks.ReentrantLock; -import net.jcip.annotations.GuardedBy; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicInteger; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,17 +60,12 @@ public class ConcurrencyLimitingRequestThrottler implements RequestThrottler { private final String logPrefix; private final int maxConcurrentRequests; private final int maxQueueSize; - - private final ReentrantLock lock = new ReentrantLock(); - - @GuardedBy("lock") - private int concurrentRequests; - - @GuardedBy("lock") - private final Deque queue = new ArrayDeque<>(); - - @GuardedBy("lock") - private boolean closed; + private final AtomicInteger concurrentRequests = new AtomicInteger(0); + // CLQ is not O(1) for size(), as it forces a full iteration of the queue. So, we track + // the size of the queue explicitly. + private final Deque queue = new ConcurrentLinkedDeque<>(); + private final AtomicInteger queueSize = new AtomicInteger(0); + private volatile boolean closed = false; public ConcurrencyLimitingRequestThrottler(DriverContext context) { this.logPrefix = context.getSessionName(); @@ -88,50 +82,62 @@ public ConcurrencyLimitingRequestThrottler(DriverContext context) { @Override public void register(@NonNull Throttled request) { - boolean notifyReadyRequired = false; + if (closed) { + LOG.trace("[{}] Rejecting request after shutdown", logPrefix); + fail(request, "The session is shutting down"); + return; + } - lock.lock(); - try { - if (closed) { - LOG.trace("[{}] Rejecting request after shutdown", logPrefix); - fail(request, "The session is shutting down"); - } else if (queue.isEmpty() && concurrentRequests < maxConcurrentRequests) { - // We have capacity for one more concurrent request + // Implementation note: Technically the "concurrent requests" or "queue size" + // could read transiently over the limit, but the queue itself will never grow + // beyond the limit since we always check for that condition and revert if + // over-limit. We do this instead of a CAS-loop to avoid the potential loop. + + // If no backlog exists AND we get capacity, we can execute immediately + if (queueSize.get() == 0) { + // Take a claim first, and then check if we are OK to proceed + int newConcurrent = concurrentRequests.incrementAndGet(); + if (newConcurrent <= maxConcurrentRequests) { LOG.trace("[{}] Starting newly registered request", logPrefix); - concurrentRequests += 1; - notifyReadyRequired = true; - } else if (queue.size() < maxQueueSize) { - LOG.trace("[{}] Enqueuing request", logPrefix); - queue.add(request); + request.onThrottleReady(false); + return; } else { - LOG.trace("[{}] Rejecting request because of full queue", logPrefix); - fail( - request, - String.format( - "The session has reached its maximum capacity " - + "(concurrent requests: %d, queue size: %d)", - maxConcurrentRequests, maxQueueSize)); + // We exceeded the limit, decrement the count and fall through to the queuing logic + concurrentRequests.decrementAndGet(); } - } finally { - lock.unlock(); } - // no need to hold the lock while allowing the task to progress - if (notifyReadyRequired) { - request.onThrottleReady(false); + // If we have a backlog, or we failed to claim capacity, try to enqueue + int newQueueSize = queueSize.incrementAndGet(); + if (newQueueSize <= maxQueueSize) { + LOG.trace("[{}] Enqueuing request", logPrefix); + queue.offer(request); + + // Double-check that we were still supposed to be enqueued; it is possible + // that the session was closed while we were enqueuing, it's also possible + // that it is right now removing the request, so we need to check both + if (closed) { + if (queue.remove(request)) { + queueSize.decrementAndGet(); + LOG.trace("[{}] Rejecting late request after shutdown", logPrefix); + fail(request, "The session is shutting down"); + } + } + } else { + LOG.trace("[{}] Rejecting request because of full queue", logPrefix); + queueSize.decrementAndGet(); + fail( + request, + String.format( + "The session has reached its maximum capacity " + + "(concurrent requests: %d, queue size: %d)", + maxConcurrentRequests, maxQueueSize)); } } @Override public void signalSuccess(@NonNull Throttled request) { - Throttled nextRequest = null; - lock.lock(); - try { - nextRequest = onRequestDoneAndDequeNext(); - } finally { - lock.unlock(); - } - + Throttled nextRequest = onRequestDoneAndDequeNext(); if (nextRequest != null) { nextRequest.onThrottleReady(true); } @@ -145,17 +151,13 @@ public void signalError(@NonNull Throttled request, @NonNull Throwable error) { @Override public void signalTimeout(@NonNull Throttled request) { Throttled nextRequest = null; - lock.lock(); - try { - if (!closed) { - if (queue.remove(request)) { // The request timed out before it was active - LOG.trace("[{}] Removing timed out request from the queue", logPrefix); - } else { - nextRequest = onRequestDoneAndDequeNext(); - } + if (!closed) { + if (queue.remove(request)) { // The request timed out before it was active + queueSize.decrementAndGet(); + LOG.trace("[{}] Removing timed out request from the queue", logPrefix); + } else { + nextRequest = onRequestDoneAndDequeNext(); } - } finally { - lock.unlock(); } if (nextRequest != null) { @@ -166,17 +168,13 @@ public void signalTimeout(@NonNull Throttled request) { @Override public void signalCancel(@NonNull Throttled request) { Throttled nextRequest = null; - lock.lock(); - try { - if (!closed) { - if (queue.remove(request)) { // The request has been cancelled before it was active - LOG.trace("[{}] Removing cancelled request from the queue", logPrefix); - } else { - nextRequest = onRequestDoneAndDequeNext(); - } + if (!closed) { + if (queue.remove(request)) { // The request has been cancelled before it was active + queueSize.decrementAndGet(); + LOG.trace("[{}] Removing cancelled request from the queue", logPrefix); + } else { + nextRequest = onRequestDoneAndDequeNext(); } - } finally { - lock.unlock(); } if (nextRequest != null) { @@ -184,17 +182,16 @@ public void signalCancel(@NonNull Throttled request) { } } - @SuppressWarnings("GuardedBy") // this method is only called with the lock held @Nullable private Throttled onRequestDoneAndDequeNext() { - assert lock.isHeldByCurrentThread(); if (!closed) { - if (queue.isEmpty()) { - concurrentRequests -= 1; + Throttled nextRequest = queue.poll(); + if (nextRequest == null) { + concurrentRequests.decrementAndGet(); } else { + queueSize.decrementAndGet(); LOG.trace("[{}] Starting dequeued request", logPrefix); - // don't touch concurrentRequests since we finished one but started another - return queue.poll(); + return nextRequest; } } @@ -204,45 +201,28 @@ private Throttled onRequestDoneAndDequeNext() { @Override public void close() { - lock.lock(); - try { - closed = true; - LOG.debug("[{}] Rejecting {} queued requests after shutdown", logPrefix, queue.size()); - for (Throttled request : queue) { - fail(request, "The session is shutting down"); - } - } finally { - lock.unlock(); + closed = true; + + LOG.debug("[{}] Rejecting {} queued requests after shutdown", logPrefix, queueSize.get()); + Throttled request; + while ((request = queue.poll()) != null) { + queueSize.decrementAndGet(); + fail(request, "The session is shutting down"); } } public int getQueueSize() { - lock.lock(); - try { - return queue.size(); - } finally { - lock.unlock(); - } + return queueSize.get(); } @VisibleForTesting int getConcurrentRequests() { - lock.lock(); - try { - return concurrentRequests; - } finally { - lock.unlock(); - } + return concurrentRequests.get(); } @VisibleForTesting Deque getQueue() { - lock.lock(); - try { - return queue; - } finally { - lock.unlock(); - } + return queue; } private static void fail(Throttled request, String message) { diff --git a/manual/core/non_blocking/README.md b/manual/core/non_blocking/README.md index 7abe9d856a3..f320ffd13d2 100644 --- a/manual/core/non_blocking/README.md +++ b/manual/core/non_blocking/README.md @@ -152,15 +152,13 @@ should not be used if strict lock-freedom is enforced. [`SafeInitNodeStateListener`]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/metadata/SafeInitNodeStateListener.html -The same is valid for both built-in [request throttlers]: +The `RateLimitingRequestThrottler` is currently blocking. The `ConcurrencyLimitingRequestThrottler` +is lock-free. -* `ConcurrencyLimitingRequestThrottler` -* `RateLimitingRequestThrottler` - -See the section about [throttling](../throttling) for details about these components. Again, they -use locks internally, and depending on how many requests are being executed in parallel, the thread -contention on these locks can be high: in short, if your application enforces strict lock-freedom, -then these components should not be used. +See the section about [throttling](../throttling) for details about these components. Depending on +how many requests are being executed in parallel, the thread contention on these locks can be high: +in short, if your application enforces strict lock-freedom, then you should not use the +`RateLimitingRequestThrottler`. [request throttlers]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/throttling/RequestThrottler.html From 69eebb939c71dbb709099f7bf04b1a8b7e17012f Mon Sep 17 00:00:00 2001 From: Ivan Sopov Date: Mon, 28 Jul 2025 11:28:59 +0300 Subject: [PATCH 381/395] Change groupId in README patch by Ivan Sopov; reviewed by Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/2049 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6e1cc337d8..0f6c2bb5a6f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ and Cassandra Query Language (CQL) v3. ## Getting the driver -The driver artifacts are published in Maven central, under the group id [com.datastax.oss]; there +The driver artifacts are published in Maven central, under the group id [org.apache.cassandra]; there are multiple modules, all prefixed with `java-driver-`. ```xml @@ -48,7 +48,7 @@ dependency if you plan to use it. Refer to each module's manual for more details ([core](manual/core/), [query builder](manual/query_builder/), [mapper](manual/mapper)). -[com.datastax.oss]: http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.datastax.oss%22 +[org.apache.cassandra]: http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.cassandra%22 ## Compatibility From 05e6717253d1c6ae0c5a9ce20fcf5ab448d32ec6 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Fri, 12 Jul 2024 09:37:06 +0800 Subject: [PATCH 382/395] manual: correct the codeblock directive patch by Kefu Chai; reviewed by Andy Tolbert and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/1940 --- manual/mapper/daos/getentity/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/mapper/daos/getentity/README.md b/manual/mapper/daos/getentity/README.md index abb7cb076c8..de9a530b558 100644 --- a/manual/mapper/daos/getentity/README.md +++ b/manual/mapper/daos/getentity/README.md @@ -108,7 +108,7 @@ The method can return: * a single entity instance. If the argument is a result set type, the generated code will extract the first row and convert it, or return `null` if the result set is empty. - ````java + ```java @GetEntity Product asProduct(Row row); From ff2d7f26c63e7a3ed3a74906771b246949112414 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 14 Apr 2025 16:40:53 +0200 Subject: [PATCH 383/395] CASSJAVA-92: Local DC provided for nodetool clientstats patch by Lukasz Antoniak; reviewed by Bret McGuire and Abe Ratnofsky for CASSJAVA-92 --- .../loadbalancing/LoadBalancingPolicy.java | 7 + .../core/context/DefaultDriverContext.java | 14 +- .../core/context/StartupOptionsBuilder.java | 28 ++++ .../BasicLoadBalancingPolicy.java | 31 ++++- .../DefaultLoadBalancingPolicy.java | 10 ++ .../helper/OptionalLocalDcHelper.java | 31 +++-- .../FixedHostNameAddressTranslatorTest.java | 3 +- .../SubnetAddressTranslatorTest.java | 3 +- .../context/DefaultDriverContextTest.java | 2 +- .../context/MockedDriverContextFactory.java | 124 +++++++++++++++--- .../context/StartupOptionsBuilderTest.java | 45 ++++++- 11 files changed, 252 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java index d890ae6c100..de0d9db4ebd 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java @@ -24,6 +24,7 @@ import com.datastax.oss.driver.api.core.tracker.RequestTracker; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Queue; @@ -76,6 +77,12 @@ default Optional getRequestTracker() { */ void init(@NonNull Map nodes, @NonNull DistanceReporter distanceReporter); + /** Returns map containing details that impact C* node connectivity. */ + @NonNull + default Map getStartupConfiguration() { + return Collections.emptyMap(); + } + /** * Returns the coordinators to use for a new query. * diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index a24b632f640..0d7db27dfbe 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -216,8 +216,8 @@ public class DefaultDriverContext implements InternalDriverContext { new LazyReference<>("metricIdGenerator", this::buildMetricIdGenerator, cycleDetector); private final LazyReference requestThrottlerRef = new LazyReference<>("requestThrottler", this::buildRequestThrottler, cycleDetector); - private final LazyReference> startupOptionsRef = - new LazyReference<>("startupOptions", this::buildStartupOptions, cycleDetector); + private final LazyReference startupOptionsRef = + new LazyReference<>("startupOptionsFactory", this::buildStartupOptionsFactory, cycleDetector); private final LazyReference nodeStateListenerRef; private final LazyReference schemaChangeListenerRef; private final LazyReference requestTrackerRef; @@ -335,16 +335,15 @@ public DefaultDriverContext( } /** - * Builds a map of options to send in a Startup message. + * Returns builder of options to send in a Startup message. * * @see #getStartupOptions() */ - protected Map buildStartupOptions() { + protected StartupOptionsBuilder buildStartupOptionsFactory() { return new StartupOptionsBuilder(this) .withClientId(startupClientId) .withApplicationName(startupApplicationName) - .withApplicationVersion(startupApplicationVersion) - .build(); + .withApplicationVersion(startupApplicationVersion); } protected Map buildLoadBalancingPolicies() { @@ -1013,7 +1012,8 @@ public ProtocolVersion getProtocolVersion() { @NonNull @Override public Map getStartupOptions() { - return startupOptionsRef.get(); + // startup options are calculated dynamically and may vary per connection + return startupOptionsRef.get().build(); } protected RequestLogFormatter buildRequestLogFormatter() { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java index 684d6b01b9c..89a9266b3ac 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java @@ -19,24 +19,34 @@ import com.datastax.dse.driver.api.core.config.DseDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.protocol.internal.request.Startup; import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; +import com.fasterxml.jackson.databind.ObjectMapper; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Map; +import java.util.Optional; import java.util.UUID; import net.jcip.annotations.Immutable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Immutable public class StartupOptionsBuilder { public static final String DRIVER_NAME_KEY = "DRIVER_NAME"; public static final String DRIVER_VERSION_KEY = "DRIVER_VERSION"; + public static final String DRIVER_BAGGAGE = "DRIVER_BAGGAGE"; public static final String APPLICATION_NAME_KEY = "APPLICATION_NAME"; public static final String APPLICATION_VERSION_KEY = "APPLICATION_VERSION"; public static final String CLIENT_ID_KEY = "CLIENT_ID"; + private static final Logger LOG = LoggerFactory.getLogger(StartupOptionsBuilder.class); + private static final ObjectMapper mapper = new ObjectMapper(); + protected final InternalDriverContext context; private UUID clientId; private String applicationName; @@ -119,6 +129,7 @@ public Map build() { if (applicationVersion != null) { builder.put(APPLICATION_VERSION_KEY, applicationVersion); } + driverBaggage().ifPresent(s -> builder.put(DRIVER_BAGGAGE, s)); return builder.build(); } @@ -142,4 +153,21 @@ protected String getDriverName() { protected String getDriverVersion() { return Session.OSS_DRIVER_COORDINATES.getVersion().toString(); } + + private Optional driverBaggage() { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + for (Map.Entry entry : + context.getLoadBalancingPolicies().entrySet()) { + Map config = entry.getValue().getStartupConfiguration(); + if (!config.isEmpty()) { + builder.put(entry.getKey(), config); + } + } + try { + return Optional.of(mapper.writeValueAsString(builder.build())); + } catch (Exception e) { + LOG.warn("Failed to construct startup driver baggage", e); + return Optional.empty(); + } + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java index 587ef4183bd..a02a5eb3148 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java @@ -45,6 +45,7 @@ import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import com.datastax.oss.driver.shaded.guava.common.base.Predicates; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.Lists; import com.datastax.oss.driver.shaded.guava.common.collect.Sets; import edu.umd.cs.findbugs.annotations.NonNull; @@ -155,10 +156,38 @@ public BasicLoadBalancingPolicy(@NonNull DriverContext context, @NonNull String * Before initialization, this method always returns null. */ @Nullable - protected String getLocalDatacenter() { + public String getLocalDatacenter() { return localDc; } + @NonNull + @Override + public Map getStartupConfiguration() { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + if (localDc != null) { + builder.put("localDc", localDc); + } else { + // Local data center may not be discovered prior to connection pool initialization. + // In such scenario, return configured local data center name. + // Note that when using DC inferring load balancing policy, startup configuration + // may not show local DC name, because it will be discovered only once control connection + // is established and datacenter of contact points known. + Optional configuredDc = + new OptionalLocalDcHelper(context, profile, logPrefix).configuredLocalDc(); + configuredDc.ifPresent(d -> builder.put("localDc", d)); + } + if (!preferredRemoteDcs.isEmpty()) { + builder.put("preferredRemoteDcs", preferredRemoteDcs); + } + if (allowDcFailoverForLocalCl) { + builder.put("allowDcFailoverForLocalCl", allowDcFailoverForLocalCl); + } + if (maxNodesPerRemoteDc > 0) { + builder.put("maxNodesPerRemoteDc", maxNodesPerRemoteDc); + } + return ImmutableMap.of(BasicLoadBalancingPolicy.class.getSimpleName(), builder.build()); + } + /** @return The nodes currently considered as live. */ protected NodeSet getLiveNodes() { return liveNodes; diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java index 0f03cbb3643..9c31b606f18 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java @@ -34,6 +34,7 @@ import com.datastax.oss.driver.internal.core.util.collection.QueryPlan; import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.MapMaker; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -350,4 +351,13 @@ private boolean hasSufficientResponses(long now) { return this.oldest - threshold >= 0; } } + + @NonNull + @Override + public Map getStartupConfiguration() { + Map parent = super.getStartupConfiguration(); + return ImmutableMap.of( + DefaultLoadBalancingPolicy.class.getSimpleName(), + parent.get(BasicLoadBalancingPolicy.class.getSimpleName())); + } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java index d470f96c42c..c6143f3fa16 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java @@ -65,20 +65,14 @@ public OptionalLocalDcHelper( @Override @NonNull public Optional discoverLocalDc(@NonNull Map nodes) { - String localDc = context.getLocalDatacenter(profile.getName()); - if (localDc != null) { - LOG.debug("[{}] Local DC set programmatically: {}", logPrefix, localDc); - checkLocalDatacenterCompatibility(localDc, context.getMetadataManager().getContactPoints()); - return Optional.of(localDc); - } else if (profile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) { - localDc = profile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER); - LOG.debug("[{}] Local DC set from configuration: {}", logPrefix, localDc); - checkLocalDatacenterCompatibility(localDc, context.getMetadataManager().getContactPoints()); - return Optional.of(localDc); + Optional localDc = configuredLocalDc(); + if (localDc.isPresent()) { + checkLocalDatacenterCompatibility( + localDc.get(), context.getMetadataManager().getContactPoints()); } else { LOG.debug("[{}] Local DC not set, DC awareness will be disabled", logPrefix); - return Optional.empty(); } + return localDc; } /** @@ -138,4 +132,19 @@ protected String formatDcs(Iterable nodes) { } return String.join(", ", new TreeSet<>(l)); } + + /** @return Local data center set programmatically or from configuration file. */ + @NonNull + public Optional configuredLocalDc() { + String localDc = context.getLocalDatacenter(profile.getName()); + if (localDc != null) { + LOG.debug("[{}] Local DC set programmatically: {}", logPrefix, localDc); + return Optional.of(localDc); + } else if (profile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) { + localDc = profile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER); + LOG.debug("[{}] Local DC set from configuration: {}", logPrefix, localDc); + return Optional.of(localDc); + } + return Optional.empty(); + } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java index 92800998056..3bb9c4bc291 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java @@ -26,7 +26,6 @@ import com.datastax.oss.driver.internal.core.context.DefaultDriverContext; import com.datastax.oss.driver.internal.core.context.MockedDriverContextFactory; import java.net.InetSocketAddress; -import java.util.Optional; import org.junit.Test; public class FixedHostNameAddressTranslatorTest { @@ -36,7 +35,7 @@ public void should_translate_address() { DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class); when(defaultProfile.getString(ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME)).thenReturn("myaddress"); DefaultDriverContext defaultDriverContext = - MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile)); + MockedDriverContextFactory.defaultDriverContext(defaultProfile); FixedHostNameAddressTranslator translator = new FixedHostNameAddressTranslator(defaultDriverContext); diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java index 2aa6ae75bc2..420170654dc 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java @@ -30,7 +30,6 @@ import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import java.net.InetSocketAddress; import java.util.Map; -import java.util.Optional; import org.junit.Test; @SuppressWarnings("resource") @@ -148,6 +147,6 @@ public void should_fail_on_default_address_without_port() { private static DefaultDriverContext context(Map subnetAddresses) { DriverExecutionProfile profile = mock(DriverExecutionProfile.class); when(profile.getStringMap(ADDRESS_TRANSLATOR_SUBNET_ADDRESSES)).thenReturn(subnetAddresses); - return MockedDriverContextFactory.defaultDriverContext(Optional.of(profile)); + return MockedDriverContextFactory.defaultDriverContext(profile); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java index baf101508d4..6d4585cb4d7 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java @@ -42,7 +42,7 @@ private DefaultDriverContext buildMockedContext(Optional compressionOpti DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class); when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none")) .thenReturn(compressionOption.orElse("none")); - return MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile)); + return MockedDriverContextFactory.defaultDriverContext(defaultProfile); } private void doCreateCompressorTest(Optional configVal, Class expectedClz) { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java index 06817326844..a8b25193f54 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java @@ -24,44 +24,45 @@ import com.datastax.oss.driver.api.core.config.DriverConfig; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy; +import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator; +import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; import com.datastax.oss.driver.api.core.tracker.RequestTracker; +import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry; +import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; import com.datastax.oss.driver.shaded.guava.common.collect.Maps; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.UUID; public class MockedDriverContextFactory { public static DefaultDriverContext defaultDriverContext() { - return defaultDriverContext(Optional.empty()); + return defaultDriverContext(MockedDriverContextFactory.defaultProfile("datacenter1")); } public static DefaultDriverContext defaultDriverContext( - Optional profileOption) { - - /* If the caller provided a profile use that, otherwise make a new one */ - final DriverExecutionProfile profile = - profileOption.orElseGet( - () -> { - DriverExecutionProfile blankProfile = mock(DriverExecutionProfile.class); - when(blankProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none")) - .thenReturn("none"); - when(blankProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) - .thenReturn(Duration.ofMinutes(5)); - when(blankProfile.isDefined(DefaultDriverOption.METRICS_FACTORY_CLASS)) - .thenReturn(true); - when(blankProfile.getString(DefaultDriverOption.METRICS_FACTORY_CLASS)) - .thenReturn("DefaultMetricsFactory"); - return blankProfile; - }); + DriverExecutionProfile defaultProfile, DriverExecutionProfile... profiles) { /* Setup machinery to connect the input DriverExecutionProfile to the config loader */ final DriverConfig driverConfig = mock(DriverConfig.class); final DriverConfigLoader configLoader = mock(DriverConfigLoader.class); when(configLoader.getInitialConfig()).thenReturn(driverConfig); - when(driverConfig.getDefaultProfile()).thenReturn(profile); + when(driverConfig.getDefaultProfile()).thenReturn(defaultProfile); + when(driverConfig.getProfile(defaultProfile.getName())).thenReturn(defaultProfile); + + for (DriverExecutionProfile profile : profiles) { + when(driverConfig.getProfile(profile.getName())).thenReturn(profile); + } ProgrammaticArguments args = ProgrammaticArguments.builder() @@ -71,6 +72,89 @@ public static DefaultDriverContext defaultDriverContext( .withLocalDatacenters(Maps.newHashMap()) .withNodeDistanceEvaluators(Maps.newHashMap()) .build(); - return new DefaultDriverContext(configLoader, args); + + return new DefaultDriverContext(configLoader, args) { + @NonNull + @Override + public Map getLoadBalancingPolicies() { + ImmutableMap.Builder map = ImmutableMap.builder(); + map.put( + defaultProfile.getName(), + mockLoadBalancingPolicy( + this, + defaultProfile.getName(), + defaultProfile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))); + for (DriverExecutionProfile profile : profiles) { + map.put( + profile.getName(), + mockLoadBalancingPolicy( + this, + profile.getName(), + profile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))); + } + return map.build(); + } + + @NonNull + @Override + public ConsistencyLevelRegistry getConsistencyLevelRegistry() { + return mock(ConsistencyLevelRegistry.class); + } + }; + } + + public static DriverExecutionProfile defaultProfile(String localDc) { + return createProfile(DriverExecutionProfile.DEFAULT_NAME, localDc); + } + + public static DriverExecutionProfile createProfile(String name, String localDc) { + DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class); + when(defaultProfile.getName()).thenReturn(name); + when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none")) + .thenReturn("none"); + when(defaultProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER)) + .thenReturn(Duration.ofMinutes(5)); + when(defaultProfile.isDefined(DefaultDriverOption.METRICS_FACTORY_CLASS)).thenReturn(true); + when(defaultProfile.getString(DefaultDriverOption.METRICS_FACTORY_CLASS)) + .thenReturn("DefaultMetricsFactory"); + when(defaultProfile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) + .thenReturn(localDc); + return defaultProfile; + } + + public static void allowRemoteDcConnectivity( + DriverExecutionProfile profile, + int maxNodesPerRemoteDc, + boolean allowRemoteSatisfyLocalDc, + List preferredRemoteDcs) { + when(profile.getInt(DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC)) + .thenReturn(maxNodesPerRemoteDc); + when(profile.getBoolean( + DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS)) + .thenReturn(allowRemoteSatisfyLocalDc); + when(profile.getStringList(DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS)) + .thenReturn(preferredRemoteDcs); + } + + private static LoadBalancingPolicy mockLoadBalancingPolicy( + DefaultDriverContext driverContext, String profile, String localDc) { + LoadBalancingPolicy loadBalancingPolicy = + new DefaultLoadBalancingPolicy(driverContext, profile) { + @NonNull + @Override + protected Optional discoverLocalDc(@NonNull Map nodes) { + return Optional.ofNullable(localDc); + } + + @NonNull + @Override + protected NodeDistanceEvaluator createNodeDistanceEvaluator( + @Nullable String localDc, @NonNull Map nodes) { + return mock(NodeDistanceEvaluator.class); + } + }; + loadBalancingPolicy.init( + Collections.emptyMap(), mock(LoadBalancingPolicy.DistanceReporter.class)); + return loadBalancingPolicy; } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java index 33811b2793a..d12e50b7e8e 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java @@ -26,10 +26,10 @@ import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList; import com.datastax.oss.protocol.internal.request.Startup; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,7 +41,8 @@ private DefaultDriverContext buildMockedContext(String compression) { DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class); when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none")) .thenReturn(compression); - return MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile)); + when(defaultProfile.getName()).thenReturn(DriverExecutionProfile.DEFAULT_NAME); + return MockedDriverContextFactory.defaultDriverContext(defaultProfile); } private void assertDefaultStartupOptions(Startup startup) { @@ -94,4 +95,44 @@ public void should_fail_to_build_startup_options_with_invalid_compression() { new Startup(ctx.getStartupOptions()); }); } + + @Test + public void should_include_all_local_dcs_in_startup_message() { + + DefaultDriverContext ctx = + MockedDriverContextFactory.defaultDriverContext( + MockedDriverContextFactory.defaultProfile("us-west-2"), + MockedDriverContextFactory.createProfile("oltp", "us-east-2"), + MockedDriverContextFactory.createProfile("olap", "eu-central-1")); + Startup startup = new Startup(ctx.getStartupOptions()); + assertThat(startup.options) + .containsEntry( + StartupOptionsBuilder.DRIVER_BAGGAGE, + "{\"default\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"us-west-2\"}}," + + "\"oltp\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"us-east-2\"}}," + + "\"olap\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"eu-central-1\"}}}"); + } + + @Test + public void should_include_all_lbp_details_in_startup_message() { + + DriverExecutionProfile defaultProfile = MockedDriverContextFactory.defaultProfile("dc1"); + DriverExecutionProfile oltpProfile = MockedDriverContextFactory.createProfile("oltp", "dc1"); + MockedDriverContextFactory.allowRemoteDcConnectivity( + oltpProfile, 2, true, ImmutableList.of("dc2", "dc3")); + DefaultDriverContext ctx = + MockedDriverContextFactory.defaultDriverContext(defaultProfile, oltpProfile); + + Startup startup = new Startup(ctx.getStartupOptions()); + + assertThat(startup.options) + .containsEntry( + StartupOptionsBuilder.DRIVER_BAGGAGE, + "{\"default\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"dc1\"}}," + + "\"oltp\":{\"DefaultLoadBalancingPolicy\":{" + + "\"localDc\":\"dc1\"," + + "\"preferredRemoteDcs\":[\"dc2\",\"dc3\"]," + + "\"allowDcFailoverForLocalCl\":true," + + "\"maxNodesPerRemoteDc\":2}}}"); + } } From e2c7ad4d11555eeacce6bd436547b403f83eb24f Mon Sep 17 00:00:00 2001 From: janehe Date: Tue, 15 Apr 2025 13:18:34 -0700 Subject: [PATCH 384/395] CASSJAVA-97: Let users inject an ID for each request and write to the custom payload patch by Jane He; reviewed by Abe Ratnofsky and Bret McGuire for CASSJAVA-97 --- core/revapi.json | 5 + .../api/core/config/DefaultDriverOption.java | 6 + .../api/core/config/TypedDriverOption.java | 4 + .../api/core/context/DriverContext.java | 5 + .../core/session/ProgrammaticArguments.java | 17 +++ .../api/core/session/SessionBuilder.java | 22 +++ .../api/core/tracker/RequestIdGenerator.java | 77 +++++++++++ .../api/core/tracker/RequestTracker.java | 41 +++--- .../core/context/DefaultDriverContext.java | 24 ++++ .../internal/core/cql/CqlRequestHandler.java | 59 +++++++-- .../DefaultLoadBalancingPolicy.java | 4 +- .../tracker/MultiplexingRequestTracker.java | 31 +++-- .../core/tracker/NoopRequestTracker.java | 8 +- .../internal/core/tracker/RequestLogger.java | 12 +- .../core/tracker/UuidRequestIdGenerator.java | 43 ++++++ .../tracker/W3CContextRequestIdGenerator.java | 67 ++++++++++ core/src/main/resources/reference.conf | 7 + .../core/cql/RequestHandlerTestHarness.java | 3 + .../core/tracker/RequestIdGeneratorTest.java | 80 +++++++++++ .../core/tracker/RequestIdGeneratorIT.java | 125 ++++++++++++++++++ .../tracker/RequestNodeLoggerExample.java | 8 +- manual/core/request_id/README.md | 48 +++++++ 22 files changed, 637 insertions(+), 59 deletions(-) create mode 100644 core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/tracker/UuidRequestIdGenerator.java create mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/tracker/W3CContextRequestIdGenerator.java create mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/tracker/RequestIdGeneratorTest.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java create mode 100644 manual/core/request_id/README.md diff --git a/core/revapi.json b/core/revapi.json index f39c7d4a7c0..8c707659c13 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -7407,6 +7407,11 @@ { "code": "java.method.varargOverloadsOnlyDifferInVarargParameter", "justification": "CASSJAVA-102: Migrate revapi config into dedicated config files, ported from pom.xml" + }, + { + "code": "java.method.addedToInterface", + "new": "method java.util.Optional com.datastax.oss.driver.api.core.context.DriverContext::getRequestIdGenerator()", + "justification": "CASSJAVA-97: Let users inject an ID for each request and write to the custom payload" } ] } diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java index 4e45bf7b117..60c44193577 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/DefaultDriverOption.java @@ -995,6 +995,12 @@ public enum DefaultDriverOption implements DriverOption { *

    Value-type: boolean */ SSL_ALLOW_DNS_REVERSE_LOOKUP_SAN("advanced.ssl-engine-factory.allow-dns-reverse-lookup-san"), + /** + * The class of session-wide component that generates request IDs. + * + *

    Value-type: {@link String} + */ + REQUEST_ID_GENERATOR_CLASS("advanced.request-id.generator.class"), /** * An address to always translate all node addresses to that same proxy hostname no matter what IP * address a node has, but still using its native transport port. diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java index aa4e4af12dc..182753300e7 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/config/TypedDriverOption.java @@ -281,6 +281,10 @@ public String toString() { new TypedDriverOption<>( DefaultDriverOption.REQUEST_TRACKER_CLASSES, GenericType.listOf(String.class)); + /** The class of a session-wide component that generates request IDs. */ + public static final TypedDriverOption REQUEST_ID_GENERATOR_CLASS = + new TypedDriverOption<>(DefaultDriverOption.REQUEST_ID_GENERATOR_CLASS, GenericType.STRING); + /** Whether to log successful requests. */ public static final TypedDriverOption REQUEST_LOGGER_SUCCESS_ENABLED = new TypedDriverOption<>( diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/context/DriverContext.java b/core/src/main/java/com/datastax/oss/driver/api/core/context/DriverContext.java index 5b32389e362..6f0afd3df8a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/context/DriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/context/DriverContext.java @@ -33,6 +33,7 @@ import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.api.core.ssl.SslEngineFactory; import com.datastax.oss.driver.api.core.time.TimestampGenerator; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Map; @@ -139,6 +140,10 @@ default SpeculativeExecutionPolicy getSpeculativeExecutionPolicy(@NonNull String @NonNull RequestTracker getRequestTracker(); + /** @return The driver's request ID generator; never {@code null}. */ + @NonNull + Optional getRequestIdGenerator(); + /** @return The driver's request throttler; never {@code null}. */ @NonNull RequestThrottler getRequestThrottler(); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java index 4e08bd5434c..5e10fb4d915 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/ProgrammaticArguments.java @@ -23,6 +23,7 @@ import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; import com.datastax.oss.driver.api.core.ssl.SslEngineFactory; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; @@ -59,6 +60,7 @@ public static Builder builder() { private final NodeStateListener nodeStateListener; private final SchemaChangeListener schemaChangeListener; private final RequestTracker requestTracker; + private final RequestIdGenerator requestIdGenerator; private final Map localDatacenters; private final Map> nodeFilters; private final Map nodeDistanceEvaluators; @@ -77,6 +79,7 @@ private ProgrammaticArguments( @Nullable NodeStateListener nodeStateListener, @Nullable SchemaChangeListener schemaChangeListener, @Nullable RequestTracker requestTracker, + @Nullable RequestIdGenerator requestIdGenerator, @NonNull Map localDatacenters, @NonNull Map> nodeFilters, @NonNull Map nodeDistanceEvaluators, @@ -94,6 +97,7 @@ private ProgrammaticArguments( this.nodeStateListener = nodeStateListener; this.schemaChangeListener = schemaChangeListener; this.requestTracker = requestTracker; + this.requestIdGenerator = requestIdGenerator; this.localDatacenters = localDatacenters; this.nodeFilters = nodeFilters; this.nodeDistanceEvaluators = nodeDistanceEvaluators; @@ -128,6 +132,11 @@ public RequestTracker getRequestTracker() { return requestTracker; } + @Nullable + public RequestIdGenerator getRequestIdGenerator() { + return requestIdGenerator; + } + @NonNull public Map getLocalDatacenters() { return localDatacenters; @@ -196,6 +205,7 @@ public static class Builder { private NodeStateListener nodeStateListener; private SchemaChangeListener schemaChangeListener; private RequestTracker requestTracker; + private RequestIdGenerator requestIdGenerator; private ImmutableMap.Builder localDatacentersBuilder = ImmutableMap.builder(); private final ImmutableMap.Builder> nodeFiltersBuilder = ImmutableMap.builder(); @@ -294,6 +304,12 @@ public Builder addRequestTracker(@NonNull RequestTracker requestTracker) { return this; } + @NonNull + public Builder withRequestIdGenerator(@Nullable RequestIdGenerator requestIdGenerator) { + this.requestIdGenerator = requestIdGenerator; + return this; + } + @NonNull public Builder withLocalDatacenter( @NonNull String profileName, @NonNull String localDatacenter) { @@ -417,6 +433,7 @@ public ProgrammaticArguments build() { nodeStateListener, schemaChangeListener, requestTracker, + requestIdGenerator, localDatacentersBuilder.build(), nodeFiltersBuilder.build(), nodeDistanceEvaluatorsBuilder.build(), diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java index cbf896a0873..25500119047 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/session/SessionBuilder.java @@ -35,6 +35,7 @@ import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; import com.datastax.oss.driver.api.core.ssl.ProgrammaticSslEngineFactory; import com.datastax.oss.driver.api.core.ssl.SslEngineFactory; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.registry.MutableCodecRegistry; @@ -47,6 +48,7 @@ import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import com.datastax.oss.driver.internal.core.metadata.DefaultEndPoint; import com.datastax.oss.driver.internal.core.session.DefaultSession; +import com.datastax.oss.driver.internal.core.tracker.W3CContextRequestIdGenerator; import com.datastax.oss.driver.internal.core.util.concurrent.BlockingOperation; import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures; import edu.umd.cs.findbugs.annotations.NonNull; @@ -83,6 +85,8 @@ @NotThreadSafe public abstract class SessionBuilder { + public static final String ASTRA_PAYLOAD_KEY = "traceparent"; + private static final Logger LOG = LoggerFactory.getLogger(SessionBuilder.class); @SuppressWarnings("unchecked") @@ -318,6 +322,17 @@ public SelfT addRequestTracker(@NonNull RequestTracker requestTracker) { return self; } + /** + * Registers a request ID generator. The driver will use the generated ID in the logs and + * optionally add to the custom payload so that users can correlate logs about the same request + * from the Cassandra side. + */ + @NonNull + public SelfT withRequestIdGenerator(@NonNull RequestIdGenerator requestIdGenerator) { + this.programmaticArgumentsBuilder.withRequestIdGenerator(requestIdGenerator); + return self; + } + /** * Registers an authentication provider to use with the session. * @@ -861,6 +876,13 @@ protected final CompletionStage buildDefaultSessionAsync() { List configContactPoints = defaultConfig.getStringList(DefaultDriverOption.CONTACT_POINTS, Collections.emptyList()); if (cloudConfigInputStream != null) { + // override request id generator, unless user has already set it + if (programmaticArguments.getRequestIdGenerator() == null) { + programmaticArgumentsBuilder.withRequestIdGenerator( + new W3CContextRequestIdGenerator(ASTRA_PAYLOAD_KEY)); + LOG.debug( + "A secure connect bundle is provided, using W3CContextRequestIdGenerator as request ID generator."); + } if (!programmaticContactPoints.isEmpty() || !configContactPoints.isEmpty()) { LOG.info( "Both a secure connect bundle and contact points were provided. These are mutually exclusive. The contact points from the secure bundle will have priority."); diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java new file mode 100644 index 00000000000..59ac3fdacf7 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.api.core.tracker; + +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +/** + * Interface responsible for generating request IDs. + * + *

    Note that all request IDs have a parent/child relationship. A "parent ID" can loosely be + * thought of as encompassing a sequence of a request + any attendant retries, speculative + * executions etc. It's scope is identical to that of a {@link + * com.datastax.oss.driver.internal.core.cql.CqlRequestHandler}. A "request ID" represents a single + * request within this larger scope. Note that a request corresponding to a request ID may be + * retried; in that case the retry count will be appended to the corresponding identifier in the + * logs. + */ +public interface RequestIdGenerator { + + String DEFAULT_PAYLOAD_KEY = "request-id"; + + /** + * Generates a unique identifier for the session request. This will be the identifier for the + * entire `session.execute()` call. This identifier will be added to logs, and propagated to + * request trackers. + * + * @return a unique identifier for the session request + */ + String getSessionRequestId(); + + /** + * Generates a unique identifier for the node request. This will be the identifier for the CQL + * request against a particular node. There can be one or more node requests for a single session + * request, due to retries or speculative executions. This identifier will be added to logs, and + * propagated to request trackers. + * + * @param statement the statement to be executed + * @param parentId the session request identifier + * @return a unique identifier for the node request + */ + String getNodeRequestId(@NonNull Request statement, @NonNull String parentId); + + default String getCustomPayloadKey() { + return DEFAULT_PAYLOAD_KEY; + } + + default Statement getDecoratedStatement( + @NonNull Statement statement, @NonNull String requestId) { + Map customPayload = + NullAllowingImmutableMap.builder() + .putAll(statement.getCustomPayload()) + .put(getCustomPayloadKey(), ByteBuffer.wrap(requestId.getBytes(StandardCharsets.UTF_8))) + .build(); + return statement.setCustomPayload(customPayload); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java index d29ee48d352..065b41e496a 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestTracker.java @@ -47,21 +47,22 @@ default void onSuccess( @NonNull Node node) {} /** - * Invoked each time a request succeeds. + * Invoked each time a session request succeeds. A session request is a `session.execute()` call * * @param latencyNanos the overall execution time (from the {@link Session#execute(Request, * GenericType) session.execute} call until the result is made available to the client). * @param executionProfile the execution profile of this request. * @param node the node that returned the successful response. - * @param requestLogPrefix the dedicated log prefix for this request + * @param sessionRequestLogPrefix the dedicated log prefix for this request */ default void onSuccess( @NonNull Request request, long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String requestLogPrefix) { - // If client doesn't override onSuccess with requestLogPrefix delegate call to the old method + @NonNull String sessionRequestLogPrefix) { + // If client doesn't override onSuccess with sessionRequestLogPrefix delegate call to the old + // method onSuccess(request, latencyNanos, executionProfile, node); } @@ -78,13 +79,13 @@ default void onError( @Nullable Node node) {} /** - * Invoked each time a request fails. + * Invoked each time a session request fails. A session request is a `session.execute()` call * * @param latencyNanos the overall execution time (from the {@link Session#execute(Request, * GenericType) session.execute} call until the error is propagated to the client). * @param executionProfile the execution profile of this request. * @param node the node that returned the error response, or {@code null} if the error occurred - * @param requestLogPrefix the dedicated log prefix for this request + * @param sessionRequestLogPrefix the dedicated log prefix for this request */ default void onError( @NonNull Request request, @@ -92,8 +93,9 @@ default void onError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @Nullable Node node, - @NonNull String requestLogPrefix) { - // If client doesn't override onError with requestLogPrefix delegate call to the old method + @NonNull String sessionRequestLogPrefix) { + // If client doesn't override onError with sessionRequestLogPrefix delegate call to the old + // method onError(request, error, latencyNanos, executionProfile, node); } @@ -110,14 +112,15 @@ default void onNodeError( @NonNull Node node) {} /** - * Invoked each time a request fails at the node level. Similar to {@link #onError(Request, - * Throwable, long, DriverExecutionProfile, Node, String)} but at a per node level. + * Invoked each time a node request fails. A node request is a CQL request sent to a particular + * node. There can be one or more node requests for a single session request, due to retries or + * speculative executions. * * @param latencyNanos the overall execution time (from the {@link Session#execute(Request, * GenericType) session.execute} call until the error is propagated to the client). * @param executionProfile the execution profile of this request. * @param node the node that returned the error response. - * @param requestLogPrefix the dedicated log prefix for this request + * @param nodeRequestLogPrefix the dedicated log prefix for this request */ default void onNodeError( @NonNull Request request, @@ -125,8 +128,9 @@ default void onNodeError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String requestLogPrefix) { - // If client doesn't override onNodeError with requestLogPrefix delegate call to the old method + @NonNull String nodeRequestLogPrefix) { + // If client doesn't override onNodeError with nodeRequestLogPrefix delegate call to the old + // method onNodeError(request, error, latencyNanos, executionProfile, node); } @@ -142,22 +146,23 @@ default void onNodeSuccess( @NonNull Node node) {} /** - * Invoked each time a request succeeds at the node level. Similar to {@link #onSuccess(Request, - * long, DriverExecutionProfile, Node, String)} but at per node level. + * Invoked each time a node request succeeds. A node request is a CQL request sent to a particular + * node. There can be one or more node requests for a single session request, due to retries or + * speculative executions. * * @param latencyNanos the overall execution time (from the {@link Session#execute(Request, * GenericType) session.execute} call until the result is made available to the client). * @param executionProfile the execution profile of this request. * @param node the node that returned the successful response. - * @param requestLogPrefix the dedicated log prefix for this request + * @param nodeRequestLogPrefix the dedicated log prefix for this request */ default void onNodeSuccess( @NonNull Request request, long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String requestLogPrefix) { - // If client doesn't override onNodeSuccess with requestLogPrefix delegate call to the old + @NonNull String nodeRequestLogPrefix) { + // If client doesn't override onNodeSuccess with nodeRequestLogPrefix delegate call to the old // method onNodeSuccess(request, latencyNanos, executionProfile, node); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java index 0d7db27dfbe..3074bda2398 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java @@ -44,6 +44,7 @@ import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.api.core.ssl.SslEngineFactory; import com.datastax.oss.driver.api.core.time.TimestampGenerator; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; @@ -221,6 +222,7 @@ public class DefaultDriverContext implements InternalDriverContext { private final LazyReference nodeStateListenerRef; private final LazyReference schemaChangeListenerRef; private final LazyReference requestTrackerRef; + private final LazyReference> requestIdGeneratorRef; private final LazyReference> authProviderRef; private final LazyReference> lifecycleListenersRef = new LazyReference<>("lifecycleListeners", this::buildLifecycleListeners, cycleDetector); @@ -282,6 +284,11 @@ public DefaultDriverContext( this.requestTrackerRef = new LazyReference<>( "requestTracker", () -> buildRequestTracker(requestTrackerFromBuilder), cycleDetector); + this.requestIdGeneratorRef = + new LazyReference<>( + "requestIdGenerator", + () -> buildRequestIdGenerator(programmaticArguments.getRequestIdGenerator()), + cycleDetector); this.sslEngineFactoryRef = new LazyReference<>( "sslEngineFactory", @@ -708,6 +715,17 @@ protected RequestTracker buildRequestTracker(RequestTracker requestTrackerFromBu } } + protected Optional buildRequestIdGenerator( + RequestIdGenerator requestIdGenerator) { + return (requestIdGenerator != null) + ? Optional.of(requestIdGenerator) + : Reflection.buildFromConfig( + this, + DefaultDriverOption.REQUEST_ID_GENERATOR_CLASS, + RequestIdGenerator.class, + "com.datastax.oss.driver.internal.core.tracker"); + } + protected Optional buildAuthProvider(AuthProvider authProviderFromBuilder) { return (authProviderFromBuilder != null) ? Optional.of(authProviderFromBuilder) @@ -972,6 +990,12 @@ public RequestTracker getRequestTracker() { return requestTrackerRef.get(); } + @NonNull + @Override + public Optional getRequestIdGenerator() { + return requestIdGeneratorRef.get(); + } + @Nullable @Override public String getLocalDatacenter(@NonNull String profileName) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java index 0808bdce63f..6842547b11a 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java @@ -44,6 +44,7 @@ import com.datastax.oss.driver.api.core.servererrors.WriteTimeoutException; import com.datastax.oss.driver.api.core.session.throttling.RequestThrottler; import com.datastax.oss.driver.api.core.session.throttling.Throttled; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.driver.api.core.tracker.RequestTracker; import com.datastax.oss.driver.internal.core.adminrequest.ThrottledAdminRequestHandler; import com.datastax.oss.driver.internal.core.adminrequest.UnexpectedResponseException; @@ -59,6 +60,7 @@ import com.datastax.oss.driver.internal.core.tracker.RequestLogger; import com.datastax.oss.driver.internal.core.util.Loggers; import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan; +import com.datastax.oss.driver.shaded.guava.common.base.Joiner; import com.datastax.oss.protocol.internal.Frame; import com.datastax.oss.protocol.internal.Message; import com.datastax.oss.protocol.internal.ProtocolConstants; @@ -82,6 +84,7 @@ import java.util.AbstractMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Queue; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -100,7 +103,7 @@ public class CqlRequestHandler implements Throttled { private static final long NANOTIME_NOT_MEASURED_YET = -1; private final long startTimeNanos; - private final String logPrefix; + private final String handlerLogPrefix; private final Statement initialStatement; private final DefaultSession session; private final CqlIdentifier keyspace; @@ -125,6 +128,7 @@ public class CqlRequestHandler implements Throttled { private final List inFlightCallbacks; private final RequestThrottler throttler; private final RequestTracker requestTracker; + private final Optional requestIdGenerator; private final SessionMetricUpdater sessionMetricUpdater; private final DriverExecutionProfile executionProfile; @@ -132,15 +136,25 @@ public class CqlRequestHandler implements Throttled { // We don't use a map because nodes can appear multiple times. private volatile List> errors; + private final Joiner logPrefixJoiner = Joiner.on('|'); + private final String sessionName; + private final String sessionRequestId; + protected CqlRequestHandler( Statement statement, DefaultSession session, InternalDriverContext context, - String sessionLogPrefix) { + String sessionName) { this.startTimeNanos = System.nanoTime(); - this.logPrefix = sessionLogPrefix + "|" + this.hashCode(); - LOG.trace("[{}] Creating new handler for request {}", logPrefix, statement); + this.requestIdGenerator = context.getRequestIdGenerator(); + this.sessionName = sessionName; + this.sessionRequestId = + this.requestIdGenerator + .map(RequestIdGenerator::getSessionRequestId) + .orElse(Integer.toString(this.hashCode())); + this.handlerLogPrefix = logPrefixJoiner.join(sessionName, sessionRequestId); + LOG.trace("[{}] Creating new handler for request {}", handlerLogPrefix, statement); this.initialStatement = statement; this.session = session; @@ -155,7 +169,7 @@ protected CqlRequestHandler( context.getRequestThrottler().signalCancel(this); } } catch (Throwable t2) { - Loggers.warnWithException(LOG, "[{}] Uncaught exception", logPrefix, t2); + Loggers.warnWithException(LOG, "[{}] Uncaught exception", handlerLogPrefix, t2); } return null; }); @@ -250,9 +264,9 @@ private void sendRequest( } Node node = retriedNode; DriverChannel channel = null; - if (node == null || (channel = session.getChannel(node, logPrefix)) == null) { + if (node == null || (channel = session.getChannel(node, handlerLogPrefix)) == null) { while (!result.isDone() && (node = queryPlan.poll()) != null) { - channel = session.getChannel(node, logPrefix); + channel = session.getChannel(node, handlerLogPrefix); if (channel != null) { break; } else { @@ -267,6 +281,16 @@ private void sendRequest( setFinalError(statement, AllNodesFailedException.fromErrors(this.errors), null, -1); } } else { + Statement finalStatement = statement; + String nodeRequestId = + this.requestIdGenerator + .map((g) -> g.getNodeRequestId(finalStatement, sessionRequestId)) + .orElse(Integer.toString(this.hashCode())); + statement = + this.requestIdGenerator + .map((g) -> g.getDecoratedStatement(finalStatement, nodeRequestId)) + .orElse(finalStatement); + NodeResponseCallback nodeResponseCallback = new NodeResponseCallback( statement, @@ -276,7 +300,7 @@ private void sendRequest( currentExecutionIndex, retryCount, scheduleNextExecution, - logPrefix); + logPrefixJoiner.join(this.sessionName, nodeRequestId, currentExecutionIndex)); Message message = Conversions.toMessage(statement, executionProfile, context); channel .write(message, statement.isTracing(), statement.getCustomPayload(), nodeResponseCallback) @@ -335,9 +359,17 @@ private void setFinalResult( totalLatencyNanos = completionTimeNanos - startTimeNanos; long nodeLatencyNanos = completionTimeNanos - callback.nodeStartTimeNanos; requestTracker.onNodeSuccess( - callback.statement, nodeLatencyNanos, executionProfile, callback.node, logPrefix); + callback.statement, + nodeLatencyNanos, + executionProfile, + callback.node, + handlerLogPrefix); requestTracker.onSuccess( - callback.statement, totalLatencyNanos, executionProfile, callback.node, logPrefix); + callback.statement, + totalLatencyNanos, + executionProfile, + callback.node, + handlerLogPrefix); } if (sessionMetricUpdater.isEnabled( DefaultSessionMetric.CQL_REQUESTS, executionProfile.getName())) { @@ -439,7 +471,8 @@ private void setFinalError(Statement statement, Throwable error, Node node, i cancelScheduledTasks(); if (!(requestTracker instanceof NoopRequestTracker)) { long latencyNanos = System.nanoTime() - startTimeNanos; - requestTracker.onError(statement, error, latencyNanos, executionProfile, node, logPrefix); + requestTracker.onError( + statement, error, latencyNanos, executionProfile, node, handlerLogPrefix); } if (error instanceof DriverTimeoutException) { throttler.signalTimeout(this); @@ -489,7 +522,7 @@ private NodeResponseCallback( this.execution = execution; this.retryCount = retryCount; this.scheduleNextExecution = scheduleNextExecution; - this.logPrefix = logPrefix + "|" + execution; + this.logPrefix = logPrefix; } // this gets invoked once the write completes. @@ -567,7 +600,7 @@ private void scheduleSpeculativeExecution(int index, long delay) { if (!result.isDone()) { LOG.trace( "[{}] Starting speculative execution {}", - CqlRequestHandler.this.logPrefix, + CqlRequestHandler.this.handlerLogPrefix, index); activeExecutionsCount.incrementAndGet(); startedSpeculativeExecutionsCount.incrementAndGet(); diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java index 9c31b606f18..8e1c1fe5039 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java @@ -246,7 +246,7 @@ public void onNodeSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { updateResponseTimes(node); } @@ -257,7 +257,7 @@ public void onNodeError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { updateResponseTimes(node); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java index d4d20f3eb78..6fe2ba059bd 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/MultiplexingRequestTracker.java @@ -82,10 +82,12 @@ public void onSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String sessionRequestLogPrefix) { invokeTrackers( - tracker -> tracker.onSuccess(request, latencyNanos, executionProfile, node, logPrefix), - logPrefix, + tracker -> + tracker.onSuccess( + request, latencyNanos, executionProfile, node, sessionRequestLogPrefix), + sessionRequestLogPrefix, "onSuccess"); } @@ -96,10 +98,12 @@ public void onError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @Nullable Node node, - @NonNull String logPrefix) { + @NonNull String sessionRequestLogPrefix) { invokeTrackers( - tracker -> tracker.onError(request, error, latencyNanos, executionProfile, node, logPrefix), - logPrefix, + tracker -> + tracker.onError( + request, error, latencyNanos, executionProfile, node, sessionRequestLogPrefix), + sessionRequestLogPrefix, "onError"); } @@ -109,10 +113,12 @@ public void onNodeSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { invokeTrackers( - tracker -> tracker.onNodeSuccess(request, latencyNanos, executionProfile, node, logPrefix), - logPrefix, + tracker -> + tracker.onNodeSuccess( + request, latencyNanos, executionProfile, node, nodeRequestLogPrefix), + nodeRequestLogPrefix, "onNodeSuccess"); } @@ -123,11 +129,12 @@ public void onNodeError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { invokeTrackers( tracker -> - tracker.onNodeError(request, error, latencyNanos, executionProfile, node, logPrefix), - logPrefix, + tracker.onNodeError( + request, error, latencyNanos, executionProfile, node, nodeRequestLogPrefix), + nodeRequestLogPrefix, "onNodeError"); } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java index 09ac27e5e75..3821c6ace2d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/NoopRequestTracker.java @@ -42,7 +42,7 @@ public void onSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String requestPrefix) { + @NonNull String sessionRequestLogPrefix) { // nothing to do } @@ -53,7 +53,7 @@ public void onError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, Node node, - @NonNull String requestPrefix) { + @NonNull String sessionRequestLogPrefix) { // nothing to do } @@ -64,7 +64,7 @@ public void onNodeError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String requestPrefix) { + @NonNull String nodeRequestLogPrefix) { // nothing to do } @@ -74,7 +74,7 @@ public void onNodeSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String requestPrefix) { + @NonNull String nodeRequestLogPrefix) { // nothing to do } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java index 235ef051b40..f242ff89c54 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/RequestLogger.java @@ -86,7 +86,7 @@ public void onSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String sessionRequestLogPrefix) { boolean successEnabled = executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOGGER_SUCCESS_ENABLED, false); @@ -129,7 +129,7 @@ public void onSuccess( showValues, maxValues, maxValueLength, - logPrefix); + sessionRequestLogPrefix); } @Override @@ -139,7 +139,7 @@ public void onError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, Node node, - @NonNull String logPrefix) { + @NonNull String sessionRequestLogPrefix) { if (!executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOGGER_ERROR_ENABLED, false)) { return; @@ -173,7 +173,7 @@ public void onError( maxValues, maxValueLength, showStackTraces, - logPrefix); + sessionRequestLogPrefix); } @Override @@ -183,7 +183,7 @@ public void onNodeError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { // Nothing to do } @@ -193,7 +193,7 @@ public void onNodeSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { // Nothing to do } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/UuidRequestIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/UuidRequestIdGenerator.java new file mode 100644 index 00000000000..cc07d6717f4 --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/UuidRequestIdGenerator.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.tracker; + +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; +import com.datastax.oss.driver.api.core.uuid.Uuids; +import edu.umd.cs.findbugs.annotations.NonNull; + +public class UuidRequestIdGenerator implements RequestIdGenerator { + public UuidRequestIdGenerator(DriverContext context) {} + + /** Generates a random v4 UUID. */ + @Override + public String getSessionRequestId() { + return Uuids.random().toString(); + } + + /** + * {session-request-id}-{random-uuid} All node requests for a session request will have the same + * session request id + */ + @Override + public String getNodeRequestId(@NonNull Request statement, @NonNull String parentId) { + return parentId + "-" + Uuids.random(); + } +} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/W3CContextRequestIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/W3CContextRequestIdGenerator.java new file mode 100644 index 00000000000..fe15b93bc8e --- /dev/null +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/tracker/W3CContextRequestIdGenerator.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.tracker; + +import com.datastax.oss.driver.api.core.context.DriverContext; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; +import com.datastax.oss.driver.shaded.guava.common.io.BaseEncoding; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.security.SecureRandom; +import java.util.Random; + +public class W3CContextRequestIdGenerator implements RequestIdGenerator { + + private final Random random = new SecureRandom(); + private final BaseEncoding baseEncoding = BaseEncoding.base16().lowerCase(); + private final String payloadKey; + + public W3CContextRequestIdGenerator(DriverContext context) { + payloadKey = RequestIdGenerator.super.getCustomPayloadKey(); + } + + public W3CContextRequestIdGenerator(String payloadKey) { + this.payloadKey = payloadKey; + } + + /** Random 16 bytes, e.g. "4bf92f3577b34da6a3ce929d0e0e4736" */ + @Override + public String getSessionRequestId() { + byte[] bytes = new byte[16]; + random.nextBytes(bytes); + return baseEncoding.encode(bytes); + } + + /** + * Following the format of W3C "traceparent" spec, + * https://www.w3.org/TR/trace-context/#traceparent-header-field-values e.g. + * "00-4bf92f3577b34da6a3ce929d0e0e4736-a3ce929d0e0e4736-01" All node requests in the same session + * request share the same "trace-id" field value + */ + @Override + public String getNodeRequestId(@NonNull Request statement, @NonNull String parentId) { + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + return String.format("00-%s-%s-00", parentId, baseEncoding.encode(bytes)); + } + + @Override + public String getCustomPayloadKey() { + return this.payloadKey; + } +} diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 3c6851a48ee..741b1d97654 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -918,6 +918,13 @@ datastax-java-driver { } } + advanced.request-id { + generator { + # The component that generates a unique identifier for each CQL request, and possibly write the id to the custom payload . + // class = W3CContextRequestIdGenerator + } + } + # A session-wide component that controls the rate at which requests are executed. # # Implementations vary, but throttlers generally track a metric that represents the level of diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java index 9d86302aabf..6ecd6111992 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java @@ -61,6 +61,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -168,6 +169,8 @@ protected RequestHandlerTestHarness(Builder builder) { when(context.getRequestThrottler()).thenReturn(new PassThroughRequestThrottler(context)); when(context.getRequestTracker()).thenReturn(new NoopRequestTracker(context)); + + when(context.getRequestIdGenerator()).thenReturn(Optional.empty()); } public DefaultSession getSession() { diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/tracker/RequestIdGeneratorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/tracker/RequestIdGeneratorTest.java new file mode 100644 index 00000000000..fb1883e125f --- /dev/null +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/tracker/RequestIdGeneratorTest.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.internal.core.tracker; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.Strict.class) +public class RequestIdGeneratorTest { + @Mock private InternalDriverContext context; + @Mock private Statement statement; + + @Test + public void uuid_generator_should_generate() { + // given + UuidRequestIdGenerator generator = new UuidRequestIdGenerator(context); + // when + String parentId = generator.getSessionRequestId(); + String requestId = generator.getNodeRequestId(statement, parentId); + // then + // e.g. "550e8400-e29b-41d4-a716-446655440000", which is 36 characters long + assertThat(parentId.length()).isEqualTo(36); + // e.g. "550e8400-e29b-41d4-a716-446655440000-550e8400-e29b-41d4-a716-446655440000", which is 73 + // characters long + assertThat(requestId.length()).isEqualTo(73); + } + + @Test + public void w3c_generator_should_generate() { + // given + W3CContextRequestIdGenerator generator = new W3CContextRequestIdGenerator(context); + // when + String parentId = generator.getSessionRequestId(); + String requestId = generator.getNodeRequestId(statement, parentId); + // then + // e.g. "4bf92f3577b34da6a3ce929d0e0e4736", which is 32 characters long + assertThat(parentId.length()).isEqualTo(32); + // According to W3C "traceparent" spec, + // https://www.w3.org/TR/trace-context/#traceparent-header-field-values + // e.g. "00-4bf92f3577b34da6a3ce929d0e0e4736-a3ce929d0e0e4736-01", which 55 characters long + assertThat(requestId.length()).isEqualTo(55); + } + + @Test + public void w3c_generator_default_payloadkey() { + W3CContextRequestIdGenerator w3cGenerator = new W3CContextRequestIdGenerator(context); + assertThat(w3cGenerator.getCustomPayloadKey()) + .isEqualTo(RequestIdGenerator.DEFAULT_PAYLOAD_KEY); + } + + @Test + public void w3c_generator_provided_payloadkey() { + String someString = RandomStringUtils.random(12); + W3CContextRequestIdGenerator w3cGenerator = new W3CContextRequestIdGenerator(someString); + assertThat(w3cGenerator.getCustomPayloadKey()).isEqualTo(someString); + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java new file mode 100644 index 00000000000..2848a8fb629 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.datastax.oss.driver.core.tracker; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; +import com.datastax.oss.driver.api.testinfra.ccm.CcmRule; +import com.datastax.oss.driver.api.testinfra.session.SessionUtils; +import com.datastax.oss.driver.categories.ParallelizableTests; +import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; + +@Category(ParallelizableTests.class) +public class RequestIdGeneratorIT { + private CcmRule ccmRule = CcmRule.getInstance(); + + @Rule public TestRule chain = RuleChain.outerRule(ccmRule); + + @Test + public void should_write_uuid_to_custom_payload_with_key() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString(DefaultDriverOption.REQUEST_ID_GENERATOR_CLASS, "UuidRequestIdGenerator") + .build(); + try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { + String query = "SELECT * FROM system.local"; + ResultSet rs = session.execute(query); + ByteBuffer id = rs.getExecutionInfo().getRequest().getCustomPayload().get("request-id"); + assertThat(id.remaining()).isEqualTo(73); + } + } + + @Test + public void should_write_default_request_id_to_custom_payload_with_key() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString( + DefaultDriverOption.REQUEST_ID_GENERATOR_CLASS, "W3CContextRequestIdGenerator") + .build(); + try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { + String query = "SELECT * FROM system.local"; + ResultSet rs = session.execute(query); + ByteBuffer id = rs.getExecutionInfo().getRequest().getCustomPayload().get("request-id"); + assertThat(id.remaining()).isEqualTo(55); + } + } + + @Test + public void should_use_customized_request_id_generator() { + RequestIdGenerator myRequestIdGenerator = + new RequestIdGenerator() { + @Override + public String getSessionRequestId() { + return "123"; + } + + @Override + public String getNodeRequestId(@NonNull Request statement, @NonNull String parentId) { + return "456"; + } + + @Override + public Statement getDecoratedStatement( + @NonNull Statement statement, @NonNull String requestId) { + Map customPayload = + NullAllowingImmutableMap.builder() + .putAll(statement.getCustomPayload()) + .put("trace_key", ByteBuffer.wrap(requestId.getBytes(StandardCharsets.UTF_8))) + .build(); + return statement.setCustomPayload(customPayload); + } + }; + try (CqlSession session = + (CqlSession) + SessionUtils.baseBuilder() + .addContactEndPoints(ccmRule.getContactPoints()) + .withRequestIdGenerator(myRequestIdGenerator) + .build()) { + String query = "SELECT * FROM system.local"; + ResultSet rs = session.execute(query); + ByteBuffer id = rs.getExecutionInfo().getRequest().getCustomPayload().get("trace_key"); + assertThat(id).isEqualTo(ByteBuffer.wrap("456".getBytes(StandardCharsets.UTF_8))); + } + } + + @Test + public void should_not_write_id_to_custom_payload_when_key_is_not_set() { + DriverConfigLoader loader = SessionUtils.configLoaderBuilder().build(); + try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { + String query = "SELECT * FROM system.local"; + ResultSet rs = session.execute(query); + assertThat(rs.getExecutionInfo().getRequest().getCustomPayload().get("trace_key")).isNull(); + } + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestNodeLoggerExample.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestNodeLoggerExample.java index eae98339637..8eb2fb80a73 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestNodeLoggerExample.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestNodeLoggerExample.java @@ -39,7 +39,7 @@ public void onNodeError( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { if (!executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOGGER_ERROR_ENABLED)) { return; } @@ -66,7 +66,7 @@ public void onNodeError( maxValues, maxValueLength, showStackTraces, - logPrefix); + nodeRequestLogPrefix); } @Override @@ -75,7 +75,7 @@ public void onNodeSuccess( long latencyNanos, @NonNull DriverExecutionProfile executionProfile, @NonNull Node node, - @NonNull String logPrefix) { + @NonNull String nodeRequestLogPrefix) { boolean successEnabled = executionProfile.getBoolean(DefaultDriverOption.REQUEST_LOGGER_SUCCESS_ENABLED); boolean slowEnabled = @@ -114,6 +114,6 @@ public void onNodeSuccess( showValues, maxValues, maxValueLength, - logPrefix); + nodeRequestLogPrefix); } } diff --git a/manual/core/request_id/README.md b/manual/core/request_id/README.md new file mode 100644 index 00000000000..a766a4419af --- /dev/null +++ b/manual/core/request_id/README.md @@ -0,0 +1,48 @@ + + +## Request Id + +### Quick overview + +Users can inject an identifier for each individual CQL request, and such ID can be written in to the [custom payload](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v5.spec) to +correlate a request across the driver and the Apache Cassandra server. + +A request ID generator needs to generate both: +- Session request ID: an identifier for an entire session.execute() call +- Node request ID: an identifier for the execution of a CQL statement against a particular node. There can be one or more node requests for a single session request, due to retries or speculative executions. + +Usage: +* Inject ID generator: set the desired `RequestIdGenerator` in `advanced.request-id.generator.class`. +* Add ID to custom payload: the default behavior of a `RequestIdGenerator` is to add the request ID into the custom payload with the key `request-id`. Override `RequestIdGenerator.getDecoratedStatement` to customize the behavior. + +### Request Id Generator Configuration + +Request ID generator can be declared in the [configuration](../configuration/) as follows: + +``` +datastax-java-driver.advanced.request-id.generator { + class = com.example.app.MyGenerator +} +``` + +To register your own request ID generator, specify the name of the class +that implements `RequestIdGenerator`. + +The generated ID will be added to the log message of `CqlRequestHandler`, and propagated to other classes, e.g. the request trackers. \ No newline at end of file From 104751c166402274f46135b9d367bee1cfdd124d Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Tue, 14 Oct 2025 15:08:52 -0500 Subject: [PATCH 385/395] Changelog entries for 4.19.1 patch by Bret McGuire; reviewed by Andy Tolbert --- changelog/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 08634bcb834..9e223318e65 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -21,6 +21,24 @@ under the License. +### 4.19.1 + +- [improvement] CASSJAVA-97: Let users inject an ID for each request and write to the custom payload +- [improvement] CASSJAVA-92: Add Local DC to driver connection info and provide visibility with nodetool clientstats +- [bug] PR 2025: Eliminate lock in ConcurrencyLimitingRequestThrottler +- [improvement] CASSJAVA-89: Fix deprecated table configs in Cassandra 5 +- [improvement] PR 2028: Remove unnecessary locking in DefaultNettyOptions +- [improvement] CASSJAVA-102: Fix revapi spurious complaints about optional dependencies +- [improvement] PR 2013: Add SubnetAddressTranslator +- [improvement] CASSJAVA-68: Improve DefaultCodecRegistry.CacheKey#hashCode() to eliminate Object[] allocation +- [improvement] PR 1989: Bump Jackson version to la(te)st 2.13.x, 2.13.5 +- [improvement] CASSJAVA-76: Make guava an optional dependency of java-driver-guava-shaded +- [bug] PR 2035: Prevent long overflow in SNI address resolution +- [improvement] CASSJAVA-77: 4.x: Upgrade Netty to 4.1.119 +- [improvement] CASSJAVA-40: Driver testing against Java 21 +- [improvement] CASSJAVA-90: Update native-protocol +- [improvement] CASSJAVA-80: Support configuration to disable DNS reverse-lookups for SAN validation + ### 4.19.0 - [bug] JAVA-3055: Prevent PreparedStatement cache to be polluted if a request is cancelled. From 77b2baebebfa208e2a7a29f6b09b6cb86e3a4b61 Mon Sep 17 00:00:00 2001 From: Andy Tolbert <6889771+tolbertam@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:32:38 -0500 Subject: [PATCH 386/395] [maven-release-plugin] prepare release 4.19.1 --- bom/pom.xml | 20 ++++++++++---------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- guava-shaded/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index f03317edc03..05e9d74dc5c 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-bom pom @@ -33,47 +33,47 @@ org.apache.cassandra java-driver-core - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-core-shaded - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-mapper-processor - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-mapper-runtime - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-query-builder - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-guava-shaded - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-test-infra - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-metrics-micrometer - 4.19.1-SNAPSHOT + 4.19.1 org.apache.cassandra java-driver-metrics-microprofile - 4.19.1-SNAPSHOT + 4.19.1 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 451db1dcd1b..4cc8197b6dd 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index b8d7d5c2d3b..9ed02b81dd7 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index e930f4c0610..5328b4bbd36 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index 1c762074673..c4b5eb38026 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 8f7740e148f..4c5f04de515 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 15f082e6864..a473320ea44 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.19.1-SNAPSHOT + 4.19.1 java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index ed37e861a96..62c1c5fc799 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-guava-shaded Apache Cassandra Java Driver - guava shaded dep diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index b489076c257..16661191427 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 519f1411ce9..d7aaa7f9d67 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 3a767c2a352..af2936a3805 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 091bb5f3e93..3dd89d1737b 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 5163b5366f4..cca6eafc603 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 4b41f790145..e60981f7fc8 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 2cfeb65e757..355449acf0e 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1055,7 +1055,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.19.1 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 0bc46f9bb91..1860cf65d12 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index b0808757ce4..e61f4f2826b 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1-SNAPSHOT + 4.19.1 java-driver-test-infra bundle From f63108175fd22e2db893c57b0975bc518977ab4b Mon Sep 17 00:00:00 2001 From: Andy Tolbert <6889771+tolbertam@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:32:41 -0500 Subject: [PATCH 387/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 20 ++++++++++---------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- guava-shaded/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 05e9d74dc5c..fab36abad4c 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-bom pom @@ -33,47 +33,47 @@ org.apache.cassandra java-driver-core - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-core-shaded - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-mapper-processor - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-mapper-runtime - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-query-builder - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-guava-shaded - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-test-infra - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-metrics-micrometer - 4.19.1 + 4.19.2-SNAPSHOT org.apache.cassandra java-driver-metrics-microprofile - 4.19.1 + 4.19.2-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 4cc8197b6dd..617664eec97 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index 9ed02b81dd7..e750b791d3b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index 5328b4bbd36..27d6d026a4d 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index c4b5eb38026..fbf8cd21076 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 4c5f04de515..498d5dc603a 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index a473320ea44..df1e2b2613b 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.19.1 + 4.19.2-SNAPSHOT java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index 62c1c5fc799..ad581bc0f98 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-guava-shaded Apache Cassandra Java Driver - guava shaded dep diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 16661191427..8360c8a211f 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index d7aaa7f9d67..5368c24c2b6 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index af2936a3805..a21254da908 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 3dd89d1737b..08211d04c2b 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index cca6eafc603..95c1ca9bb42 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index e60981f7fc8..abb54e159f6 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 355449acf0e..4e3d7006169 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1055,7 +1055,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.19.1 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index 1860cf65d12..e1db8485799 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index e61f4f2826b..1a73cde23cd 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.1 + 4.19.2-SNAPSHOT java-driver-test-infra bundle From 8f69c24d6cd6db75c6811fc32ee9ab39121ecaa6 Mon Sep 17 00:00:00 2001 From: janehe Date: Mon, 10 Nov 2025 12:50:59 -0800 Subject: [PATCH 388/395] CASSJAVA-116: Retry or Speculative Execution with RequestIdGenerator throws "Duplicate Key" patch by Jane He; reviewed by Andy Tolbert and Lukasz Atoniak for CASSJAVA-116 --- .../api/core/tracker/RequestIdGenerator.java | 29 +++++---- .../core/cql/CqlRequestHandlerRetryTest.java | 63 +++++++++++++++++++ .../core/cql/RequestHandlerTestHarness.java | 10 ++- .../core/tracker/RequestIdGeneratorIT.java | 21 ++++++- 4 files changed, 110 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java index 59ac3fdacf7..21db3793b01 100644 --- a/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java +++ b/core/src/main/java/com/datastax/oss/driver/api/core/tracker/RequestIdGenerator.java @@ -19,20 +19,21 @@ import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.session.Request; -import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap; import edu.umd.cs.findbugs.annotations.NonNull; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; /** * Interface responsible for generating request IDs. * - *

    Note that all request IDs have a parent/child relationship. A "parent ID" can loosely be - * thought of as encompassing a sequence of a request + any attendant retries, speculative + *

    Note that all request IDs have a parent/child relationship. A "session request ID" can loosely + * be thought of as encompassing a sequence of a request + any attendant retries, speculative * executions etc. It's scope is identical to that of a {@link - * com.datastax.oss.driver.internal.core.cql.CqlRequestHandler}. A "request ID" represents a single - * request within this larger scope. Note that a request corresponding to a request ID may be + * com.datastax.oss.driver.internal.core.cql.CqlRequestHandler}. A "node request ID" represents a + * single request within this larger scope. Note that a request corresponding to a request ID may be * retried; in that case the retry count will be appended to the corresponding identifier in the * logs. */ @@ -67,11 +68,17 @@ default String getCustomPayloadKey() { default Statement getDecoratedStatement( @NonNull Statement statement, @NonNull String requestId) { - Map customPayload = - NullAllowingImmutableMap.builder() - .putAll(statement.getCustomPayload()) - .put(getCustomPayloadKey(), ByteBuffer.wrap(requestId.getBytes(StandardCharsets.UTF_8))) - .build(); - return statement.setCustomPayload(customPayload); + + Map existing = new HashMap<>(statement.getCustomPayload()); + String key = getCustomPayloadKey(); + + // Add or overwrite + existing.put(key, ByteBuffer.wrap(requestId.getBytes(StandardCharsets.UTF_8))); + + // Allowing null key/values + // Wrap a map inside to be immutable without instanciating a new map + Map unmodifiableMap = Collections.unmodifiableMap(existing); + + return statement.setCustomPayload(unmodifiableMap); } } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java index bea52891c18..ccac873c616 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerRetryTest.java @@ -48,6 +48,8 @@ import com.datastax.oss.driver.api.core.servererrors.ServerError; import com.datastax.oss.driver.api.core.servererrors.UnavailableException; import com.datastax.oss.driver.api.core.servererrors.WriteTimeoutException; +import com.datastax.oss.driver.api.core.session.Request; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.protocol.internal.ProtocolConstants; import com.datastax.oss.protocol.internal.response.Error; import com.datastax.oss.protocol.internal.response.error.ReadTimeout; @@ -55,9 +57,13 @@ import com.datastax.oss.protocol.internal.response.error.WriteTimeout; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; public class CqlRequestHandlerRetryTest extends CqlRequestHandlerTestBase { @@ -384,6 +390,63 @@ public void should_rethrow_error_if_not_idempotent_and_error_unsafe_or_policy_re } } + @Test + @UseDataProvider("failureAndIdempotent") + public void should_not_fail_with_duplicate_key_when_retrying_with_request_id_generator( + FailureScenario failureScenario, boolean defaultIdempotence, Statement statement) { + + // Create a RequestIdGenerator that uses the same key as the statement's custom payload + RequestIdGenerator requestIdGenerator = + new RequestIdGenerator() { + private AtomicInteger counter = new AtomicInteger(0); + + @Override + public String getSessionRequestId() { + return "session-123"; + } + + @Override + public String getNodeRequestId(@NonNull Request request, @NonNull String parentId) { + return parentId + "-" + counter.getAndIncrement(); + } + }; + + RequestHandlerTestHarness.Builder harnessBuilder = + RequestHandlerTestHarness.builder() + .withDefaultIdempotence(defaultIdempotence) + .withRequestIdGenerator(requestIdGenerator); + failureScenario.mockRequestError(harnessBuilder, node1); + harnessBuilder.withResponse(node2, defaultFrameOf(singleRow())); + + try (RequestHandlerTestHarness harness = harnessBuilder.build()) { + failureScenario.mockRetryPolicyVerdict( + harness.getContext().getRetryPolicy(anyString()), RetryVerdict.RETRY_NEXT); + + CompletionStage resultSetFuture = + new CqlRequestHandler(statement, harness.getSession(), harness.getContext(), "test") + .handle(); + + // The test should succeed without throwing a duplicate key exception + assertThatStage(resultSetFuture) + .isSuccess( + resultSet -> { + Iterator rows = resultSet.currentPage().iterator(); + assertThat(rows.hasNext()).isTrue(); + assertThat(rows.next().getString("message")).isEqualTo("hello, world"); + + ExecutionInfo executionInfo = resultSet.getExecutionInfo(); + assertThat(executionInfo.getCoordinator()).isEqualTo(node2); + assertThat(executionInfo.getErrors()).hasSize(1); + assertThat(executionInfo.getErrors().get(0).getKey()).isEqualTo(node1); + + // Verify that the custom payload still contains the request ID key + // (either the original value or the generated one, depending on implementation) + assertThat(executionInfo.getRequest().getCustomPayload().get("request-id")) + .isEqualTo(ByteBuffer.wrap("session-123-1".getBytes(StandardCharsets.UTF_8))); + }); + } + } + /** * Sets up the mocks to simulate an error from a node, and make the retry policy return a given * decision for that error. diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java index 6ecd6111992..6a7657d5809 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java @@ -37,6 +37,7 @@ import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.api.core.specex.SpeculativeExecutionPolicy; import com.datastax.oss.driver.api.core.time.TimestampGenerator; +import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; import com.datastax.oss.driver.internal.core.DefaultConsistencyLevelRegistry; import com.datastax.oss.driver.internal.core.ProtocolFeature; @@ -170,7 +171,8 @@ protected RequestHandlerTestHarness(Builder builder) { when(context.getRequestTracker()).thenReturn(new NoopRequestTracker(context)); - when(context.getRequestIdGenerator()).thenReturn(Optional.empty()); + when(context.getRequestIdGenerator()) + .thenReturn(Optional.ofNullable(builder.requestIdGenerator)); } public DefaultSession getSession() { @@ -203,6 +205,7 @@ public static class Builder { private final List poolBehaviors = new ArrayList<>(); private boolean defaultIdempotence; private ProtocolVersion protocolVersion; + private RequestIdGenerator requestIdGenerator; /** * Sets the given node as the next one in the query plan; an empty pool will be simulated when @@ -258,6 +261,11 @@ public Builder withProtocolVersion(ProtocolVersion protocolVersion) { return this; } + public Builder withRequestIdGenerator(RequestIdGenerator requestIdGenerator) { + this.requestIdGenerator = requestIdGenerator; + return this; + } + /** * Sets the given node as the next one in the query plan; the test code is responsible of * calling the methods on the returned object to complete the write and the query. diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java index 2848a8fb629..516a62bb1f7 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/tracker/RequestIdGeneratorIT.java @@ -17,12 +17,14 @@ */ package com.datastax.oss.driver.core.tracker; +import static com.datastax.oss.driver.Assertions.assertThatStage; import static org.assertj.core.api.Assertions.assertThat; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.tracker.RequestIdGenerator; @@ -119,7 +121,24 @@ public void should_not_write_id_to_custom_payload_when_key_is_not_set() { try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { String query = "SELECT * FROM system.local"; ResultSet rs = session.execute(query); - assertThat(rs.getExecutionInfo().getRequest().getCustomPayload().get("trace_key")).isNull(); + assertThat(rs.getExecutionInfo().getRequest().getCustomPayload().get("request-id")).isNull(); + } + } + + @Test + public void should_succeed_with_null_value_in_custom_payload() { + DriverConfigLoader loader = + SessionUtils.configLoaderBuilder() + .withString( + DefaultDriverOption.REQUEST_ID_GENERATOR_CLASS, "W3CContextRequestIdGenerator") + .build(); + try (CqlSession session = SessionUtils.newSession(ccmRule, loader)) { + String query = "SELECT * FROM system.local"; + Map customPayload = + new NullAllowingImmutableMap.Builder(1).put("my_key", null).build(); + SimpleStatement statement = + SimpleStatement.newInstance(query).setCustomPayload(customPayload); + assertThatStage(session.executeAsync(statement)).isSuccess(); } } } From 19c60c08b9eecbcfba3c61564bbe15bf3115089a Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Wed, 12 Nov 2025 18:31:56 -0600 Subject: [PATCH 389/395] Changelog updates for 4.19.2 patch by Bret McGuire; reviewed by Lukasz Antoniak and Andy Tolbert reference: https://github.com/apache/cassandra-java-driver/pull/2062 --- changelog/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog/README.md b/changelog/README.md index 9e223318e65..b01c3db3bf9 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -21,6 +21,10 @@ under the License. +### 4.19.2 + +- [bug] CASSJAVA-116: Retry or Speculative Execution with RequestIdGenerator throws "Duplicate Key" + ### 4.19.1 - [improvement] CASSJAVA-97: Let users inject an ID for each request and write to the custom payload From 30b05bd7991617b212b8089787fe9ca829d00154 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 13 Nov 2025 12:02:08 -0600 Subject: [PATCH 390/395] [maven-release-plugin] prepare release 4.19.2 --- bom/pom.xml | 20 ++++++++++---------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- guava-shaded/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index fab36abad4c..2e6e476d02a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-bom pom @@ -33,47 +33,47 @@ org.apache.cassandra java-driver-core - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-core-shaded - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-mapper-processor - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-mapper-runtime - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-query-builder - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-guava-shaded - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-test-infra - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-metrics-micrometer - 4.19.2-SNAPSHOT + 4.19.2 org.apache.cassandra java-driver-metrics-microprofile - 4.19.2-SNAPSHOT + 4.19.2 com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 617664eec97..b8e56b89b82 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index e750b791d3b..d8a058537f2 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index 27d6d026a4d..71600fbee2c 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index fbf8cd21076..0c2d802266e 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index 498d5dc603a..fc8d3ac0f8e 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index df1e2b2613b..29c1aa42001 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.19.2-SNAPSHOT + 4.19.2 java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index ad581bc0f98..2da3da4024f 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-guava-shaded Apache Cassandra Java Driver - guava shaded dep diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 8360c8a211f..bf122a19e35 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index 5368c24c2b6..baa2e42c539 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index a21254da908..5076a146901 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index 08211d04c2b..c5eeee518da 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 95c1ca9bb42..1c6359d2cdd 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index abb54e159f6..2fb5f3cb27f 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index 4e3d7006169..c37285e5f7c 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1055,7 +1055,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - HEAD + 4.19.2 diff --git a/query-builder/pom.xml b/query-builder/pom.xml index e1db8485799..a62c800cbd3 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 1a73cde23cd..0f24f638047 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2-SNAPSHOT + 4.19.2 java-driver-test-infra bundle From 62eade21bfeb16a12ce71013fbaebf1c19b5ae96 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 13 Nov 2025 12:02:11 -0600 Subject: [PATCH 391/395] [maven-release-plugin] prepare for next development iteration --- bom/pom.xml | 20 ++++++++++---------- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- distribution-source/pom.xml | 2 +- distribution-tests/pom.xml | 2 +- distribution/pom.xml | 2 +- examples/pom.xml | 2 +- guava-shaded/pom.xml | 2 +- integration-tests/pom.xml | 2 +- mapper-processor/pom.xml | 2 +- mapper-runtime/pom.xml | 2 +- metrics/micrometer/pom.xml | 2 +- metrics/microprofile/pom.xml | 2 +- osgi-tests/pom.xml | 2 +- pom.xml | 4 ++-- query-builder/pom.xml | 2 +- test-infra/pom.xml | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bom/pom.xml b/bom/pom.xml index 2e6e476d02a..dd76153a9b1 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-bom pom @@ -33,47 +33,47 @@ org.apache.cassandra java-driver-core - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-core-shaded - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-mapper-processor - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-mapper-runtime - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-query-builder - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-guava-shaded - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-test-infra - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-metrics-micrometer - 4.19.2 + 4.19.3-SNAPSHOT org.apache.cassandra java-driver-metrics-microprofile - 4.19.2 + 4.19.3-SNAPSHOT com.datastax.oss diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index b8e56b89b82..3727ab9422d 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-core-shaded Apache Cassandra Java Driver - core with shaded deps diff --git a/core/pom.xml b/core/pom.xml index d8a058537f2..089e15cd933 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-core bundle diff --git a/distribution-source/pom.xml b/distribution-source/pom.xml index 71600fbee2c..4c1f11e53a8 100644 --- a/distribution-source/pom.xml +++ b/distribution-source/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-distribution-source pom diff --git a/distribution-tests/pom.xml b/distribution-tests/pom.xml index 0c2d802266e..9cef313f8a5 100644 --- a/distribution-tests/pom.xml +++ b/distribution-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-distribution-tests Apache Cassandra Java Driver - distribution tests diff --git a/distribution/pom.xml b/distribution/pom.xml index fc8d3ac0f8e..20b9afc1bcd 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-distribution diff --git a/examples/pom.xml b/examples/pom.xml index 29c1aa42001..12e42dfdf53 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ java-driver-parent org.apache.cassandra - 4.19.2 + 4.19.3-SNAPSHOT java-driver-examples Apache Cassandra Java Driver - examples. diff --git a/guava-shaded/pom.xml b/guava-shaded/pom.xml index 2da3da4024f..da2e82e0ab0 100644 --- a/guava-shaded/pom.xml +++ b/guava-shaded/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-guava-shaded Apache Cassandra Java Driver - guava shaded dep diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index bf122a19e35..34cb3ef7063 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-integration-tests jar diff --git a/mapper-processor/pom.xml b/mapper-processor/pom.xml index baa2e42c539..04d8c98c4f0 100644 --- a/mapper-processor/pom.xml +++ b/mapper-processor/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-mapper-processor Apache Cassandra Java Driver - object mapper processor diff --git a/mapper-runtime/pom.xml b/mapper-runtime/pom.xml index 5076a146901..57fbd5d3432 100644 --- a/mapper-runtime/pom.xml +++ b/mapper-runtime/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-mapper-runtime bundle diff --git a/metrics/micrometer/pom.xml b/metrics/micrometer/pom.xml index c5eeee518da..37ba8556a53 100644 --- a/metrics/micrometer/pom.xml +++ b/metrics/micrometer/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT ../../ java-driver-metrics-micrometer diff --git a/metrics/microprofile/pom.xml b/metrics/microprofile/pom.xml index 1c6359d2cdd..9893711d340 100644 --- a/metrics/microprofile/pom.xml +++ b/metrics/microprofile/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT ../../ java-driver-metrics-microprofile diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 2fb5f3cb27f..bd3a6380d6b 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-osgi-tests jar diff --git a/pom.xml b/pom.xml index c37285e5f7c..6834cdd1882 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT pom Apache Cassandra Java Driver https://github.com/datastax/java-driver @@ -1055,7 +1055,7 @@ limitations under the License.]]> scm:git:git@github.com:datastax/java-driver.git scm:git:git@github.com:datastax/java-driver.git https://github.com/datastax/java-driver - 4.19.2 + HEAD diff --git a/query-builder/pom.xml b/query-builder/pom.xml index a62c800cbd3..2bfe1bee8f5 100644 --- a/query-builder/pom.xml +++ b/query-builder/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-query-builder bundle diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 0f24f638047..5bf2d07f652 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -23,7 +23,7 @@ org.apache.cassandra java-driver-parent - 4.19.2 + 4.19.3-SNAPSHOT java-driver-test-infra bundle From a7da99556b6c202eecc6d5cb1c6371492729ab49 Mon Sep 17 00:00:00 2001 From: absurdfarce Date: Thu, 4 Dec 2025 12:04:26 -0600 Subject: [PATCH 392/395] Removing interface to Travis CI Patch by Bret McGuire; reviewed by Andy Tolbert and Bret McGuire reference: https://github.com/apache/cassandra-java-driver/pull/2066 --- .travis.yml | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 84d40ce1356..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -language: java -dist: trusty -sudo: false -# see https://sormuras.github.io/blog/2018-03-20-jdk-matrix.html -matrix: - include: - # 8 - - env: JDK='OpenJDK 8' - jdk: openjdk8 - # 11 - - env: JDK='OpenJDK 11' - # switch to JDK 11 before running tests - before_script: . $TRAVIS_BUILD_DIR/ci/install-jdk.sh -F 11 -L GPL -before_install: - # Require JDK8 for compiling - - jdk_switcher use openjdk8 - - ./install-snapshots.sh -install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -script: mvn test -Djacoco.skip=true -Dmaven.test.failure.ignore=true -Dmaven.javadoc.skip=true -B -V -cache: - directories: - - $HOME/.m2 From ded2985f14e9774cb46dd0104b1f045613bc0279 Mon Sep 17 00:00:00 2001 From: "April I. Murphy" <36110273+aimurphy@users.noreply.github.com> Date: Thu, 20 Nov 2025 08:21:36 -0800 Subject: [PATCH 393/395] Replace outdated link in README patch by April Murphy; reviewed by Bret McGuire and Lukasz Antoniak reference: https://github.com/apache/cassandra-java-driver/pull/2064 --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 0f6c2bb5a6f..5994a4be8a1 100644 --- a/README.md +++ b/README.md @@ -67,10 +67,6 @@ remain unchanged, and the new API will look very familiar to 2.x and 3.x users. See the [upgrade guide](upgrade_guide/) for details. -## Error Handling - -See the [Cassandra error handling done right blog](https://www.datastax.com/blog/cassandra-error-handling-done-right) for error handling with the Java Driver for Apache Cassandra™. - ## Useful links * [Manual](manual/) From e762df872b7ca02b4cd5cf780bd96f77815c9646 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Fri, 19 Dec 2025 13:13:18 +0100 Subject: [PATCH 394/395] ninja-fix: Remove ASF donation message --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5994a4be8a1..d8ef01d0964 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Java Driver for Apache Cassandra® -:warning: The java-driver has recently been donated by Datastax to The Apache Software Foundation and the Apache Cassandra project. Bear with us as we move assets and coordinates. - [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.cassandra/java-driver-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.cassandra/java-driver-core) From 595cb29912dc8b55663cc13bafe3f17dc4f91ce6 Mon Sep 17 00:00:00 2001 From: Abe Ratnofsky Date: Mon, 22 Dec 2025 22:20:20 -0800 Subject: [PATCH 395/395] Update LZ4 and Netty dependencies for CVE response The primary goal here is to address CVE-2025-12183. Netty includes a dependency on vulnerable versions of lz4-java, so update to a fixed version of Netty as well. On the C* server side, we opted to move to the new community fork of lz4-java, so match that decision here (CASSANDRA-21052). patch by Abe Ratnofsky; reviewed by Francisco Guerrero for CASSJAVA-113 --- NOTICE_binary.txt | 2 +- core-shaded/pom.xml | 2 +- core/pom.xml | 2 +- core/src/main/resources/reference.conf | 2 +- .../internal/core/insights/PlatformInfoFinderTest.java | 2 +- core/src/test/resources/insights/test-dependencies.txt | 2 +- integration-tests/pom.xml | 2 +- manual/core/compression/README.md | 6 +++--- manual/core/integration/README.md | 2 +- osgi-tests/pom.xml | 2 +- .../oss/driver/internal/osgi/support/BundleOptions.java | 2 +- pom.xml | 6 +++--- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/NOTICE_binary.txt b/NOTICE_binary.txt index c60d8ceb245..f6f11c298f6 100644 --- a/NOTICE_binary.txt +++ b/NOTICE_binary.txt @@ -100,7 +100,7 @@ and decompression library written by Adrien Grand. It can be obtained at: * LICENSE: * license/LICENSE.lz4.txt (Apache License 2.0) * HOMEPAGE: - * https://github.com/jpountz/lz4-java + * https://github.com/yawkat/lz4-java This product optionally depends on 'lzma-java', a LZMA Java compression and decompression library, which can be obtained at: diff --git a/core-shaded/pom.xml b/core-shaded/pom.xml index 3727ab9422d..84cb4b15398 100644 --- a/core-shaded/pom.xml +++ b/core-shaded/pom.xml @@ -74,7 +74,7 @@ true - org.lz4 + at.yawk.lz4 lz4-java true diff --git a/core/pom.xml b/core/pom.xml index 089e15cd933..8758d20d78a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -73,7 +73,7 @@ true - org.lz4 + at.yawk.lz4 lz4-java true diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 741b1d97654..4ae83362e29 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1114,7 +1114,7 @@ datastax-java-driver { # The name of the algorithm used to compress protocol frames. # # The possible values are: - # - lz4: requires net.jpountz.lz4:lz4 in the classpath. + # - lz4: requires at.yawk.lz4:lz4-java in the classpath. # - snappy: requires org.xerial.snappy:snappy-java in the classpath. # - the string "none" to indicate no compression (this is functionally equivalent to omitting # the option). diff --git a/core/src/test/java/com/datastax/dse/driver/internal/core/insights/PlatformInfoFinderTest.java b/core/src/test/java/com/datastax/dse/driver/internal/core/insights/PlatformInfoFinderTest.java index 80294ea6b7d..2a098363d46 100644 --- a/core/src/test/java/com/datastax/dse/driver/internal/core/insights/PlatformInfoFinderTest.java +++ b/core/src/test/java/com/datastax/dse/driver/internal/core/insights/PlatformInfoFinderTest.java @@ -77,7 +77,7 @@ public void should_find_dependencies_from_file() { "com.fasterxml.jackson.core:jackson-annotations", withUnverifiedRuntimeVersion("2.8.11")); expected.put("com.fasterxml.jackson.core:jackson-core", withUnverifiedRuntimeVersion("2.8.11")); expected.put("io.netty:netty-handler", withUnverifiedRuntimeVersion("4.0.56.Final")); - expected.put("org.lz4:lz4-java", withUnverifiedRuntimeVersionOptional("1.4.1")); + expected.put("at.yawk.lz4:lz4-java", withUnverifiedRuntimeVersionOptional("1.10.1")); expected.put("org.hdrhistogram:HdrHistogram", withUnverifiedRuntimeVersionOptional("2.1.10")); expected.put("com.github.jnr:jffi", withUnverifiedRuntimeVersion("1.2.16")); expected.put("io.netty:netty-buffer", withUnverifiedRuntimeVersion("4.0.56.Final")); diff --git a/core/src/test/resources/insights/test-dependencies.txt b/core/src/test/resources/insights/test-dependencies.txt index 6cabe8b257d..e9186a35e6b 100644 --- a/core/src/test/resources/insights/test-dependencies.txt +++ b/core/src/test/resources/insights/test-dependencies.txt @@ -17,7 +17,7 @@ The following files have been resolved: com.fasterxml.jackson.core:jackson-core:jar:2.8.11:compile org.hdrhistogram:HdrHistogram:jar:2.1.10:compile (optional) org.ow2.asm:asm-tree:jar:5.0.3:compile - org.lz4:lz4-java:jar:1.4.1:compile (optional) + at.yawk.lz4:lz4-java:jar:1.10.1:compile (optional) io.netty:netty-transport:jar:4.0.56.Final:compile io.dropwizard.metrics:metrics-core:jar:3.2.2:compile io.netty:netty-common:jar:4.0.56.Final:compile diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 34cb3ef7063..e302e12077f 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -129,7 +129,7 @@ test - org.lz4 + at.yawk.lz4 lz4-java test diff --git a/manual/core/compression/README.md b/manual/core/compression/README.md index 9e84fde917d..9f7ae3c4854 100644 --- a/manual/core/compression/README.md +++ b/manual/core/compression/README.md @@ -46,7 +46,7 @@ datastax-java-driver { Compression must be set before opening a session, it cannot be changed at runtime. -Two algorithms are supported out of the box: [LZ4](https://github.com/jpountz/lz4-java) and +Two algorithms are supported out of the box: [LZ4](https://github.com/yawkat/lz4-java) and [Snappy](http://google.github.io/snappy/). The LZ4 implementation is a good first choice; it offers fallback implementations in case native libraries fail to load and [benchmarks](http://java-performance.info/performance-general-compression/) suggest that it offers @@ -63,9 +63,9 @@ Dependency: ```xml - org.lz4 + at.yawk.lz4 lz4-java - 1.4.1 + 1.10.1 ``` diff --git a/manual/core/integration/README.md b/manual/core/integration/README.md index f2a96160bce..e2c7bc218ee 100644 --- a/manual/core/integration/README.md +++ b/manual/core/integration/README.md @@ -416,7 +416,7 @@ are not available on your platform, you can exclude the following dependency: #### Compression libraries -The driver supports compression with either [LZ4](https://github.com/jpountz/lz4-java) or +The driver supports compression with either [LZ4](https://github.com/yawkat/lz4-java) or [Snappy](http://google.github.io/snappy/). These dependencies are optional; you have to add them explicitly in your application in order to diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index bd3a6380d6b..c2cc4d830f1 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -79,7 +79,7 @@ snappy-java - org.lz4 + at.yawk.lz4 lz4-java diff --git a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java index 3e6171ca530..378b515aa65 100644 --- a/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java +++ b/osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/BundleOptions.java @@ -117,7 +117,7 @@ public static CompositeOption jacksonBundles() { public static CompositeOption lz4Bundle() { return () -> options( - mavenBundle("org.lz4", "lz4-java").versionAsInProject(), + mavenBundle("at.yawk.lz4", "lz4-java").versionAsInProject(), systemProperty("cassandra.compression").value("LZ4")); } diff --git a/pom.xml b/pom.xml index 6834cdd1882..eb83459cfb4 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 2.1.12 4.1.18 - 4.1.119.Final + 4.1.130.Final 1.2.1 1.1.10.1 - 1.7.1 + 1.10.1 3.19.0 1.3 @@ -137,7 +137,7 @@ ${snappy.version} - org.lz4 + at.yawk.lz4 lz4-java ${lz4.version}