From e8b25ab368a5cc8a59983ca8bd7b2020d07b19bd Mon Sep 17 00:00:00 2001 From: hhughes Date: Thu, 20 Jul 2023 12:16:13 -0700 Subject: [PATCH 001/130] 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 002/130] 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 003/130] 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 004/130] 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 005/130] 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 006/130] 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 007/130] 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 008/130] 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 009/130] 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 010/130] 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 011/130] 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 012/130] 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 013/130] 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 014/130] 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 015/130] 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 016/130] 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 017/130] =?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 018/130] 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 021/130] 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 022/130] 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 023/130] 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 024/130] 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 025/130] [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 026/130] [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 027/130] 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 028/130] 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 029/130] 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 030/130] 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 031/130] 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 032/130] 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 033/130] 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 034/130] 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 035/130] 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 036/130] 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 037/130] 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 038/130] 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 039/130] 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 040/130] 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 041/130] 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 042/130] 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 043/130] 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 044/130] 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 { 4.0 - Apache Cassandra® v4.x (CURRENTLY UNDER DEVELOPMENT) + Apache Cassandra® v4.0.x + + + 4.1 + Apache Cassandra® v4.1.x dse-4.8.16 @@ -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 045/130] 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 046/130] 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 047/130] 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 048/130] 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 049/130] 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 050/130] 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 051/130] [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 052/130] [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 053/130] 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 054/130] 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 055/130] 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 056/130] 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 057/130] 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 058/130] 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 059/130] 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 060/130] 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 061/130] 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 @@ -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 062/130] 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 063/130] 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 064/130] 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 065/130] 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 066/130] 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 067/130] 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 068/130] 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 069/130] 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 070/130] 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 071/130] 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 072/130] 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 073/130] 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 074/130] 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 075/130] 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 076/130] 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 077/130] 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 078/130] 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 079/130] 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 080/130] 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 081/130] 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 082/130] 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 083/130] 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 084/130] 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 085/130] 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 086/130] 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 087/130] 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 088/130] 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 089/130] 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 090/130] 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 091/130] 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 092/130] 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 093/130] 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 094/130] [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 095/130] [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 096/130] 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 097/130] 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 098/130] 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 099/130] 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 100/130] 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 101/130] 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 103/130] 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 104/130] 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 105/130] 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 106/130] 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 107/130] 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 108/130] 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 109/130] 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 110/130] 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 111/130] 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 112/130] 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 113/130] 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 114/130] 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 115/130] 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 116/130] 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 117/130] 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 118/130] 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 119/130] 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 120/130] 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 121/130] [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 122/130] [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 123/130] 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 124/130] 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 125/130] [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 126/130] [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 127/130] 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 128/130] 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 129/130] 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 130/130] 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}