From c2241aaa85f073e7a04d853904caad62753b131b Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Tue, 7 Apr 2026 13:33:26 +0200 Subject: [PATCH 1/4] CASSSIDECAR-421: Upgrade Java driver to 4.x --- adapters/adapters-base/build.gradle | 4 +- .../adapters/base/CassandraAdapter.java | 30 +- .../base/db/ConnectedClientStats.java | 4 +- .../ConnectedClientStatsDatabaseAccessor.java | 4 +- .../base/db/ConnectedClientStatsSummary.java | 2 +- .../db/schema/ConnectedClientsSchema.java | 6 +- .../base/db/ConnectedClientStatsTest.java | 7 +- adapters/adapters-cassandra41/build.gradle | 2 +- adapters/adapters-cassandra50/build.gradle | 2 +- build.gradle | 3 +- conf/logback.xml | 4 +- conf/sidecar.yaml | 2 +- examples/lifecycle/conf/sidecar.yaml.template | 2 +- gradle.properties | 2 +- integration-framework/build.gradle | 2 +- .../SharedClusterIntegrationTestBase.java | 37 ++- .../testing/TemporaryCqlSessionProvider.java | 105 ++++--- .../cassandra/testing/TlsTestUtils.java | 67 ++-- ...RoleBasedAuthorizationIntegrationTest.java | 28 +- .../sidecar/cdc/CdcIntegrationTest.java | 2 +- .../ClusterLeaseClaimTaskIntegrationTest.java | 26 +- ...roElectorateMembershipIntegrationTest.java | 3 +- ...SystemDatabaseAccessorIntegrationTest.java | 3 +- .../routes/CassandraStatsIntegrationTest.java | 9 +- .../InvalidateCacheIntegrationTest.java | 17 +- .../resources/config/sidecar.yaml.template | 2 +- scripts/relocate-dtest-dependencies.pom | 2 +- server-common/build.gradle | 6 +- .../com/datastax/driver/core/DriverUtils.java | 54 ++-- .../common/server/CQLSessionProvider.java | 14 +- .../common/server/ICassandraAdapter.java | 12 +- .../server/cluster/locator/TokenRange.java | 21 +- .../common/server/utils/DriverUtils.java | 40 +-- .../sidecar/db/DatabaseAccessor.java | 10 +- .../sidecar/db/LocalDatabaseAccessor.java | 10 +- .../sidecar/db/schema/AbstractSchema.java | 22 +- .../db/schema/CassandraSystemTableSchema.java | 6 +- .../sidecar/db/schema/TableSchema.java | 12 +- .../cluster/locator/TokenRangeTest.java | 30 +- server/build.gradle | 6 +- .../bridge/CassandraBridgeFactory.java | 4 +- .../cassandra/sidecar/acl/AuthCache.java | 10 +- .../sidecar/cdc/CachingSchemaStore.java | 4 +- .../sidecar/cdc/CdcAvroSerializer.java | 4 +- .../cassandra/sidecar/cdc/CdcManager.java | 3 +- .../sidecar/cdc/CdcSchemaSupplier.java | 9 +- .../sidecar/cdc/SidecarCdcOptions.java | 2 +- .../cdc/SidecarClusterConfigProvider.java | 20 +- .../cdc/StateSidecarCdcCassandraClient.java | 5 +- .../cluster/CQLSessionProviderImpl.java | 174 +++++------ .../cluster/CassandraAdapterDelegate.java | 109 ++++--- .../cluster/driver/CustomDriverOption.java | 45 +++ .../driver/MultiplexingNodeStateListener.java | 176 +++++++++++ .../driver/SidecarLoadBalancingPolicy.java | 159 ++++------ .../locator/CachedLocalTokenRanges.java | 54 ++-- .../DcLocalTopologyChangeEventCodec.java | 3 +- .../CassandraClientTokenRingProvider.java | 69 +++-- .../coordination/ClusterLeaseClaimTask.java | 6 +- .../ContentionFreeRangeManager.java | 3 +- .../InnerDcTokenAdjacentPeerProvider.java | 64 ++-- ...KeyspaceTokenZeroElectorateMembership.java | 14 +- .../sidecar/coordination/RangeManager.java | 23 +- .../coordination/TokenRingProvider.java | 11 +- .../datahub/ClusterToAspectConverter.java | 2 +- .../ClusterToDataPlatformInfoConverter.java | 2 +- ...taPlatformInstancePropertiesConverter.java | 2 +- .../sidecar/datahub/IdentifiersProvider.java | 6 +- .../datahub/KeyspaceToAspectConverter.java | 2 +- .../KeyspaceToBrowsePathsV2Converter.java | 2 +- ...eyspaceToContainerPropertiesConverter.java | 4 +- ...yspaceToDataPlatformInstanceConverter.java | 2 +- .../datahub/KeyspaceToSubTypesConverter.java | 2 +- .../sidecar/datahub/SchemaReporter.java | 27 +- .../sidecar/datahub/SchemaReportingTask.java | 2 +- .../datahub/TableToAspectConverter.java | 6 +- .../datahub/TableToBrowsePathsConverter.java | 8 +- .../TableToBrowsePathsV2Converter.java | 8 +- .../datahub/TableToContainerConverter.java | 8 +- .../TableToDataPlatformInstanceConverter.java | 6 +- .../TableToDatasetPropertiesConverter.java | 15 +- .../TableToSchemaMetadataConverter.java | 120 ++++--- .../datahub/TableToSubTypesConverter.java | 6 +- .../sidecar/db/CdcDatabaseAccessor.java | 54 ++-- .../sidecar/db/ConfigAccessorImpl.java | 6 +- .../cassandra/sidecar/db/RestoreJob.java | 22 +- .../db/RestoreJobDatabaseAccessor.java | 48 +-- .../cassandra/sidecar/db/RestoreRange.java | 8 +- .../db/RestoreRangeDatabaseAccessor.java | 7 +- .../cassandra/sidecar/db/RestoreSlice.java | 8 +- .../db/RestoreSliceDatabaseAccessor.java | 6 +- .../cassandra/sidecar/db/ServiceConfig.java | 3 +- .../db/SidecarLeaseDatabaseAccessor.java | 4 +- .../SidecarPermissionsDatabaseAccessor.java | 6 +- .../db/SystemAuthDatabaseAccessor.java | 12 +- .../db/SystemViewsDatabaseAccessor.java | 4 +- .../db/TableHistoryDatabaseAccessor.java | 8 +- .../db/VirtualTablesDatabaseAccessor.java | 17 +- .../sidecar/db/schema/CdcStatesSchema.java | 18 +- .../sidecar/db/schema/ConfigsSchema.java | 18 +- .../sidecar/db/schema/RestoreJobsSchema.java | 6 +- .../db/schema/RestoreRangesSchema.java | 6 +- .../db/schema/RestoreSlicesSchema.java | 6 +- .../db/schema/SidecarInternalKeyspace.java | 10 +- .../sidecar/db/schema/SidecarLeaseSchema.java | 6 +- .../schema/SidecarRolePermissionsSchema.java | 6 +- .../db/schema/SidecarSchemaInitializer.java | 4 +- .../sidecar/db/schema/SystemAuthSchema.java | 14 +- .../sidecar/db/schema/SystemViewsSchema.java | 6 +- .../sidecar/db/schema/TableHistorySchema.java | 21 +- .../handlers/KeyspaceSchemaHandler.java | 8 +- .../handlers/LifecycleUpdateHandler.java | 6 +- .../handlers/NodeDecommissionHandler.java | 4 +- .../sidecar/handlers/NodeDrainHandler.java | 4 +- .../sidecar/handlers/NodeMoveHandler.java | 4 +- .../sidecar/handlers/RepairHandler.java | 4 +- .../sidecar/handlers/ReportSchemaHandler.java | 2 +- .../restore/UpdateRestoreJobHandler.java | 4 +- .../sstableuploads/SSTableUploadHandler.java | 2 +- .../ValidateTableExistenceHandler.java | 14 +- .../cassandra/sidecar/job/OperationalJob.java | 4 +- .../livemigration/DataCopyTaskManager.java | 4 +- .../sidecar/modules/ConfigurationModule.java | 2 - .../sidecar/restore/RestoreJobDiscoverer.java | 11 +- .../sidecar/restore/RestoreJobUtil.java | 4 +- .../sidecar/routes/RoutingContextUtils.java | 4 +- .../tasks/CdcConfigRefresherNotifierTask.java | 3 +- .../sidecar/tasks/ClusterTopologyMonitor.java | 6 +- .../sidecar/utils/MetadataUtils.java | 43 ++- .../sidecar/utils/TokenSplitUtil.java | 8 +- .../sidecar/restore/StorageClientTest.java | 6 +- ...utualTLSAuthenticationIntegrationTest.java | 6 +- .../SidecarLoadBalancingPolicyTest.java | 17 +- .../SchemaReporterIntegrationTest.java | 12 +- .../db/RestoreJobDatabaseAccessorIntTest.java | 6 +- .../RestoreRangeDatabaseAccessorIntTest.java | 6 +- .../RestoreSliceDatabaseAccessorIntTest.java | 6 +- .../sidecar/restore/RestoreJobTestUtils.java | 4 +- ...estoreJobDiscovererNodeLeavingIntTest.java | 4 +- ...STableComponentHandlerIntegrationTest.java | 4 +- .../CreateSnapshotHandlerIntegrationTest.java | 6 +- .../ListSnapshotHandlerIntegrationTest.java | 6 +- .../SSTableImportHandlerIntegrationTest.java | 14 +- .../routes/tokenrange/JoiningMultiDCTest.java | 9 +- .../routes/tokenrange/LeavingTest.java | 3 +- .../routes/tokenrange/LeavingTestMultiDC.java | 6 +- .../MultiDCSingleReplicatedJoiningTest.java | 16 +- .../tokenrange/ReplacementMultiDCTest.java | 13 +- .../testing/CassandraSidecarTestContext.java | 12 +- .../sidecar/testing/IntegrationTestBase.java | 24 +- .../testing/IntegrationTestModule.java | 17 +- .../testing/CassandraTestTemplate.java | 6 +- .../ConfigurableCassandraTestContext.java | 3 +- .../sidecar/TestCassandraAdapterDelegate.java | 2 +- .../apache/cassandra/sidecar/TestModule.java | 14 +- .../MutualTLSAuthenticationHandlerTest.java | 15 +- ...ReloadingJwtAuthenticationHandlerTest.java | 11 +- .../RoleBasedAuthorizationProviderTest.java | 2 +- .../cluster/CassandraAdapterDelegateTest.java | 45 +-- .../CassandraClientTokenRingProviderTest.java | 292 ++++++++++-------- ...InnerDcTokenAdjacentPeerProviderTests.java | 76 +++-- .../datahub/IdentifiersProviderTest.java | 21 +- .../sidecar/datahub/SchemaReporterTest.java | 259 +++++++++------- .../BasicPermissionsDatabaseAccessorTest.java | 12 +- .../sidecar/db/CdcDatabaseAccessorTests.java | 104 ++----- .../sidecar/db/ConfigAccessorImplTest.java | 14 +- .../db/RestoreJobDatabaseAccessorTest.java | 10 +- .../cassandra/sidecar/db/RestoreJobTest.java | 12 +- .../sidecar/db/RestoreSliceTest.java | 20 +- .../sidecar/db/SidecarSchemaTest.java | 39 ++- .../sidecar/db/SystemAuthSchemaTest.java | 17 +- .../ListOperationalJobsHandlerTest.java | 6 +- .../handlers/OperationalJobHandlerTest.java | 10 +- .../sidecar/handlers/RepairHandlerTest.java | 11 +- .../handlers/ReportSchemaHandlerTest.java | 4 +- .../sidecar/handlers/SchemaHandlerTest.java | 16 +- .../handlers/TableStatsHandlerTest.java | 16 +- .../LiveMigrationDataCopyTaskHandlerTest.java | 3 +- .../restore/CreateRestoreJobHandlerTest.java | 4 +- .../restore/RestoreJobSummaryHandlerTest.java | 10 +- .../BaseUploadsHandlerTest.java | 11 +- .../InMemoryOperationalJobTrackerTest.java | 6 +- .../sidecar/job/NodeDrainJobTest.java | 4 +- .../sidecar/job/NodeMoveJobTest.java | 4 +- .../job/OperationalJobManagerTest.java | 6 +- .../sidecar/job/OperationalJobTest.java | 14 +- .../cassandra/sidecar/job/RepairJobTest.java | 31 +- .../DataCopyTaskManagerTest.java | 3 +- .../LiveMigrationFileDownloaderTest.java | 5 +- .../sidecar/metrics/SchemaMetricsTest.java | 12 +- .../BaseRestoreJobProgressCollectorTest.java | 4 +- .../restore/RestoreJobDiscovererTest.java | 37 +-- .../restore/RestoreJobManagerTest.java | 18 +- .../sidecar/restore/RestoreJobUtilTest.java | 4 +- .../sidecar/restore/RestoreRangeTaskTest.java | 34 +- .../sidecar/restore/RestoreRangeTest.java | 10 +- .../restore/RingTopologyRefresherTest.java | 20 +- .../CassandraClusterSchemaMonitorTest.java | 37 ++- .../CdcRawDirectorySpaceCleanerTest.java | 3 +- .../resources/datahub/integration_test.json | 2 +- .../resources/datahub/primitive_types.json | 2 +- .../test/resources/logback-in-jvm-dtest.xml | 3 +- test-common/build.gradle | 2 +- .../testing/SharedExecutorNettyOptions.java | 72 ----- vertx-client/src/test/resources/log4j2.xml | 4 +- 204 files changed, 2139 insertions(+), 1756 deletions(-) create mode 100644 server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java create mode 100644 server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java delete mode 100644 test-common/src/testFixtures/java/org/apache/cassandra/sidecar/testing/SharedExecutorNettyOptions.java diff --git a/adapters/adapters-base/build.gradle b/adapters/adapters-base/build.gradle index 5ff2fb1dd..fd7955808 100644 --- a/adapters/adapters-base/build.gradle +++ b/adapters/adapters-base/build.gradle @@ -50,10 +50,10 @@ dependencies { api("com.google.guava:guava:${project.rootProject.guavaVersion}") compileOnly('org.jetbrains:annotations:23.0.0') - compileOnly('com.datastax.cassandra:cassandra-driver-core:3.11.3') + compileOnly('org.apache.cassandra:java-driver-core:4.19.1') implementation("org.slf4j:slf4j-api:${project.slf4jVersion}") - testImplementation('com.datastax.cassandra:cassandra-driver-core:3.11.3') + testImplementation('org.apache.cassandra:java-driver-core:4.19.1') testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junitVersion}" testImplementation "org.junit.jupiter:junit-jupiter-params:${project.junitVersion}" testImplementation "org.assertj:assertj-core:3.24.2" diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java index d8bc9eea0..09219ba47 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java @@ -22,12 +22,12 @@ import java.util.Map; import java.util.Objects; -import com.datastax.driver.core.ConsistencyLevel; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.Statement; +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.CqlSession; +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.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; import org.apache.cassandra.sidecar.common.response.NodeSettings; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.common.server.ClusterMembershipOperations; @@ -56,7 +56,7 @@ public class CassandraAdapter implements ICassandraAdapter protected final CQLSessionProvider cqlSessionProvider; protected final InetSocketAddress localNativeTransportAddress; protected final DriverUtils driverUtils; - private volatile Host host; + private volatile Node host; private final StorageOperations storageOperations; private final ClusterMembershipOperations clusterMembershipOperations; private final TableOperations tableOperations; @@ -95,7 +95,7 @@ public CassandraAdapter(DnsResolver dnsResolver, @NotNull public Metadata metadata() throws CassandraUnavailableException { - return cqlSessionProvider.get().getCluster().getMetadata(); + return cqlSessionProvider.get().getMetadata(); } /** @@ -117,13 +117,13 @@ public Map v2NodeSettings() @Override @NotNull - public ResultSet executeLocal(Statement statement) + public ResultSet executeLocal(Statement statement) { - Session activeSession = cqlSessionProvider.get(); + CqlSession activeSession = cqlSessionProvider.get(); Metadata metadata = metadata(); - Host host = getHost(metadata); - statement.setConsistencyLevel(ConsistencyLevel.ONE); - statement.setHost(host); + Node host = getHost(metadata); + statement = statement.setConsistencyLevel(ConsistencyLevel.ONE) + .setNode(host); return activeSession.execute(statement); } @@ -139,7 +139,7 @@ public InetSocketAddress localNativeTransportAddress() public InetSocketAddress localStorageBroadcastAddress() { Metadata metadata = metadata(); - return getHost(metadata).getBroadcastSocketAddress(); + return getHost(metadata).getBroadcastAddress().get(); // Maybe return null? } /** @@ -248,7 +248,7 @@ protected CompactionStatsOperations createCompactionStatsOperations(StorageOpera } @NotNull - protected Host getHost(Metadata metadata) + protected Node getHost(Metadata metadata) { if (host != null) { diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStats.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStats.java index 01bb3a378..7da5fd58c 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStats.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStats.java @@ -20,7 +20,7 @@ import java.util.Map; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.Row; import org.apache.cassandra.sidecar.db.DataObjectMappingException; import org.jetbrains.annotations.NotNull; @@ -53,7 +53,7 @@ public static ConnectedClientStats from(@NotNull Row row) throws DataObjectMappi public ConnectedClientStats(@NotNull Row row) { - this.address = row.getInet("address").getHostAddress(); + this.address = row.getInetAddress("address").getHostAddress(); this.port = row.getInt("port"); this.hostname = row.getString("hostname"); this.username = row.getString("username"); diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java index f465c9d4f..d30549b2a 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java @@ -21,8 +21,8 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; import org.apache.cassandra.sidecar.adapters.base.db.schema.ConnectedClientsSchema; import org.apache.cassandra.sidecar.common.server.ICassandraAdapter; import org.apache.cassandra.sidecar.common.utils.Preconditions; diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsSummary.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsSummary.java index c59da807e..e889c6c66 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsSummary.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsSummary.java @@ -22,7 +22,7 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import com.datastax.driver.core.ResultSet; +import com.datastax.oss.driver.api.core.cql.ResultSet; import org.apache.cassandra.sidecar.db.DataObjectMappingException; import org.jetbrains.annotations.NotNull; diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java index b7cbc8bda..54aff9019 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.adapters.base.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.db.schema.CassandraSystemTableSchema; import org.jetbrains.annotations.NotNull; @@ -42,7 +42,7 @@ protected String keyspaceName() } @Override - public void prepareStatements(@NotNull Session session) + public void prepareStatements(@NotNull CqlSession session) { statsStatement = prepare(statsStatement, session, statsStatement()); connectionsByUserStatement = prepare(connectionsByUserStatement, session, selectConnectionsByUserStatement()); diff --git a/adapters/adapters-base/src/test/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsTest.java b/adapters/adapters-base/src/test/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsTest.java index fdb6b86ba..88fdaeed0 100644 --- a/adapters/adapters-base/src/test/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsTest.java +++ b/adapters/adapters-base/src/test/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsTest.java @@ -24,8 +24,8 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.ColumnDefinitions; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.ColumnDefinitions; +import com.datastax.oss.driver.api.core.cql.Row; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; @@ -109,7 +109,7 @@ private void setupMockData(Row mockRow, boolean isMissingFields) when(mockRow.getColumnDefinitions().contains(anyString())).thenReturn(true); } - when(mockRow.getInet("address")).thenReturn(InetAddress.getLoopbackAddress()); + when(mockRow.getInetAddress("address")).thenReturn(InetAddress.getLoopbackAddress()); when(mockRow.getInt("port")).thenReturn(0); when(mockRow.getString("hostname")).thenReturn("localhost"); when(mockRow.getString("username")).thenReturn("u1"); @@ -125,6 +125,5 @@ private void setupMockData(Row mockRow, boolean isMissingFields) when(mockRow.getMap("authentication_metadata", String.class, String.class)).thenReturn(authMetadata); when(mockRow.getString("authentication_mode")).thenReturn(authMode); when(mockRow.getMap("client_options", String.class, String.class)).thenReturn(clientOptions); - } } diff --git a/adapters/adapters-cassandra41/build.gradle b/adapters/adapters-cassandra41/build.gradle index 8f4f44f60..9ceaf820c 100644 --- a/adapters/adapters-cassandra41/build.gradle +++ b/adapters/adapters-cassandra41/build.gradle @@ -49,7 +49,7 @@ dependencies { api(project(":adapters:adapters-base")) compileOnly('org.jetbrains:annotations:23.0.0') - compileOnly('com.datastax.cassandra:cassandra-driver-core:3.11.3') + compileOnly('org.apache.cassandra:java-driver-core:4.19.1') implementation("org.slf4j:slf4j-api:${project.slf4jVersion}") } diff --git a/adapters/adapters-cassandra50/build.gradle b/adapters/adapters-cassandra50/build.gradle index b52a18d6f..7589e79e2 100644 --- a/adapters/adapters-cassandra50/build.gradle +++ b/adapters/adapters-cassandra50/build.gradle @@ -50,7 +50,7 @@ dependencies { api(project(":adapters:adapters-cassandra41")) compileOnly('org.jetbrains:annotations:23.0.0') - compileOnly('com.datastax.cassandra:cassandra-driver-core:3.11.3') + compileOnly('org.apache.cassandra:java-driver-core:4.19.1') implementation("org.slf4j:slf4j-api:${project.slf4jVersion}") } diff --git a/build.gradle b/build.gradle index 8609adf8d..24a1bb66b 100644 --- a/build.gradle +++ b/build.gradle @@ -136,10 +136,9 @@ allprojects { } repositories { - mavenCentral() - // for dtest jar mavenLocal() + mavenCentral() } checkstyle { diff --git a/conf/logback.xml b/conf/logback.xml index df0e2b14d..000c83b8d 100644 --- a/conf/logback.xml +++ b/conf/logback.xml @@ -72,7 +72,5 @@ - - - + diff --git a/conf/sidecar.yaml b/conf/sidecar.yaml index 62e521858..f6d494f71 100644 --- a/conf/sidecar.yaml +++ b/conf/sidecar.yaml @@ -338,7 +338,7 @@ driver_parameters: path: path/to/keystore.p12 password: password num_connections: 6 -# local_dc: datacenter1 + local_dc: datacenter1 healthcheck: initial_delay: 0ms diff --git a/examples/lifecycle/conf/sidecar.yaml.template b/examples/lifecycle/conf/sidecar.yaml.template index fd312423f..e3c4476d1 100644 --- a/examples/lifecycle/conf/sidecar.yaml.template +++ b/examples/lifecycle/conf/sidecar.yaml.template @@ -303,7 +303,7 @@ driver_parameters: path: path/to/keystore.p12 password: password num_connections: 6 -# local_dc: datacenter1 + local_dc: datacenter1 healthcheck: initial_delay: 0ms diff --git a/gradle.properties b/gradle.properties index e7822d725..a34ad0f11 100644 --- a/gradle.properties +++ b/gradle.properties @@ -46,5 +46,5 @@ swaggerVersion=2.2.21 kryoVersion=4.0.2 # OSHI dependencies oshiVersion=6.9.0 -analyticsVersion=0.3.0 +analyticsVersion=0.4-SNAPSHOT kafkaClientVersion=3.7.0 diff --git a/integration-framework/build.gradle b/integration-framework/build.gradle index 29b9c942b..ceb7af1d3 100644 --- a/integration-framework/build.gradle +++ b/integration-framework/build.gradle @@ -43,7 +43,7 @@ dependencies { api('org.mockito:mockito-inline:4.10.0') api("org.assertj:assertj-core:${assertjCoreVersion}") - api('com.datastax.cassandra:cassandra-driver-core:3.11.5') + api('org.apache.cassandra:java-driver-core:4.19.1') implementation("com.google.inject:guice:${guiceVersion}") implementation("com.google.guava:guava:27.0.1-jre") diff --git a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java index 7cad85100..38e64940a 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java +++ b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java @@ -53,10 +53,11 @@ import org.slf4j.LoggerFactory; import com.codahale.metrics.MetricRegistry; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.SimpleStatement; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.CqlSessionBuilder; +import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -323,7 +324,7 @@ protected void createTestKeyspace(QualifiedName name, Map rf) createTestKeyspace(name.maybeQuotedKeyspace(), rf); } - protected void createTestKeyspace(Session session, QualifiedName name, Map rf) + protected void createTestKeyspace(CqlSession session, QualifiedName name, Map rf) { createTestKeyspace(session, name.maybeQuotedKeyspace(), rf); } @@ -333,7 +334,7 @@ protected void createTestKeyspace(String keyspace, Map rf) createTestKeyspace(cluster::schemaChangeIgnoringStoppedInstances, keyspace, rf); } - protected void createTestKeyspace(Session session, String keyspace, Map rf) + protected void createTestKeyspace(CqlSession session, String keyspace, Map rf) { createTestKeyspace(session::execute, keyspace, rf); } @@ -350,7 +351,7 @@ protected void createTestTable(QualifiedName name, String createTableStatement) createTestTable(cluster::schemaChangeIgnoringStoppedInstances, name, createTableStatement); } - protected void createTestTable(Session session, QualifiedName name, String createTableStatement) + protected void createTestTable(CqlSession session, QualifiedName name, String createTableStatement) { createTestTable(session::execute, name, createTableStatement); } @@ -578,21 +579,20 @@ protected ResultSet queryAllDataWithDriver(QualifiedName table) */ protected ResultSet queryAllDataWithDriver(QualifiedName table, ConsistencyLevel consistency) { - Cluster driverCluster = createDriverCluster(cluster.delegate()); - Session session = driverCluster.connect(); - SimpleStatement statement = new SimpleStatement(String.format("SELECT * FROM %s;", table)); - statement.setConsistencyLevel(com.datastax.driver.core.ConsistencyLevel.valueOf(consistency.name())); + CqlSession session = createDriverSession(cluster.delegate()); + SimpleStatement statement = SimpleStatement.newInstance(String.format("SELECT * FROM %s;", table)); + statement = statement.setConsistencyLevel(DefaultConsistencyLevel.valueOf(consistency.name())); return session.execute(statement); } // Utility methods - public static Cluster createDriverCluster(ICluster dtest) + public static CqlSession createDriverSession(ICluster dtest) { - return createDriverCluster(dtest, null); + return createDriverSession(dtest, null); } - public static Cluster createDriverCluster(ICluster dtest, Consumer overrideBuilder) + public static CqlSession createDriverSession(ICluster dtest, Consumer overrideBuilder) { dtest.stream().forEach((i) -> { if (!i.config().has(Feature.NATIVE_PROTOCOL) || !i.config().has(Feature.GOSSIP)) @@ -601,12 +601,12 @@ public static Cluster createDriverCluster(ICluster dtest, C "but one or more is missing"); } }); - Cluster.Builder builder = Cluster.builder() - .withoutMetrics(); + CqlSessionBuilder builder = CqlSession.builder(); dtest.stream().forEach((i) -> { InetSocketAddress address = new InetSocketAddress(i.broadcastAddress().getAddress(), i.config().getInt("native_transport_port")); - builder.addContactPointsWithPorts(address); + builder.addContactPoint(address); + builder.withLocalDatacenter(i.config().localDatacenter()); }); if (overrideBuilder != null) { @@ -733,8 +733,7 @@ public IntegrationTestModule(Iterable instances, public CQLSessionProvider cqlSessionProvider() { List contactPoints = buildContactPoints(instances); - return new TemporaryCqlSessionProvider(contactPoints, - SharedExecutorNettyOptions.INSTANCE); + return new TemporaryCqlSessionProvider(contactPoints, "datacenter1", null); } @Provides diff --git a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/TemporaryCqlSessionProvider.java b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/TemporaryCqlSessionProvider.java index f19f92236..7902050a5 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/TemporaryCqlSessionProvider.java +++ b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/TemporaryCqlSessionProvider.java @@ -19,23 +19,27 @@ package org.apache.cassandra.sidecar.testing; import java.net.InetSocketAddress; +import java.time.Duration; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.net.ssl.SSLContext; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.NettyOptions; -import com.datastax.driver.core.PlainTextAuthProvider; -import com.datastax.driver.core.SSLOptions; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.exceptions.DriverException; -import com.datastax.driver.core.exceptions.DriverInternalError; -import com.datastax.driver.core.policies.ExponentialReconnectionPolicy; -import com.datastax.driver.core.policies.ReconnectionPolicy; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.CqlSessionBuilder; +import com.datastax.oss.driver.api.core.DriverException; +import com.datastax.oss.driver.api.core.DriverExecutionException; +import com.datastax.oss.driver.api.core.config.DefaultDriverOption; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.internal.core.connection.ExponentialReconnectionPolicy; +import org.apache.cassandra.sidecar.cluster.driver.MultiplexingNodeStateListener; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException; import org.jetbrains.annotations.NotNull; @@ -51,80 +55,84 @@ public class TemporaryCqlSessionProvider implements CQLSessionProvider { private static final Logger logger = LoggerFactory.getLogger(TemporaryCqlSessionProvider.class); private final List contactPoints; - private Session localSession; - private final SSLOptions sslOptions; - private final NettyOptions nettyOptions; - private final ReconnectionPolicy reconnectionPolicy; + private final String localDc; + private CqlSession localSession; + private final MultiplexingNodeStateListener multiplexingNodeStateListener; + private final SSLContext sslContext; - public TemporaryCqlSessionProvider(List contactPoints, NettyOptions options) + public TemporaryCqlSessionProvider(List contactPoints, String localDc) { - this(contactPoints, options, null); + this(contactPoints, localDc, null); } - public TemporaryCqlSessionProvider(List contactPoints, NettyOptions options, SSLOptions sslOptions) + public TemporaryCqlSessionProvider(List contactPoints, String localDc, SSLContext sslContext) { - nettyOptions = options; - reconnectionPolicy = new ExponentialReconnectionPolicy(100, 1000); + this.multiplexingNodeStateListener = new MultiplexingNodeStateListener(); this.contactPoints = contactPoints; - this.sslOptions = sslOptions; + this.localDc = localDc; + this.sslContext = sslContext; } @NotNull @Override - public synchronized Session get() + public synchronized CqlSession get() { if (localSession != null) { return localSession; } - Cluster cluster = null; try { logger.info("Connecting to {}", contactPoints); - cluster = Cluster.builder() - .addContactPointsWithPorts(contactPoints) - .withReconnectionPolicy(reconnectionPolicy) - .withoutMetrics() - .withSSL(sslOptions) - .withAuthProvider(new PlainTextAuthProvider("cassandra", "cassandra")) - // tests can create a lot of these Cluster objects, to avoid creating HWTs and - // event thread pools for each we have the override - .withNettyOptions(nettyOptions) - .build(); - localSession = cluster.connect(); + DriverConfigLoader configLoader = DriverConfigLoader.programmaticBuilder() + .withString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, "datacenter1") + .withClass(DefaultDriverOption.RECONNECTION_POLICY_CLASS, ExponentialReconnectionPolicy.class) + .withDuration(DefaultDriverOption.RECONNECTION_BASE_DELAY, Duration.ofMillis(100)) + .withDuration(DefaultDriverOption.RECONNECTION_MAX_DELAY, Duration.ofMillis(1000)) + .withStringList(DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES, + Collections.emptyList()) + .build(); + CqlSessionBuilder builder = CqlSession.builder() + .addContactPoints(contactPoints) + .withLocalDatacenter(localDc) + .withNodeStateListener(multiplexingNodeStateListener) + .withAuthCredentials("cassandra", "cassandra") + .withSslContext(sslContext) + .withConfigLoader(configLoader); + localSession = builder.build(); logger.info("Successfully connected to Cassandra instance!"); } catch (Exception connectionException) { logger.error("Failed to reach Cassandra", connectionException); - if (cluster != null) - { - try - { - cluster.close(); - } - catch (Exception closeException) - { - logger.error("Failed to close cluster in cleanup", closeException); - connectionException.addSuppressed(closeException); - } - } throw new CassandraUnavailableException(CQL, connectionException); } return localSession; } @Override - public Session getIfConnected() + public CqlSession getIfConnected() { return this.localSession; } + @Override + public void registerNodeStateListener(NodeStateListener nodeStateListener) + { + multiplexingNodeStateListener.register(nodeStateListener); + } + + @Override + public void unregisterNodeStateListener(NodeStateListener nodeStateListener) + { + multiplexingNodeStateListener.unregister(nodeStateListener); + } + @Override public void close() { - Session localSession; + CqlSession localSession; synchronized (this) { localSession = this.localSession; @@ -135,8 +143,7 @@ public void close() { try { - localSession.getCluster().closeAsync().get(1, TimeUnit.MINUTES); - localSession.closeAsync().get(1, TimeUnit.MINUTES); + localSession.closeAsync().toCompletableFuture().get(1, TimeUnit.MINUTES); } catch (InterruptedException e) { @@ -166,7 +173,7 @@ else if (cause instanceof DriverException) } else { - throw new DriverInternalError("Unexpected exception thrown", cause); + throw new DriverExecutionException(cause); } } } diff --git a/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java b/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java index 92d3800a6..61c7dd6fc 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java +++ b/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java @@ -20,28 +20,20 @@ import java.io.IOException; import java.io.InputStream; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.security.KeyStore; -import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.PlainTextAuthProvider; -import com.datastax.driver.core.RemoteEndpointAwareNettySSLOptions; -import com.datastax.driver.core.SSLOptions; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.exceptions.AuthenticationException; -import com.datastax.driver.core.policies.DCAwareRoundRobinPolicy; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.CqlSessionBuilder; import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.distributed.shared.Uninterruptibles; @@ -52,13 +44,12 @@ */ public class TlsTestUtils { - public static SSLOptions getSSLOptions(String keystorePath, String keystorePassword, + public static SSLContext getSSLContext(String keystorePath, String keystorePassword, String trustStorePath, String trustStorePassword) throws RuntimeException { try { - SslContext context = buildSSLContext(keystorePath, keystorePassword, trustStorePath, trustStorePassword); - return new RemoteEndpointAwareNettySSLOptions(context); + return buildSSLContext(keystorePath, keystorePassword, trustStorePath, trustStorePassword); } catch (GeneralSecurityException | IOException e) { @@ -69,8 +60,8 @@ public static SSLOptions getSSLOptions(String keystorePath, String keystorePassw public static void withAuthenticatedSession(IInstance instance, String username, String password, - Consumer consumer, - SSLOptions sslOptions) + Consumer consumer, + SSLContext sslOptions) { withAuthenticatedSession(instance, username, password, (builder) -> builder, consumer, sslOptions); } @@ -78,29 +69,25 @@ public static void withAuthenticatedSession(IInstance instance, public static void withAuthenticatedSession(IInstance instance, String username, String password, - Function builderCustomizer, - Consumer consumer, - SSLOptions sslOptions) + Function builderCustomizer, + Consumer consumer, + SSLContext sslOptions) { InetSocketAddress nativeInetSocketAddress = new InetSocketAddress(instance.config().broadcastAddress().getAddress(), tryGetIntConfig(instance.config(), "native_transport_port", 9042)); - InetAddress address = nativeInetSocketAddress.getAddress(); - com.datastax.driver.core.Cluster.Builder builder = com.datastax.driver.core.Cluster.builder() - .withLoadBalancingPolicy( - new DCAwareRoundRobinPolicy.Builder().build()) - .withSSL(sslOptions) - .withoutJMXReporting() - .withAuthProvider(new PlainTextAuthProvider(username, password)) - .addContactPoint(address.getHostAddress()) - .withPort(nativeInetSocketAddress.getPort()); + CqlSessionBuilder builder = CqlSession.builder() + .withSslContext(sslOptions) + .withAuthCredentials(username, password) + .withLocalDatacenter("datacenter1") + .addContactPoint(nativeInetSocketAddress); if (builderCustomizer != null) { builder = builderCustomizer.apply(builder); } - try (com.datastax.driver.core.Cluster c = builder.build(); Session session = c.connect()) + try (CqlSession session = builder.build()) { consumer.accept(session); } @@ -113,14 +100,14 @@ public static void withAuthenticatedSession(IInstance instance, */ public static void waitForExistingRoles(Runnable runnable) { - for (int i = 0; i < 60; i++) + for (int i = 0; i < 120; i++) { try { runnable.run(); return; } - catch (AuthenticationException exception) + catch (RuntimeException exception) { if (exception.getMessage() != null && exception.getMessage().contains("Provided username cassandra and/or password are incorrect")) @@ -136,22 +123,22 @@ public static void waitForExistingRoles(Runnable runnable) } } - public static SslContext buildSSLContext(String keystorePath, String keystorePassword, + public static SSLContext buildSSLContext(String keystorePath, String keystorePassword, String trustStorePath, String trustStorePassword) throws GeneralSecurityException, IOException { - SslContextBuilder sslContextBuilder; + SSLContext sslContext; try { - sslContextBuilder = SslContextBuilder.forClient() - .protocols(List.of("TLSv1.2", "TLSv1.3")); + // TODO(lantoniak): Multiple protocols are not supported. + sslContext = SSLContext.getInstance("TLSv1.3"); + KeyManagerFactory kmf = null; if (keystorePath != null && keystorePassword != null) { KeyStore keyStore = createKeystore(keystorePath, keystorePassword); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, keystorePassword.toCharArray()); - sslContextBuilder.keyManager(kmf); } // We set the truststore only if it is configured. For an SSL connection, if the truststore is required @@ -159,8 +146,10 @@ public static SslContext buildSSLContext(String keystorePath, String keystorePas KeyStore truststore = createKeystore(trustStorePath, trustStorePassword); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(truststore); - sslContextBuilder.trustManager(tmf); - return sslContextBuilder.build(); + + sslContext.init(kmf != null ? kmf.getKeyManagers() : null, + tmf.getTrustManagers(), null); + return sslContext; } catch (Exception e) { diff --git a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationIntegrationTest.java b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationIntegrationTest.java index 8801124b5..2fc66e1a2 100644 --- a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationIntegrationTest.java +++ b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationIntegrationTest.java @@ -30,12 +30,13 @@ import java.util.function.Function; import java.util.stream.Collectors; +import javax.net.ssl.SSLContext; + import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.SSLOptions; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.stats.CacheStats; import com.google.inject.AbstractModule; @@ -81,7 +82,6 @@ import org.apache.cassandra.sidecar.testing.MtlsTestHelper; import org.apache.cassandra.sidecar.testing.QualifiedName; import org.apache.cassandra.sidecar.testing.SharedClusterSidecarIntegrationTestBase; -import org.apache.cassandra.sidecar.testing.SharedExecutorNettyOptions; import org.apache.cassandra.sidecar.testing.TemporaryCqlSessionProvider; import org.apache.cassandra.sidecar.utils.CacheFactory; import org.apache.cassandra.sidecar.utils.SimpleCassandraVersion; @@ -90,7 +90,7 @@ import static org.apache.cassandra.sidecar.db.schema.SidecarRolePermissionsSchema.ROLE_PERMISSIONS_TABLE; import static org.apache.cassandra.testing.DriverTestUtils.buildContactPoints; import static org.apache.cassandra.testing.TestUtils.DC1_RF1; -import static org.apache.cassandra.testing.TlsTestUtils.getSSLOptions; +import static org.apache.cassandra.testing.TlsTestUtils.getSSLContext; import static org.apache.cassandra.testing.TlsTestUtils.waitForExistingRoles; import static org.apache.cassandra.testing.TlsTestUtils.withAuthenticatedSession; import static org.apache.cassandra.testing.utils.AssertionUtils.getBlocking; @@ -465,7 +465,7 @@ void testEndpointRequiringMultipleActions() String[] componentDownloadUrl = new String[1]; Path clientKeystorePath = cassandraIdentityClientKeyStore(); - SSLOptions sslOptions = getSSLOptions(clientKeystorePath.toString(), + SSLContext sslOptions = getSSLContext(clientKeystorePath.toString(), mtlsTestHelper.clientKeyStorePassword(), mtlsTestHelper.trustStorePath(), mtlsTestHelper.trustStorePassword()); @@ -715,7 +715,7 @@ void testAuthorizationCachingWithPermissionRevocation() // Revoke permission Path clientKeystorePath = cassandraIdentityClientKeyStore(); - SSLOptions sslOptions = getSSLOptions(clientKeystorePath.toString(), + SSLContext sslOptions = getSSLContext(clientKeystorePath.toString(), mtlsTestHelper.clientKeyStorePassword(), mtlsTestHelper.trustStorePath(), mtlsTestHelper.trustStorePassword()); @@ -826,7 +826,7 @@ protected void initializeSchemaForTest() Path clientKeystorePath = cassandraIdentityClientKeyStore(); createRequiredKeystores(); - SSLOptions sslOptions = getSSLOptions(clientKeystorePath.toString(), + SSLContext sslOptions = getSSLContext(clientKeystorePath.toString(), mtlsTestHelper.clientKeyStorePassword(), mtlsTestHelper.trustStorePath(), mtlsTestHelper.trustStorePassword()); @@ -839,7 +839,7 @@ protected void initializeSchemaForTest() }, sslOptions); } - private void createSidecarRolesPermissionsTable(Session session) + private void createSidecarRolesPermissionsTable(CqlSession session) { String statement = String.format("CREATE TABLE IF NOT EXISTS sidecar_internal.%s (" + "role text," @@ -850,7 +850,7 @@ private void createSidecarRolesPermissionsTable(Session session) session.execute(statement); } - private void createRequiredKeyspaceTables(Session session) + private void createRequiredKeyspaceTables(CqlSession session) { for (RoleWithIdentityTestScenario scenario : ROLE_WITH_IDENTITY_TEST_SCENARIOS) { @@ -864,7 +864,7 @@ private void createRequiredKeyspaceTables(Session session) } } - private void createRequiredRoles(Session session) + private void createRequiredRoles(CqlSession session) { for (RoleWithIdentityTestScenario mapping : ROLE_WITH_IDENTITY_TEST_SCENARIOS) { @@ -897,12 +897,12 @@ private void createRequiredKeystores() } } - private void grantTablePermission(Session session, String keyspace, String table, String role) + private void grantTablePermission(CqlSession session, String keyspace, String table, String role) { session.execute("GRANT ALL PERMISSIONS ON " + keyspace + "." + table + " TO " + role); } - private void updateSidecarPermission(Session session, String role, String resource, String permission) + private void updateSidecarPermission(CqlSession session, String role, String resource, String permission) { session.execute(String.format("UPDATE sidecar_internal.role_permissions_v1 SET permissions = permissions + {'%s'} " + "where role = '%s' and resource = '%s'", permission, role, resource)); @@ -1073,12 +1073,12 @@ public CQLSessionProvider cqlSessionProvider() throw new RuntimeException(e); } - SSLOptions sslOptions = getSSLOptions(clientKeystoreForSidecarToCassandraConnections.toString(), + SSLContext sslOptions = getSSLContext(clientKeystoreForSidecarToCassandraConnections.toString(), mtlsTestHelper.clientKeyStorePassword(), mtlsTestHelper.trustStorePath(), mtlsTestHelper.trustStorePassword()); return new TemporaryCqlSessionProvider(contactPoints, - SharedExecutorNettyOptions.INSTANCE, + "datacenter1", sslOptions); } diff --git a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/cdc/CdcIntegrationTest.java b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/cdc/CdcIntegrationTest.java index 961a5224c..bddad5ff8 100644 --- a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/cdc/CdcIntegrationTest.java +++ b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/cdc/CdcIntegrationTest.java @@ -57,7 +57,7 @@ protected void initializeSchemaForTest() @Override protected void beforeTestStart() { - waitForSchemaReady(30, TimeUnit.SECONDS); + waitForSchemaReady(60, TimeUnit.SECONDS); } @Test diff --git a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskIntegrationTest.java b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskIntegrationTest.java index ee6aceb5c..e7f32e72f 100644 --- a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskIntegrationTest.java +++ b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskIntegrationTest.java @@ -40,7 +40,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import io.vertx.core.Vertx; import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.Feature; @@ -61,7 +62,6 @@ import org.apache.cassandra.sidecar.metrics.SidecarMetricsImpl; import org.apache.cassandra.sidecar.metrics.server.CoordinationMetrics; import org.apache.cassandra.sidecar.tasks.ScheduleDecision; -import org.apache.cassandra.sidecar.testing.SharedExecutorNettyOptions; import org.apache.cassandra.sidecar.utils.TestMetricUtils; import org.apache.cassandra.testing.ClusterBuilderConfiguration; import org.apache.cassandra.testing.IClusterExtension; @@ -370,18 +370,17 @@ private SidecarMetrics buildMetrics() DisconnectableCQLSessionProvider buildCqlSession(List address) { CQLSessionProvider sessionProvider = - new CQLSessionProviderImpl(address, address, 500, null, 0, SharedExecutorNettyOptions.INSTANCE); + new CQLSessionProviderImpl(address, address, 500, "datacenter1", 0); sessionProviderList.add(sessionProvider); return new DisconnectableCQLSessionProvider(sessionProvider); } SidecarLeaseDatabaseAccessor buildAccessor(CQLSessionProvider sessionProvider) { - Session session = sessionProvider.get(); + CqlSession session = sessionProvider.get(); assertThat(session).isNotNull(); - assertThat(session.getCluster()).isNotNull(); - assertThat(session.getCluster().getMetadata()).isNotNull(); - assertThat(session.getCluster().getMetadata().getKeyspace("sidecar_internal")).isNotNull(); + assertThat(session.getMetadata()).isNotNull(); + assertThat(session.getMetadata().getKeyspace("sidecar_internal")).isNotNull(); SidecarLeaseSchema tableSchema = new SidecarLeaseSchema(mockSchemaConfig); tableSchema.prepareStatements(session); return new SidecarLeaseDatabaseAccessor(tableSchema, sessionProvider); @@ -527,7 +526,7 @@ void reconnect() @Override @NotNull - public Session get() throws CassandraUnavailableException + public CqlSession get() throws CassandraUnavailableException { if (isConnected) { @@ -538,11 +537,20 @@ public Session get() throws CassandraUnavailableException } @Override - public @Nullable Session getIfConnected() + public @Nullable CqlSession getIfConnected() { return isConnected ? delegate.getIfConnected() : null; } + public void registerNodeStateListener(NodeStateListener nodeStateListener) + { + } + + @Override + public void unregisterNodeStateListener(NodeStateListener nodeStateListener) + { + } + @Override public void close() { diff --git a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java index d25d2bd7b..ed27a7347 100644 --- a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java +++ b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java @@ -56,7 +56,6 @@ import org.apache.cassandra.sidecar.db.schema.TableSchemaFetcher; import org.apache.cassandra.sidecar.metrics.MetricRegistryFactory; import org.apache.cassandra.sidecar.metrics.instance.InstanceHealthMetrics; -import org.apache.cassandra.sidecar.testing.SharedExecutorNettyOptions; import org.apache.cassandra.sidecar.utils.CassandraVersionProvider; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; import org.apache.cassandra.testing.ClusterBuilderConfiguration; @@ -191,7 +190,7 @@ static void assertMembership(List memberships, i { List address = buildContactList(instance); CQLSessionProvider sessionProvider = - new CQLSessionProviderImpl(address, address, 500, instance.config().localDatacenter(), 0, SharedExecutorNettyOptions.INSTANCE); + new CQLSessionProviderImpl(address, address, 500, instance.config().localDatacenter(), 0); InstancesMetadata instancesMetadata = buildInstancesMetadata(instance, sessionProvider, metricRegistryProvider); InstanceMetadataFetcher instanceMetadataFetcher = new InstanceMetadataFetcher(instancesMetadata); r1.add(new MostReplicatedKeyspaceTokenZeroElectorateMembership(instanceMetadataFetcher, sessionProvider, CONFIG)); diff --git a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/db/SystemDatabaseAccessorIntegrationTest.java b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/db/SystemDatabaseAccessorIntegrationTest.java index 43c58f682..be576989c 100644 --- a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/db/SystemDatabaseAccessorIntegrationTest.java +++ b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/db/SystemDatabaseAccessorIntegrationTest.java @@ -33,7 +33,6 @@ import org.apache.cassandra.sidecar.db.schema.SystemAuthSchema; import org.apache.cassandra.sidecar.db.schema.SystemViewsSchema; import org.apache.cassandra.sidecar.testing.SharedClusterSidecarIntegrationTestBase; -import org.apache.cassandra.sidecar.testing.SharedExecutorNettyOptions; import org.apache.cassandra.testing.ClusterBuilderConfiguration; import org.apache.cassandra.testing.IClusterExtension; @@ -104,6 +103,6 @@ protected void initializeSchemaForTest() private CQLSessionProvider cqlSessionProvider(IClusterExtension cluster) { List address = buildContactList(cluster.stream().map(IInstance::config).collect(Collectors.toUnmodifiableList())); - return new CQLSessionProviderImpl(address, address, 500, null, 0, "cassandra", "cassandra", null, SharedExecutorNettyOptions.INSTANCE); + return new CQLSessionProviderImpl(address, address, 500, "datacenter1", 0, "cassandra", "cassandra", null); } } diff --git a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/routes/CassandraStatsIntegrationTest.java b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/routes/CassandraStatsIntegrationTest.java index 22eada9fa..6f844a781 100644 --- a/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/routes/CassandraStatsIntegrationTest.java +++ b/integration-tests/src/integrationTest/org/apache/cassandra/sidecar/routes/CassandraStatsIntegrationTest.java @@ -26,8 +26,7 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpResponseExpectation; @@ -122,7 +121,7 @@ void retrieveClientStatsListConnections() @Test void retrieveClientStatsListConnectionsWithKeyspace() { - try (Cluster driverCluster = createDriverCluster(cluster.delegate()); Session session = driverCluster.connect()) + try (CqlSession session = createDriverSession(cluster.delegate())) { session.execute("USE " + TEST_KEYSPACE); @@ -139,7 +138,7 @@ void retrieveClientStatsListConnectionsWithKeyspace() void retrieveClientStatsMultipleConnections() { // Creates an additional connection pair - try (Cluster driverCluster = createDriverCluster(cluster.delegate()); Session ignored = driverCluster.connect()) + try (CqlSession session = createDriverSession(cluster.delegate())) { Map expectedParams = Map.of("summary", false); String testRoute = "/api/v1/cassandra/stats/connected-clients?summary=false"; @@ -262,7 +261,7 @@ void assertClientStatsResponse(HttpResponse response, Map - com.datastax.cassandra:cassandra-driver-core + org.apache.cassandra:cassandra-driver-core META-INF/maven/ diff --git a/server-common/build.gradle b/server-common/build.gradle index 4bd5e132c..c1e325766 100644 --- a/server-common/build.gradle +++ b/server-common/build.gradle @@ -51,7 +51,8 @@ dependencies { api(project(":client-common")) compileOnly('org.jetbrains:annotations:23.0.0') - compileOnly('com.datastax.cassandra:cassandra-driver-core:3.11.3') + compileOnly('org.apache.cassandra:java-driver-core:4.19.1') + compileOnly(group: 'com.google.guava', name: 'guava', version: "${project.guavaVersion}") implementation("org.slf4j:slf4j-api:${project.slf4jVersion}") testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junitVersion}" @@ -59,7 +60,8 @@ dependencies { testImplementation "org.assertj:assertj-core:3.24.2" testImplementation "org.mockito:mockito-core:4.10.0" testImplementation "org.mockito:mockito-inline:4.10.0" - testImplementation "com.datastax.cassandra:cassandra-driver-core:3.11.3" + testImplementation "org.apache.cassandra:java-driver-core:4.19.1" + testImplementation(group: 'com.google.guava', name: 'guava', version: "${project.guavaVersion}") testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junitVersion}" testFixturesImplementation("org.assertj:assertj-core:3.24.2") diff --git a/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java b/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java index 9187ac1cd..c1b05a1a0 100644 --- a/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java +++ b/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java @@ -20,6 +20,8 @@ import java.net.InetSocketAddress; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; import org.jetbrains.annotations.VisibleForTesting; /** @@ -37,25 +39,25 @@ public class DriverUtils * @return true if the host has active connections, false otherwise */ @VisibleForTesting - public static boolean hasActiveConnections(Host host) + public static boolean hasActiveConnections(Node host) { - return host.convictionPolicy.hasActiveConnections(); + return host.getOpenConnections() > 0; } - /** - * Start attempting to reconnect to the given host, as hosts with `IGNORED` distance aren't attempted - * and the SidecarLoadBalancingPolicy marks non-selected nodes as IGNORED until they need to rotate in. - * - *

Note: This method should not be used directly, but should be proxied by - * an implementation of {@link org.apache.cassandra.sidecar.common.server.utils.DriverUtils}. - * - * @param cluster The cluster object - * @param host the host to which reconnect attempts will be made - */ - public static void startPeriodicReconnectionAttempt(Cluster cluster, Host host) - { - cluster.manager.startPeriodicReconnectionAttempt(host, false); - } +// /** +// * Start attempting to reconnect to the given host, as hosts with `IGNORED` distance aren't attempted +// * and the SidecarLoadBalancingPolicy marks non-selected nodes as IGNORED until they need to rotate in. +// * +// *

Note: This method should not be used directly, but should be proxied by +// * an implementation of {@link org.apache.cassandra.sidecar.common.server.utils.DriverUtils}. +// * +// * @param cluster The cluster object +// * @param host the host to which reconnect attempts will be made +// */ +// public static void startPeriodicReconnectionAttempt(Cluster cluster, Node host) +// { +// cluster.manager.startPeriodicReconnectionAttempt(host, false); +// } /** * Gets a Host instance from metadata based on the native transport address @@ -65,15 +67,19 @@ public static void startPeriodicReconnectionAttempt(Cluster cluster, Host host) * * @param metadata the {@link Metadata} instance to search for the host * @param localNativeTransportAddress the native transport ip address and port for the host to find - * @return the {@link Host} instance if found, else null + * @return the {@link Node} instance if found, else null */ - public static Host getHost(Metadata metadata, InetSocketAddress localNativeTransportAddress) + public static Node getHost(Metadata metadata, InetSocketAddress localNativeTransportAddress) { - // Because the driver can sometimes mess up the broadcast address, we need to search by endpoint - // which is what it actually uses to connect to the cluster. Therefore, create a TranslatedAddressEndpoint - // to use for searching. It has to be one of these because that's what the driver is using internally, - // and the `.equals` method used when searching checks the type explicitly. - TranslatedAddressEndPoint endPoint = new TranslatedAddressEndPoint(localNativeTransportAddress); - return metadata.getHost(endPoint); +// // Because the driver can sometimes mess up the broadcast address, we need to search by endpoint +// // which is what it actually uses to connect to the cluster. Therefore, create a TranslatedAddressEndpoint +// // to use for searching. It has to be one of these because that's what the driver is using internally, +// // and the `.equals` method used when searching checks the type explicitly. +// TranslatedAddressEndPoint endPoint = new TranslatedAddressEndPoint(localNativeTransportAddress); +// return metadata.getHost(endPoint); + // TODO(lantoniak): Use TranslatedAddressEndPoint? + return metadata.getNodes().values().stream() + .filter(n -> n.getEndPoint().resolve().equals(localNativeTransportAddress)) + .findFirst().orElse(null); } } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java index 04a8bd151..c63f23021 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java @@ -18,7 +18,8 @@ package org.apache.cassandra.sidecar.common.server; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,20 +40,23 @@ public interface CQLSessionProvider * @return the session that holds connections to a Cassandra cluster * @throws CassandraUnavailableException when CQL connection is not successful */ - @NotNull Session get() throws CassandraUnavailableException; + @NotNull CqlSession get() throws CassandraUnavailableException; /** - * Gets the current Session object if it already exists. + * Gets the current CqlSession object if it already exists. * Unlike {@link #get()}, it does not attempt to connect to the cluster, * and it can return {@code null} when no connection is established. * The call-sites are required to handle {@code null} value. * - * @return the connected {@link Session} object if available. Null otherwise. + * @return the connected {@link CqlSession} object if available. Null otherwise. */ - @Nullable Session getIfConnected(); + @Nullable CqlSession getIfConnected(); /** * Closes the CQLSessionProvider */ void close(); + + void registerNodeStateListener(NodeStateListener nodeStateListener); + void unregisterNodeStateListener(NodeStateListener nodeStateListener); } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/ICassandraAdapter.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/ICassandraAdapter.java index 59be199f9..0025a5d3e 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/ICassandraAdapter.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/ICassandraAdapter.java @@ -21,10 +21,10 @@ import java.net.InetSocketAddress; import java.util.Map; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.SimpleStatement; -import com.datastax.driver.core.Statement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.metadata.Metadata; import org.apache.cassandra.sidecar.common.response.NodeSettings; import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException; import org.jetbrains.annotations.NotNull; @@ -69,7 +69,7 @@ public interface ICassandraAdapter @NotNull default ResultSet executeLocal(String query) throws CassandraUnavailableException { - return executeLocal(new SimpleStatement(query)); + return executeLocal(SimpleStatement.newInstance(query)); } /** @@ -79,7 +79,7 @@ default ResultSet executeLocal(String query) throws CassandraUnavailableExceptio * @return the {@link ResultSet} * @throws CassandraUnavailableException when CQL connection is not yet established */ - @NotNull ResultSet executeLocal(Statement statement) throws CassandraUnavailableException; + @NotNull ResultSet executeLocal(Statement statement) throws CassandraUnavailableException; /** * The address on which the local Cassandra instance is listening for CQL connections diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRange.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRange.java index 8f1e61c21..521d4b6d9 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRange.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRange.java @@ -28,7 +28,8 @@ import com.google.common.collect.RangeSet; import com.google.common.collect.TreeRangeSet; -import com.datastax.driver.core.DataType; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; /** * Range: (start, end] - start exclusive and end inclusive @@ -45,16 +46,16 @@ public class TokenRange * @return list of token ranges. If the input token range wraps around, the size of the list is 2; * otherwise, the list has only one range */ - public static List from(com.datastax.driver.core.TokenRange dsTokenRange) + public static List from(com.datastax.oss.driver.api.core.metadata.token.TokenRange dsTokenRange) { - DataType tokenDataType = dsTokenRange.getStart().getType(); - if (tokenDataType == DataType.varint()) // BigInteger - RandomPartitioner + com.datastax.oss.driver.api.core.metadata.token.Token tokenData = dsTokenRange.getStart(); + if (tokenData instanceof RandomToken) // BigInteger - RandomPartitioner { return dsTokenRange.unwrap() .stream() .map(range -> { - BigInteger start = (BigInteger) range.getStart().getValue(); - BigInteger end = (BigInteger) range.getEnd().getValue(); + BigInteger start = ((RandomToken) range.getStart()).getValue(); + BigInteger end = ((RandomToken) range.getEnd()).getValue(); if (end.compareTo(Partitioners.RANDOM.minimumToken().toBigInteger()) == 0) { end = Partitioners.RANDOM.maximumToken().toBigInteger(); @@ -63,13 +64,13 @@ public static List from(com.datastax.driver.core.TokenRange dsTokenR }) .collect(Collectors.toList()); } - else if (tokenDataType == DataType.bigint()) // Long - Murmur3Partitioner + else if (tokenData instanceof Murmur3Token) // Long - Murmur3Partitioner { return dsTokenRange.unwrap() .stream() .map(range -> { - BigInteger start = BigInteger.valueOf((Long) range.getStart().getValue()); - BigInteger end = BigInteger.valueOf((Long) range.getEnd().getValue()); + BigInteger start = BigInteger.valueOf(((Murmur3Token) range.getStart()).getValue()); + BigInteger end = BigInteger.valueOf(((Murmur3Token) range.getEnd()).getValue()); if (end.compareTo(Partitioners.MURMUR3.minimumToken().toBigInteger()) == 0) { end = Partitioners.MURMUR3.maximumToken().toBigInteger(); @@ -81,7 +82,7 @@ else if (tokenDataType == DataType.bigint()) // Long - Murmur3Partitioner else { throw new IllegalArgumentException( - "Unsupported token type: " + tokenDataType + + "Unsupported token type: " + tokenData.getClass().getName() + ". Only tokens of Murmur3Partitioner and RandomPartitioner are supported."); } } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java index f47bc6a8f..834a7b823 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java @@ -19,10 +19,12 @@ package org.apache.cassandra.sidecar.common.server.utils; import java.net.InetSocketAddress; +import java.net.SocketAddress; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.Metadata; +import com.google.common.base.Preconditions; + +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; /** * A shim layer that provides information from the Cassandra driver. Instead of accessing the @@ -31,26 +33,26 @@ */ public class DriverUtils { - /** - * Start attempting to reconnect to the given host, as hosts with `IGNORED` distance aren't attempted - * and the SidecarLoadBalancingPolicy marks non-selected nodes as IGNORED until they need to rotate in. - * - * @param cluster The cluster object - * @param host the host to which reconnect attempts will be made - */ - public void startPeriodicReconnectionAttempt(Cluster cluster, Host host) - { - com.datastax.driver.core.DriverUtils.startPeriodicReconnectionAttempt(cluster, host); - } +// /** +// * Start attempting to reconnect to the given host, as hosts with `IGNORED` distance aren't attempted +// * and the SidecarLoadBalancingPolicy marks non-selected nodes as IGNORED until they need to rotate in. +// * +// * @param cluster The cluster object +// * @param host the host to which reconnect attempts will be made +// */ +// public void startPeriodicReconnectionAttempt(Cluster cluster, Node host) +// { +// com.datastax.driver.core.DriverUtils.startPeriodicReconnectionAttempt(cluster, host); +// } /** * Gets a Host instance from metadata based on the native transport address * * @param metadata the {@link Metadata} instance to search for the host * @param localNativeTransportAddress the native transport ip address and port for the host to find - * @return the {@link Host} instance if found, else null + * @return the {@link Node} instance if found, else null */ - public Host getHost(Metadata metadata, InetSocketAddress localNativeTransportAddress) + public Node getHost(Metadata metadata, InetSocketAddress localNativeTransportAddress) { return com.datastax.driver.core.DriverUtils.getHost(metadata, localNativeTransportAddress); } @@ -61,8 +63,10 @@ public Host getHost(Metadata metadata, InetSocketAddress localNativeTransportAdd * @param host the host to which reconnect attempts will be made * @return the address. */ - public InetSocketAddress getSocketAddress(Host host) + public InetSocketAddress getSocketAddress(Node host) { - return host.getEndPoint().resolve(); + SocketAddress socketAddress = host.getEndPoint().resolve(); + Preconditions.checkState(socketAddress instanceof InetSocketAddress, "Unsupported endpoint type: " + host.getEndPoint()); + return (InetSocketAddress) socketAddress; } } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/DatabaseAccessor.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/DatabaseAccessor.java index 3263d1c68..6dc45fc2b 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/DatabaseAccessor.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/DatabaseAccessor.java @@ -21,9 +21,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.Statement; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Statement; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.db.schema.TableSchema; import org.jetbrains.annotations.NotNull; @@ -48,7 +48,7 @@ protected DatabaseAccessor(T tableSchema, } @NotNull - public Session session() + public CqlSession session() { return cqlSessionProvider.get(); } @@ -61,7 +61,7 @@ public boolean isAvailable() return tableSchema.isInitialized(); } - protected ResultSet execute(Statement statement) + protected ResultSet execute(Statement statement) { return session().execute(statement); } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/LocalDatabaseAccessor.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/LocalDatabaseAccessor.java index 8bff9a3e8..d82be1b78 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/LocalDatabaseAccessor.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/LocalDatabaseAccessor.java @@ -18,9 +18,9 @@ package org.apache.cassandra.sidecar.db; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.Statement; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Statement; import org.apache.cassandra.sidecar.common.server.ICassandraAdapter; import org.apache.cassandra.sidecar.db.schema.TableSchema; @@ -40,13 +40,13 @@ protected LocalDatabaseAccessor(T tableSchema, ICassandraAdapter cassandraAdapte } @Override - public Session session() + public CqlSession session() { throw new UnsupportedOperationException("LocalDatabaseAccessor does not expose Session object"); } @Override - protected ResultSet execute(Statement statement) + protected ResultSet execute(Statement statement) { return cassandraAdapter.executeLocal(statement); } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java index 0622c1918..85061254b 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java @@ -23,11 +23,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.ConsistencyLevel; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.metadata.Metadata; import org.apache.cassandra.sidecar.exceptions.SidecarSchemaModificationException; import org.jetbrains.annotations.NotNull; @@ -39,7 +38,7 @@ public abstract class AbstractSchema protected Logger logger = LoggerFactory.getLogger(this.getClass()); private volatile boolean initialized = false; - public synchronized boolean initialize(@NotNull Session session, @NotNull Predicate shouldCreateSchema) + public synchronized boolean initialize(@NotNull CqlSession session, @NotNull Predicate shouldCreateSchema) { initialized = initialized || initializeInternal(session, shouldCreateSchema); return initialized; @@ -53,15 +52,16 @@ public boolean isInitialized() return initialized; } - protected PreparedStatement prepare(PreparedStatement cached, Session session, String cqlLiteral) + protected PreparedStatement prepare(PreparedStatement cached, CqlSession session, String cqlLiteral) { - return cached == null ? session.prepare(cqlLiteral).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM) : cached; + // TODO(lantoniak): .setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM) + return cached == null ? session.prepare(cqlLiteral) : cached; } - protected boolean initializeInternal(@NotNull Session session, + protected boolean initializeInternal(@NotNull CqlSession session, @NotNull Predicate shouldCreateSchema) { - if (!exists(session.getCluster().getMetadata())) + if (!exists(session.getMetadata())) { if (shouldCreateSchema.test(this)) { @@ -102,7 +102,7 @@ protected boolean initializeInternal(@NotNull Session session, * * @param session the CQL session */ - protected abstract void prepareStatements(@NotNull Session session); + protected abstract void prepareStatements(@NotNull CqlSession session); /** * @param metadata the cluster metadata diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java index ffd2e7286..8d21ceab7 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java @@ -20,8 +20,8 @@ import java.util.function.Predicate; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Metadata; import org.jetbrains.annotations.NotNull; /** @@ -36,7 +36,7 @@ protected boolean exists(@NotNull Metadata metadata) } @Override - protected boolean initializeInternal(@NotNull Session session, + protected boolean initializeInternal(@NotNull CqlSession session, @NotNull Predicate shouldCreateSchema) { prepareStatements(session); diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/TableSchema.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/TableSchema.java index bcf4535db..3767be01f 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/TableSchema.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/TableSchema.java @@ -18,8 +18,10 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; +import java.util.Optional; + +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import org.jetbrains.annotations.NotNull; /** @@ -32,10 +34,8 @@ public abstract class TableSchema extends AbstractSchema @Override protected boolean exists(@NotNull Metadata metadata) { - KeyspaceMetadata ksMetadata = metadata.getKeyspace(keyspaceName()); - if (ksMetadata == null) - return false; - return ksMetadata.getTable(tableName()) != null; + Optional ksMetadata = metadata.getKeyspace(keyspaceName()); + return ksMetadata.map(keyspaceMetadata -> keyspaceMetadata.getTable(tableName()).isPresent()).orElse(false); } @Override diff --git a/server-common/src/test/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRangeTest.java b/server-common/src/test/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRangeTest.java index 1951a01f4..6dd756f40 100644 --- a/server-common/src/test/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRangeTest.java +++ b/server-common/src/test/java/org/apache/cassandra/sidecar/common/server/cluster/locator/TokenRangeTest.java @@ -29,6 +29,9 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3TokenRange; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; @@ -52,13 +55,13 @@ void testCreateRangeWithInvalidParams() { assertThatThrownBy(() -> new TokenRange(1, -1)) .isExactlyInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Invalid range: (Token(1)‥Token(-1)]"); + .hasMessageContaining("Invalid range: (Token(1)..Token(-1)]"); } @Test void testCreateFromJavaDriverTokenRange() { - com.datastax.driver.core.TokenRange ordinaryRange = mockRange(1L, 100L); + com.datastax.oss.driver.api.core.metadata.token.TokenRange ordinaryRange = mockRange(1L, 100L); when(ordinaryRange.isWrappedAround()).thenReturn(false); when(ordinaryRange.unwrap()).thenCallRealMethod(); List ranges = TokenRange.from(ordinaryRange); @@ -69,9 +72,8 @@ void testCreateFromJavaDriverTokenRange() @Test void testCreateFromWraparoundJavaDriverTokenRange() { - com.datastax.driver.core.TokenRange range = mockRange(10L, -10L); - List unwrapped = Arrays.asList(mockRange(10L, Long.MAX_VALUE), - mockRange(Long.MIN_VALUE, -10L)); + com.datastax.oss.driver.api.core.metadata.token.TokenRange range = mockRange(10L, -10L); + List unwrapped = Arrays.asList(mockRange(10L, Long.MAX_VALUE), mockRange(Long.MIN_VALUE, -10L)); when(range.unwrap()).thenReturn(unwrapped); List ranges = TokenRange.from(range); assertThat(ranges).hasSize(2) @@ -82,7 +84,7 @@ void testCreateFromWraparoundJavaDriverTokenRange() @Test void testCreateFromWraparoundJavaDriverTokenRangeEndingInMinToken() { - com.datastax.driver.core.TokenRange range = mockRange(10L, Long.MIN_VALUE); + com.datastax.oss.driver.api.core.metadata.token.TokenRange range = mockRange(10L, Long.MIN_VALUE); // Java driver's token range considers the range is no a wraparound, if the end is the minimum token when(range.unwrap()).thenReturn(Collections.singletonList(range)); List ranges = TokenRange.from(range); @@ -212,21 +214,13 @@ private static Arguments args(Object... args) return Arguments.arguments(args); } - private com.datastax.driver.core.TokenRange mockRange(long start, long end) + private com.datastax.oss.driver.api.core.metadata.token.TokenRange mockRange(long start, long end) { - com.datastax.driver.core.TokenRange range = mock(com.datastax.driver.core.TokenRange.class); - com.datastax.driver.core.Token startToken = mockToken(start); + com.datastax.oss.driver.api.core.metadata.token.TokenRange range = mock(Murmur3TokenRange.class); + com.datastax.oss.driver.api.core.metadata.token.Token startToken = new Murmur3Token(start); when(range.getStart()).thenReturn(startToken); - com.datastax.driver.core.Token endToken = mockToken(end); + com.datastax.oss.driver.api.core.metadata.token.Token endToken = new Murmur3Token(end); when(range.getEnd()).thenReturn(endToken); return range; } - - private com.datastax.driver.core.Token mockToken(long value) - { - com.datastax.driver.core.Token token = mock(com.datastax.driver.core.Token.class); - when(token.getType()).thenReturn(com.datastax.driver.core.DataType.bigint()); - when(token.getValue()).thenReturn(value); - return token; - } } diff --git a/server/build.gradle b/server/build.gradle index 9cf929a26..3f2704cf3 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -95,7 +95,8 @@ dependencies { implementation("io.vertx:vertx-auth-jwt:$vertxVersion") implementation("io.vertx:vertx-auth-oauth2:$vertxVersion") - implementation('com.datastax.cassandra:cassandra-driver-core:3.11.3') + implementation('org.apache.cassandra:java-driver-core:4.19.1') + implementation('org.apache.cassandra:java-driver-query-builder:4.19.1') implementation("com.google.inject:guice:${guiceVersion}") implementation("com.github.ben-manes.caffeine:caffeine:${caffeineVersion}") @@ -103,7 +104,6 @@ dependencies { implementation("ch.qos.logback:logback-core:${project.logbackVersion}") implementation("ch.qos.logback:logback-classic:${project.logbackVersion}") - implementation(group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0') implementation(group: 'commons-codec', name: 'commons-codec', version: "${project.commonsCodecVersion}") @@ -168,7 +168,7 @@ dependencies { exclude group: 'junit', module: 'junit' } - testImplementation('com.datastax.cassandra:cassandra-driver-core:3.11.3:tests') + testImplementation('org.apache.cassandra:java-driver-core:4.19.1:tests') testImplementation('org.mockito:mockito-core:4.10.0') testImplementation('org.mockito:mockito-inline:4.10.0') testImplementation("io.vertx:vertx-junit5:${project.vertxVersion}") diff --git a/server/src/main/java/org/apache/cassandra/bridge/CassandraBridgeFactory.java b/server/src/main/java/org/apache/cassandra/bridge/CassandraBridgeFactory.java index 466bc4286..6968789fc 100644 --- a/server/src/main/java/org/apache/cassandra/bridge/CassandraBridgeFactory.java +++ b/server/src/main/java/org/apache/cassandra/bridge/CassandraBridgeFactory.java @@ -133,8 +133,8 @@ public ClassLoader buildClassLoader(String... resourceNames) } }).toArray(URL[]::new); - return AccessController.doPrivileged((PrivilegedAction) () -> - new PostDelegationClassLoader(urls, Thread.currentThread().getContextClassLoader())); + return AccessController.doPrivileged( + (PrivilegedAction) () -> new PostDelegationClassLoader(urls, Thread.currentThread().getContextClassLoader())); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/acl/AuthCache.java b/server/src/main/java/org/apache/cassandra/sidecar/acl/AuthCache.java index 92c83c25f..8c2283e83 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/acl/AuthCache.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/acl/AuthCache.java @@ -242,9 +242,13 @@ protected void warmUp(int availableRetries) try { long startTimeNanos = System.nanoTime(); - cache.putAll(bulkLoadFunction.get()); - logger.info("Cache={} warmup completed successfully in {} nanoseconds", - name, System.nanoTime() - startTimeNanos); + Map values = bulkLoadFunction.get(); + if (values != null) + { + cache.putAll(values); + logger.info("Cache={} warmup completed successfully in {} nanoseconds", + name, System.nanoTime() - startTimeNanos); + } } catch (SchemaUnavailableException sue) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CachingSchemaStore.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CachingSchemaStore.java index 8795d2ed1..bb51306f4 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CachingSchemaStore.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CachingSchemaStore.java @@ -186,7 +186,9 @@ void onSchemaChanged() // Remove any old schema entries for deleted tables, this operation can be done in the end as this is // only for removing stale entries and no one is going to use these entries once the table is removed. // This doesn't have to be an atomic operation. - avroSchemasCache.keySet().retainAll(refreshedCdcTables.stream().map(cqlTable -> TableIdentifier.of(cqlTable.keyspace(), cqlTable.table())).collect(Collectors.toList())); + avroSchemasCache.keySet().retainAll(refreshedCdcTables.stream() + .map(cqlTable -> TableIdentifier.of(cqlTable.keyspace(), cqlTable.table())) + .collect(Collectors.toList())); vertx.eventBus().publish(ON_CDC_CACHE_WARMED_UP.address(), "Cdc cache warmed up"); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcAvroSerializer.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcAvroSerializer.java index 1acc7c4bd..48a86af0c 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcAvroSerializer.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcAvroSerializer.java @@ -35,8 +35,8 @@ public CdcAvroSerializer(SchemaStore schemaStore, { super(schemaStore, key -> TypeCache.get(cassandraBridgeFactory - .get(instanceMetadataFetcher.callOnFirstAvailableInstance(instance-> - instance.delegate().nodeSettings()).releaseVersion()).getVersion()) + .get(instanceMetadataFetcher.callOnFirstAvailableInstance( + instance-> instance.delegate().nodeSettings()).releaseVersion()).getVersion()) .getType(key.keyspace, key.type), "org.apache.cassandra"); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcManager.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcManager.java index 215913540..8d6f891e0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcManager.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcManager.java @@ -150,7 +150,8 @@ List buildCdcConsumers() clusterConfigProvider, eventConsumer, schemaSupplier, - () -> org.apache.cassandra.bridge.TokenRange.openClosed(range.startAsBigInt(), range.endAsBigInt()), + () -> org.apache.cassandra.bridge.TokenRange.openClosed(range.startAsBigInt(), + range.endAsBigInt()), sidecarInstancesProvider, secretsProvider, clientConfig, diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcSchemaSupplier.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcSchemaSupplier.java index 0c55ab531..2736146aa 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcSchemaSupplier.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcSchemaSupplier.java @@ -36,6 +36,7 @@ import org.apache.cassandra.sidecar.db.CdcDatabaseAccessor; import org.apache.cassandra.sidecar.utils.CdcUtil; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.apache.cassandra.spark.data.CqlTable; import org.apache.cassandra.spark.data.ReplicationFactor; import org.apache.cassandra.spark.data.partitioner.Partitioner; @@ -79,7 +80,9 @@ public class CdcSchemaSupplier implements SchemaSupplier private final CdcDatabaseAccessor cdcDatabaseAccessor; private final ConcurrentHashMap tableIdCache = new ConcurrentHashMap<>(); - public CdcSchemaSupplier(InstanceMetadataFetcher instanceMetadataFetcher, CassandraBridgeFactory cassandraBridgeFactory, CdcDatabaseAccessor cdcDatabaseAccessor) + public CdcSchemaSupplier(InstanceMetadataFetcher instanceMetadataFetcher, + CassandraBridgeFactory cassandraBridgeFactory, + CdcDatabaseAccessor cdcDatabaseAccessor) { this.instanceMetadataFetcher = instanceMetadataFetcher; this.cassandraBridgeFactory = cassandraBridgeFactory; @@ -88,8 +91,8 @@ public CdcSchemaSupplier(InstanceMetadataFetcher instanceMetadataFetcher, Cassan public CompletableFuture> getCdcEnabledTables() { - String schema = instanceMetadataFetcher.callOnFirstAvailableInstance(instance-> instance.delegate().metadata().exportSchemaAsString()); - NodeSettings nodeSettings = instanceMetadataFetcher.callOnFirstAvailableInstance(instance-> instance.delegate().nodeSettings()); + String schema = instanceMetadataFetcher.callOnFirstAvailableInstance(instance -> MetadataUtils.describe(instance.delegate().metadata())); + NodeSettings nodeSettings = instanceMetadataFetcher.callOnFirstAvailableInstance(instance -> instance.delegate().nodeSettings()); CassandraBridge cassandraBridge = cassandraBridgeFactory.get(nodeSettings.releaseVersion()); CdcBridge cdcBridge = CdcBridgeFactory.getCdcBridge(cassandraBridge); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarCdcOptions.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarCdcOptions.java index a29687199..2b156ba9f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarCdcOptions.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarCdcOptions.java @@ -42,7 +42,7 @@ public ReplicationFactor replicationFactor(String keyspace) { Map replication = instanceMetadataFetcher - .callOnFirstAvailableInstance(instance-> instance.delegate().metadata().getKeyspace(keyspace).getReplication()); + .callOnFirstAvailableInstance(instance-> instance.delegate().metadata().getKeyspace(keyspace).get().getReplication()); return new ReplicationFactor(replication); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java index 7a4c7df49..a8b3c4baa 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java @@ -19,13 +19,18 @@ package org.apache.cassandra.sidecar.cdc; +import java.util.Collection; import java.util.Set; import java.util.stream.Collectors; -import com.datastax.driver.core.Host; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.TokenMap; import org.apache.cassandra.cdc.sidecar.ClusterConfigProvider; import org.apache.cassandra.sidecar.common.response.NodeSettings; +import org.apache.cassandra.sidecar.coordination.CassandraClientTokenRingProvider; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.apache.cassandra.spark.data.partitioner.CassandraInstance; import org.apache.cassandra.spark.data.partitioner.Partitioner; @@ -56,14 +61,15 @@ public String dc() public Set getCluster() { - Set hosts = instanceMetadataFetcher.callOnFirstAvailableInstance(instance -> - instance.delegate().metadata().getAllHosts()); + Metadata metadata = instanceMetadataFetcher.callOnFirstAvailableInstance(instance -> instance.delegate().metadata()); + TokenMap tokenMap = metadata.getTokenMap().get(); + Collection hosts = metadata.getNodes().values(); return hosts.stream() - .filter(host -> host.getListenAddress() != null) - .flatMap(host -> host.getTokens().stream() + .filter(host -> host.getListenAddress().isPresent()) + .flatMap(host -> tokenMap.getTokens(host).stream() .map(token -> new CassandraInstance( - token.toString(), - host.getEndPoint().resolve().getHostName(), + CassandraClientTokenRingProvider.tokenToString(token), + MetadataUtils.resolveEndpoint(host).getHostName(), host.getDatacenter() )) ).collect(Collectors.toSet()); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/StateSidecarCdcCassandraClient.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/StateSidecarCdcCassandraClient.java index 76d56e52e..e7991663d 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/StateSidecarCdcCassandraClient.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/StateSidecarCdcCassandraClient.java @@ -20,9 +20,10 @@ import java.nio.ByteBuffer; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; -import com.datastax.driver.core.ResultSetFuture; +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import org.apache.cassandra.bridge.TokenRange; import org.apache.cassandra.cdc.sidecar.SidecarCdcCassandraClient; import org.apache.cassandra.sidecar.db.CdcDatabaseAccessor; @@ -41,7 +42,7 @@ public StateSidecarCdcCassandraClient(CdcDatabaseAccessor cdcDatabaseAccessor) this.cdcDatabaseAccessor = cdcDatabaseAccessor; } - public List storeStateAsync(@NotNull String jobId, @NotNull TokenRange range, @NotNull ByteBuffer buf, long timestamp) + public List> storeStateAsync(@NotNull String jobId, @NotNull TokenRange range, @NotNull ByteBuffer buf, long timestamp) { return cdcDatabaseAccessor.storeStateAsync(jobId, range, buf, timestamp); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java index 491ec3621..abe1a0846 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java @@ -27,30 +27,28 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import java.time.Duration; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.NettyOptions; -import com.datastax.driver.core.PlainTextAuthProvider; -import com.datastax.driver.core.QueryOptions; -import com.datastax.driver.core.RemoteEndpointAwareNettySSLOptions; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.exceptions.DriverException; -import com.datastax.driver.core.exceptions.DriverInternalError; -import com.datastax.driver.core.policies.ExponentialReconnectionPolicy; -import com.datastax.driver.core.policies.LoadBalancingPolicy; -import com.datastax.driver.core.policies.ReconnectionPolicy; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.CqlSessionBuilder; +import com.datastax.oss.driver.api.core.DriverException; +import com.datastax.oss.driver.api.core.DriverExecutionException; +import com.datastax.oss.driver.api.core.config.DriverConfigLoader; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.internal.core.connection.ExponentialReconnectionPolicy; +import org.apache.cassandra.sidecar.cluster.driver.MultiplexingNodeStateListener; import org.apache.cassandra.sidecar.cluster.driver.SidecarLoadBalancingPolicy; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; @@ -64,6 +62,15 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.VisibleForTesting; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.METADATA_SCHEMA_REFRESHED_KEYSPACES; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.RECONNECTION_BASE_DELAY; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.RECONNECTION_MAX_DELAY; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.RECONNECTION_POLICY_CLASS; +import static com.datastax.oss.driver.api.core.config.DefaultDriverOption.REPREPARE_ENABLED; +import static org.apache.cassandra.sidecar.cluster.driver.CustomDriverOption.LOCAL_INSTANCES; +import static org.apache.cassandra.sidecar.cluster.driver.CustomDriverOption.NUM_CONNECTIONS; import static org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException.Service.CQL; /** @@ -77,21 +84,20 @@ public class CQLSessionProviderImpl implements CQLSessionProvider private final int numAdditionalConnections; private final String localDc; private final SslConfiguration sslConfiguration; - private final NettyOptions nettyOptions; - private final ReconnectionPolicy reconnectionPolicy; private final List localInstances; + private final MultiplexingNodeStateListener multiplexingNodeStateListener; private final String username; private final String password; + private final long healthCheckFrequencyMillis; private final DriverUtils driverUtils; - private volatile Session session; + private volatile CqlSession session; @VisibleForTesting public CQLSessionProviderImpl(List contactPoints, List localInstances, int healthCheckFrequencyMillis, String localDc, - int numAdditionalConnections, - NettyOptions options) + int numAdditionalConnections) { this(contactPoints, localInstances, @@ -100,8 +106,7 @@ public CQLSessionProviderImpl(List contactPoints, numAdditionalConnections, null, null, - null, - options); + null); } @VisibleForTesting @@ -112,8 +117,7 @@ public CQLSessionProviderImpl(List contactPoints, int numAdditionalConnections, String username, String password, - SslConfiguration sslConfiguration, - NettyOptions options) + SslConfiguration sslConfiguration) { this.contactPoints = contactPoints; this.localInstances = localInstances; @@ -122,13 +126,12 @@ public CQLSessionProviderImpl(List contactPoints, this.username = username; this.password = password; this.sslConfiguration = sslConfiguration; - this.nettyOptions = options; - this.reconnectionPolicy = new ExponentialReconnectionPolicy(500, healthCheckFrequencyMillis); + this.healthCheckFrequencyMillis = healthCheckFrequencyMillis; + this.multiplexingNodeStateListener = new MultiplexingNodeStateListener(); this.driverUtils = new DriverUtils(); } public CQLSessionProviderImpl(SidecarConfiguration configuration, - NettyOptions options, DriverUtils driverUtils) { this.driverUtils = driverUtils; @@ -143,9 +146,8 @@ public CQLSessionProviderImpl(SidecarConfiguration configuration, this.password = driverConfiguration.password(); this.sslConfiguration = driverConfiguration.sslConfiguration(); this.numAdditionalConnections = driverConfiguration.numConnections(); - this.nettyOptions = options; - long maxDelayMs = configuration.healthCheckConfiguration().executeInterval().toMillis(); - this.reconnectionPolicy = new ExponentialReconnectionPolicy(500, maxDelayMs); + this.healthCheckFrequencyMillis = configuration.healthCheckConfiguration().executeInterval().toMillis(); + this.multiplexingNodeStateListener = new MultiplexingNodeStateListener(); } static RuntimeException propagateCause(ExecutionException e) @@ -155,13 +157,12 @@ static RuntimeException propagateCause(ExecutionException e) if (cause instanceof Error) throw ((Error) cause); // We could just rethrow e.getCause(). However, the cause of the ExecutionException has likely - // been - // created on the I/O thread receiving the response. Which means that the stacktrace associated + // been created on the I/O thread receiving the response. Which means that the stacktrace associated // with said cause will make no mention of the current thread. This is painful for say, finding // out which execute() statement actually raised the exception. So instead, we re-create the // exception. if (cause instanceof DriverException) throw ((DriverException) cause).copy(); - else throw new DriverInternalError("Unexpected exception thrown", cause); + else throw new DriverExecutionException(cause); } /** @@ -173,88 +174,78 @@ static RuntimeException propagateCause(ExecutionException e) */ @Override @NotNull - public synchronized Session get() throws CassandraUnavailableException + public synchronized CqlSession get() throws CassandraUnavailableException { if (session != null) { return session; } - Cluster cluster = null; try { logger.info("Connecting to cluster using contact points {}", contactPoints); + DriverConfigLoader configLoader = + DriverConfigLoader.programmaticBuilder() + .withString(LOAD_BALANCING_LOCAL_DATACENTER, localDc) + .withInt(NUM_CONNECTIONS, numAdditionalConnections) + .withStringList(LOCAL_INSTANCES, localInstances + .stream() + .map(i -> i.getHostString() + ":" + i.getPort()) + .collect(Collectors.toList())) + .withClass(LOAD_BALANCING_POLICY_CLASS, SidecarLoadBalancingPolicy.class) + .withClass(RECONNECTION_POLICY_CLASS, ExponentialReconnectionPolicy.class) + .withDuration(RECONNECTION_BASE_DELAY, Duration.ofMillis(500)) + .withDuration(RECONNECTION_MAX_DELAY, Duration.ofMillis(healthCheckFrequencyMillis)) + .withBoolean(REPREPARE_ENABLED, false) + .withStringList(METADATA_SCHEMA_REFRESHED_KEYSPACES, Collections.emptyList()) + .build(); + CqlSessionBuilder builder = CqlSession.builder() + .addContactPoints(contactPoints) + .withNodeStateListener(multiplexingNodeStateListener) + .withConfigLoader(configLoader); - LoadBalancingPolicy lbp = new SidecarLoadBalancingPolicy(localInstances, localDc, numAdditionalConnections, - driverUtils); - // Prevent spurious reconnects of ignored down nodes on `onUp` events - QueryOptions queryOptions = new QueryOptions().setReprepareOnUp(false); - Cluster.Builder builder - = Cluster.builder() - .addContactPointsWithPorts(contactPoints) - .withReconnectionPolicy(reconnectionPolicy) - .withoutMetrics() - .withLoadBalancingPolicy(lbp) - .withQueryOptions(queryOptions) - // tests can create a lot of these Cluster objects, to avoid creating HWTs and - // event thread pools for each we have the override - .withNettyOptions(nettyOptions); - - SslContext sslContext = createSslContext(sslConfiguration); - if (sslContext != null) - { - RemoteEndpointAwareNettySSLOptions sslOptions - = new RemoteEndpointAwareNettySSLOptions(sslContext); - builder.withSSL(sslOptions); - } + SSLContext sslContext = createSslContext(sslConfiguration); + builder.withSslContext(sslContext); if (username != null && password != null) { - builder.withCredentials(username, password); - } - // During mTLS connections, when client sends in keystore, we should have an AuthProvider passed along. - // hence we pass empty username and password in PlainTextAuthProvider here, in case user hasn't already - // configured username and password. - else if (sslConfiguration != null && sslConfiguration.isKeystoreConfigured()) - { - builder.withAuthProvider(new PlainTextAuthProvider("", "")); + builder.withAuthCredentials(username, password); } - cluster = builder.build(); - session = cluster.connect(); + session = builder.build(); logger.info("Successfully connected to Cassandra!"); return session; } catch (Exception connectionException) { logger.error("Failed to reach Cassandra", connectionException); - if (cluster != null) - { - try - { - cluster.close(); - } - catch (Exception closeException) - { - logger.error("Failed to close cluster in cleanup", closeException); - connectionException.addSuppressed(closeException); - } - } throw new CassandraUnavailableException(CQL, connectionException); } } @Override @Nullable - public Session getIfConnected() + public CqlSession getIfConnected() { return session; } + @Override + public void registerNodeStateListener(NodeStateListener nodeStateListener) + { + multiplexingNodeStateListener.register(nodeStateListener); + } + + @Override + public void unregisterNodeStateListener(NodeStateListener nodeStateListener) + { + multiplexingNodeStateListener.unregister(nodeStateListener); + } + @Override public void close() { - Session localSession; + CqlSession localSession; synchronized (this) { localSession = this.session; @@ -264,7 +255,7 @@ public void close() { try { - localSession.getCluster().closeAsync().get(1, TimeUnit.MINUTES); + localSession.closeAsync().toCompletableFuture().get(1, TimeUnit.MINUTES); } catch (InterruptedException e) { @@ -286,41 +277,44 @@ public void close() * SSL connection, the driver only needs to provide the truststore, while Cassandra supplies its keystore for * validation. In the case of an mTLS connection, both the keystore and truststore are configured on the driver side. */ - private SslContext createSslContext(SslConfiguration sslConfiguration) + private SSLContext createSslContext(SslConfiguration sslConfiguration) { if (sslConfiguration == null || !sslConfiguration.enabled()) { return null; } - SslContextBuilder sslContextBuilder; try { - sslContextBuilder = SslContextBuilder.forClient() - .protocols(sslConfiguration.secureTransportProtocols()); + // TODO(lantoniak): Multiple protocols are not supported. + SSLContext sslContext = SSLContext.getInstance(sslConfiguration.secureTransportProtocols().get(0)); + KeyManagerFactory kmf = null; if (sslConfiguration.isKeystoreConfigured()) { KeyStore keyStore = createKeystore(sslConfiguration.keystore()); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, sslConfiguration.keystore().password().toCharArray()); - sslContextBuilder.keyManager(kmf); } // We set the truststore only if it is configured. For an SSL connection, if the truststore is required // but the user has not provided one, the default Java truststore is used. + TrustManagerFactory tmf = null; if (sslConfiguration.isTrustStoreConfigured()) { KeyStore truststore = createKeystore(sslConfiguration.truststore()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(truststore); - sslContextBuilder.trustManager(tmf); } - return sslContextBuilder.build(); + + sslContext.init(kmf != null ? kmf.getKeyManagers() : null, + tmf != null ? tmf.getTrustManagers() : null, + null); + return sslContext; } catch (Exception e) { - throw new ConfigurationException("Error creating SsLContext for Cassandra connections", e); + throw new ConfigurationException("Error creating SSLContext for Cassandra connections", e); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java index 9ce60c426..776a71437 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java @@ -26,7 +26,9 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Function; import javax.management.Notification; import javax.management.NotificationListener; @@ -35,16 +37,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.ConsistencyLevel; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.SimpleStatement; -import com.datastax.driver.core.Statement; -import com.datastax.driver.core.exceptions.NoHostAvailableException; +import com.datastax.oss.driver.api.core.AllNodesFailedException; +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.internal.core.channel.ChannelEvent; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import org.apache.cassandra.sidecar.common.response.NodeSettings; @@ -85,7 +89,7 @@ *

  • We might need to swap out the adapter if the version has changed
  • * */ -public class CassandraAdapterDelegate implements ICassandraAdapter, Host.StateListener +public class CassandraAdapterDelegate implements ICassandraAdapter, NodeStateListener, Consumer { private static final Logger LOGGER = LoggerFactory.getLogger(CassandraAdapterDelegate.class); @@ -106,7 +110,7 @@ public class CassandraAdapterDelegate implements ICassandraAdapter, Host.StateLi private final AtomicBoolean isHealthCheckActive = new AtomicBoolean(false); private final InetSocketAddress localNativeTransportAddress; private final InstanceHealthMetrics healthMetrics; - private volatile Host host; + private volatile Node host; private volatile boolean closed = false; /** @@ -154,26 +158,30 @@ protected JmxNotificationListener initializeJmxListener() return notificationListener; } - private void maybeRegisterHostListener(@NotNull Session session) + private void maybeRegisterHostListener(@NotNull CqlSession activeSession) { if (!registered.get()) { - Cluster cluster = session.getCluster(); - if (!cluster.isClosed() && registered.compareAndSet(false, true)) + if (!activeSession.isClosed() && registered.compareAndSet(false, true)) { - cluster.register(this); + cqlSessionProvider.registerNodeStateListener(this); + // subscribe to receive reconnection start / stop events + ((InternalDriverContext) cqlSessionProvider.get().getContext()).getEventBus() + .register(ChannelEvent.class, this); } } } - private void maybeUnregisterHostListener(@NotNull Session session) + private void maybeUnregisterHostListener(@NotNull CqlSession activeSession) { if (registered.get()) { - Cluster cluster = session.getCluster(); - if (!cluster.isClosed() && registered.compareAndSet(true, false)) + if (!activeSession.isClosed() && registered.compareAndSet(true, false)) { - cluster.unregister(this); + cqlSessionProvider.unregisterNodeStateListener(this); + // subscribe to receive reconnection start / stop events + ((InternalDriverContext) cqlSessionProvider.get().getContext()).getEventBus() + .unregister(this, ChannelEvent.class); } } } @@ -248,7 +256,7 @@ protected synchronized void jmxHealthCheck() */ protected void nativeProtocolHealthCheck() { - Session activeSession; + CqlSession activeSession; try { activeSession = cqlSessionProvider.get(); @@ -266,7 +274,7 @@ protected void nativeProtocolHealthCheck() try { // NOTE: We cannot use `executeLocal` here as there may be no adapter yet. - Metadata metadata = activeSession.getCluster().getMetadata(); + Metadata metadata = activeSession.getMetadata(); host = getHost(metadata); if (host == null) { @@ -285,7 +293,7 @@ protected void nativeProtocolHealthCheck() notifyNativeConnection(); } } - catch (IllegalArgumentException | NoHostAvailableException e) + catch (IllegalArgumentException | AllNodesFailedException e) { LOGGER.debug("Unexpected error querying Cassandra instance {}", cassandraInstanceId, e); // The cassandra native protocol connection to the node is down. @@ -340,7 +348,7 @@ protected List maybeGetTokens(LimitedStorageOperations storageOperations } } - protected Host getHost(Metadata metadata) + protected Node getHost(Metadata metadata) { if (host == null) { @@ -405,7 +413,7 @@ public Map v2NodeSettings() throws CassandraUnavailableException @Override @NotNull - public ResultSet executeLocal(Statement statement) throws CassandraUnavailableException + public ResultSet executeLocal(Statement statement) throws CassandraUnavailableException { return fromAdapter(adapter -> adapter.executeLocal(statement)); } @@ -467,41 +475,44 @@ public CompactionStatsOperations compactionStatsOperations() throws CassandraUna } @Override - public void onAdd(Host host) + public void accept(ChannelEvent channelEvent) { - LOGGER.debug("Host added. host={}", host); - runIfThisHost(host, this::healthCheck); - } - - @Override - public void onUp(Host host) - { - LOGGER.debug("Host up. host={}", host); - runIfThisHost(host, this::healthCheck); + if (channelEvent.type == ChannelEvent.Type.RECONNECTION_STARTED) + { + onRemove(channelEvent.node); + } + if (channelEvent.type == ChannelEvent.Type.RECONNECTION_STOPPED) + { + onUp(channelEvent.node); + } } @Override - public void onDown(Host host) + public void onAdd(@NotNull Node host) { - LOGGER.debug("Host down. host={}", host); - runIfThisHost(host, this::markNativeDownAndMaybeNotifyDisconnection); + LOGGER.debug("Host added. host={}", host); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck)); } @Override - public void onRemove(Host host) + public void onUp(@NotNull Node host) { - LOGGER.debug("Host removed. host={}", host); - runIfThisHost(host, this::healthCheck); + LOGGER.debug("Host up. host={}", host); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck)); } @Override - public void onRegister(Cluster cluster) + public void onDown(@NotNull Node host) { + LOGGER.debug("Host down. host={}", host); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::markNativeDownAndMaybeNotifyDisconnection)); } @Override - public void onUnregister(Cluster cluster) + public void onRemove(@NotNull Node host) { + LOGGER.debug("Host removed. host={}", host); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck)); } /** @@ -525,7 +536,7 @@ public void close() closed = true; markNativeDownAndMaybeNotifyDisconnection(); markJmxDownAndMaybeNotifyDisconnection(); - Session activeSession = cqlSessionProvider.getIfConnected(); + CqlSession activeSession = cqlSessionProvider.getIfConnected(); if (activeSession != null) { maybeUnregisterHostListener(activeSession); @@ -596,11 +607,11 @@ protected void markJmxDownAndMaybeNotifyDisconnection() } } - protected Map queryNodeSettingsFromCql(Session activeSession, Host host) + protected Map queryNodeSettingsFromCql(CqlSession activeSession, Node host) { - SimpleStatement allSystemSettingsStatement = new SimpleStatement("SELECT name, value FROM system_views.settings"); - allSystemSettingsStatement.setHost(host); - allSystemSettingsStatement.setConsistencyLevel(ConsistencyLevel.ONE); + SimpleStatement allSystemSettingsStatement = SimpleStatement.newInstance("SELECT name, value FROM system_views.settings") + .setNode(host) + .setConsistencyLevel(ConsistencyLevel.ONE); ResultSet result = activeSession.execute(allSystemSettingsStatement); Map nodeSettings = new HashMap<>(); for (Row setting : result.all()) @@ -621,7 +632,7 @@ private T fromAdapter(Function getter) throws Cassandr return getter.apply(localAdapter); } - private void runIfThisHost(Host host, Runnable runnable) + private void runIfThisHost(Node host, Runnable runnable) { if (this.localNativeTransportAddress.equals(driverUtils.getSocketAddress(host))) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java new file mode 100644 index 000000000..cd656d277 --- /dev/null +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.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 org.apache.cassandra.sidecar.cluster.driver; + +import com.datastax.oss.driver.api.core.config.DriverOption; +import org.jspecify.annotations.NonNull; + +/** + * Custom driver options required by {@code SidecarLoadBalancingPolicy}. + */ +public enum CustomDriverOption implements DriverOption +{ + NUM_CONNECTIONS("basic.load-balancing-policy.num-connections"), + LOCAL_INSTANCES("basic.load-balancing-policy.local-instances"); + + private final String path; + + CustomDriverOption(String path) + { + this.path = path; + } + + @Override + @NonNull + public String getPath() + { + return path; + } +} diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java new file mode 100644 index 000000000..b2c751e8b --- /dev/null +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.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 org.apache.cassandra.sidecar.cluster.driver; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.internal.core.util.Loggers; + +/** + * Combines multiple node state listeners into a single one. + * Implementation note: Copied from Java driver, but with unregistering functionality. + * + *

    Any exception thrown by a child listener is caught and logged. + */ +public class MultiplexingNodeStateListener implements NodeStateListener +{ + private static final Logger LOG = LoggerFactory.getLogger(MultiplexingNodeStateListener.class); + + private final List listeners = new CopyOnWriteArrayList<>(); + + public MultiplexingNodeStateListener() + { + } + + public MultiplexingNodeStateListener(NodeStateListener... listeners) + { + this(Arrays.asList(listeners)); + } + + public MultiplexingNodeStateListener(Collection listeners) + { + addListeners(listeners); + } + + private void addListeners(Collection source) + { + for (NodeStateListener listener : source) + { + addListener(listener); + } + } + + private void addListener(NodeStateListener toAdd) + { + Objects.requireNonNull(toAdd, "listener cannot be null"); + if (toAdd instanceof MultiplexingNodeStateListener) + { + addListeners(((MultiplexingNodeStateListener) toAdd).listeners); + } + else + { + listeners.add(toAdd); + } + } + + private void removeListeners(Collection source) + { + for (NodeStateListener listener : source) + { + removeListener(listener); + } + } + + private void removeListener(NodeStateListener toRemove) + { + Objects.requireNonNull(toRemove, "listener cannot be null"); + if (toRemove instanceof MultiplexingNodeStateListener) + { + removeListeners(((MultiplexingNodeStateListener) toRemove).listeners); + } + else + { + listeners.remove(toRemove); + } + } + + public void register(NodeStateListener listener) + { + addListener(listener); + } + + public void unregister(NodeStateListener listener) + { + addListener(listener); + } + + @Override + public void onAdd(Node node) + { + invokeListeners(listener -> listener.onAdd(node), "onAdd"); + } + + @Override + public void onUp(Node node) + { + invokeListeners(listener -> listener.onUp(node), "onUp"); + } + + @Override + public void onDown(Node node) + { + invokeListeners(listener -> listener.onDown(node), "onDown"); + } + + @Override + public void onRemove(Node node) + { + invokeListeners(listener -> listener.onRemove(node), "onRemove"); + } + + @Override + public void onSessionReady(Session session) + { + invokeListeners(listener -> listener.onSessionReady(session), "onSessionReady"); + } + + @Override + public void close() throws Exception + { + for (NodeStateListener listener : listeners) + { + try + { + listener.close(); + } + catch (Exception e) + { + Loggers.warnWithException( + LOG, "Unexpected error while closing node state listener {}.", listener, e); + } + } + } + + private void invokeListeners(Consumer action, String event) + { + for (NodeStateListener listener : listeners) + { + try + { + action.accept(listener); + } + catch (Exception e) + { + Loggers.warnWithException(LOG, "Unexpected error while notifying node state listener {} of an {} event.", + listener, event, e); + } + } + } +} diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java index 2aa276618..bcb9695f3 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java @@ -19,56 +19,57 @@ package org.apache.cassandra.sidecar.cluster.driver; import java.net.InetSocketAddress; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.Random; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; -import com.google.common.collect.Iterators; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.HostDistance; -import com.datastax.driver.core.Statement; -import com.datastax.driver.core.policies.DCAwareRoundRobinPolicy; -import com.datastax.driver.core.policies.LoadBalancingPolicy; -import com.datastax.driver.core.policies.RoundRobinPolicy; -import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; +import com.datastax.oss.driver.api.core.context.DriverContext; +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.core.session.Request; +import com.datastax.oss.driver.api.core.session.Session; +import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy; +import org.apache.cassandra.sidecar.utils.MetadataUtils; +import org.jetbrains.annotations.NotNull; /** * The SidecarLoadBalancingPolicy is designed to ensure that the Cassandra Metadata objects associated with the * CqlSessionProvider have enough non-local hosts in their allowed connections to be kept up-to-date * even if the local Cassandra instances are down/have their native transport disabled. - * NOTE: This policy won't work with a child policy that is token-aware */ -public class SidecarLoadBalancingPolicy implements LoadBalancingPolicy +public class SidecarLoadBalancingPolicy extends DefaultLoadBalancingPolicy { public static final int MIN_NON_LOCAL_CONNECTIONS = 2; private static final Logger LOGGER = LoggerFactory.getLogger(SidecarLoadBalancingPolicy.class); - private final Set selectedHosts = new HashSet<>(); + private final Random random = new Random(); + private final Set localHostAddresses; - private final DriverUtils driverUtils; - private final LoadBalancingPolicy childPolicy; + private final HashSet allHosts = new HashSet<>(); private final int totalRequestedConnections; - private final Random random = new Random(); - private final HashSet allHosts = new HashSet<>(); - private Cluster cluster; + private final Set selectedHosts = new HashSet<>(); - public SidecarLoadBalancingPolicy(List localHostAddresses, - String localDc, - int numAdditionalConnections, - DriverUtils driverUtils) + public SidecarLoadBalancingPolicy(DriverContext context, String profileName) { - this.childPolicy = createChildPolicy(localDc); - this.localHostAddresses = new HashSet<>(localHostAddresses); - this.driverUtils = driverUtils; + super(context, profileName); + List localInstances = context.getConfig().getDefaultProfile().getStringList(CustomDriverOption.LOCAL_INSTANCES) + .stream() + .map(i -> { + String[] hostPort = i.split(":"); + return new InetSocketAddress(hostPort[0], Integer.parseInt(hostPort[1])); + }) + .collect(Collectors.toList()); + int numAdditionalConnections = context.getConfig().getDefaultProfile().getInt(CustomDriverOption.NUM_CONNECTIONS); + this.localHostAddresses = new HashSet<>(localInstances); if (numAdditionalConnections < MIN_NON_LOCAL_CONNECTIONS) { LOGGER.warn("Additional instances requested was {}, which is less than the minimum of {}. Using {}.", @@ -79,108 +80,68 @@ public SidecarLoadBalancingPolicy(List localHostAddresses, } @Override - public void init(Cluster cluster, Collection hosts) + public void init(Map nodes, @NotNull DistanceReporter distanceReporter) { - this.cluster = cluster; - this.allHosts.addAll(hosts); - recalculateSelectedHosts(); - childPolicy.init(cluster, hosts); + this.allHosts.addAll(nodes.values()); + recalculateSelectedHosts(true); + super.init(nodes, distanceReporter); } @Override - public HostDistance distance(Host host) + protected NodeDistance computeNodeDistance(@NotNull Node node) { - if (selectedHosts.contains(host) || isLocalHost(host)) + if (selectedHosts.contains(node) || isLocalHost(node)) { - return childPolicy.distance(host); + return super.computeNodeDistance(node); } - return HostDistance.IGNORED; - } - - @Override - public Iterator newQueryPlan(String loggedKeyspace, Statement statement) - { - Iterator child = childPolicy.newQueryPlan(loggedKeyspace, statement); - // Filter the child policy to only selected hosts - return Iterators.filter(child, selectedHosts::contains); + return NodeDistance.IGNORED; } @Override - public synchronized void onAdd(Host host) + public @NotNull Queue newQueryPlan(Request request, Session session) { - onUp(host); - childPolicy.onAdd(host); + Queue plan = super.newQueryPlan(request, session); + plan.removeIf(n -> !selectedHosts.contains(n)); + return plan; } @Override - public synchronized void onUp(Host host) + public synchronized void onUp(@NotNull Node node) { - this.allHosts.add(host); // replace existing reference if there is one + this.allHosts.add(node); // replace existing reference if there is one if (selectedHosts.size() < totalRequestedConnections) { - recalculateSelectedHosts(); + recalculateSelectedHosts(false); } - childPolicy.onUp(host); + super.onUp(node); } @Override - public synchronized void onDown(Host host) + public synchronized void onDown(@NotNull Node node) { // Don't remove local addresses from the selected host list - if (localHostAddresses.contains(driverUtils.getSocketAddress(host))) + if (localHostAddresses.contains(MetadataUtils.resolveEndpoint(node))) { - LOGGER.debug("Local Node {} has been marked down.", host); + LOGGER.debug("Local Node {} has been marked down.", node); return; } - - boolean wasSelected = selectedHosts.remove(host); - if (!wasSelected) - { - // Non-selected nodes have been marked with HostDistance.IGNORED - // even if they may otherwise be useful. This has a side effect - // of preventing the driver from trying to reconnect to them - // if we miss the `onUp` event, so we need to schedule reconnects - // for these hosts explicitly unless we have active connections. - driverUtils.startPeriodicReconnectionAttempt(cluster, host); - } - recalculateSelectedHosts(); - childPolicy.onDown(host); + recalculateSelectedHosts(false); + super.onDown(node); } @Override - public synchronized void onRemove(Host host) + public void onRemove(@NotNull Node node) { - this.allHosts.remove(host); - onDown(host); - childPolicy.onRemove(host); - } - - @Override - public void close() - { - childPolicy.close(); - } - - /** - * Creates the child policy based on the presence of a local datacenter - * - * @param localDc the local datacenter to use, or null - * @return a {@link LoadBalancingPolicy} - */ - private LoadBalancingPolicy createChildPolicy(String localDc) - { - if (localDc != null) - { - return DCAwareRoundRobinPolicy.builder().withLocalDc(localDc).build(); - } - return new RoundRobinPolicy(); + this.allHosts.remove(node); + onDown(node); + super.onRemove(node); } - private synchronized void recalculateSelectedHosts() + private synchronized void recalculateSelectedHosts(boolean initiation) { - Map> partitionedHosts = allHosts.stream() + Map> partitionedHosts = allHosts.stream() .collect(Collectors.partitioningBy(this::isLocalHost)); - List localHosts = partitionedHosts.get(true); + List localHosts = partitionedHosts.get(true); int numLocalHostsConfigured = localHostAddresses.size(); if (localHosts == null || localHosts.isEmpty()) { @@ -198,7 +159,7 @@ private synchronized void recalculateSelectedHosts() int requiredNonLocalHosts = this.totalRequestedConnections - selectedHosts.size(); if (requiredNonLocalHosts > 0) { - List nonLocalHosts = partitionedHosts.get(false); + List nonLocalHosts = partitionedHosts.get(false); if (nonLocalHosts == null || nonLocalHosts.isEmpty()) { LOGGER.debug("Did not find any non-local hosts in allHosts"); @@ -207,7 +168,9 @@ private synchronized void recalculateSelectedHosts() // Remove down and already selected hosts from consideration nonLocalHosts = nonLocalHosts.stream() - .filter(h -> !selectedHosts.contains(h) && h.isUp()) + .filter(h -> !selectedHosts.contains(h) + && (NodeState.UP.equals(h.getState()) + || (initiation && NodeState.UNKNOWN.equals(h.getState())))) .collect(Collectors.toList()); if (nonLocalHosts.size() < requiredNonLocalHosts) @@ -232,8 +195,8 @@ private synchronized void recalculateSelectedHosts() } } - private boolean isLocalHost(Host host) + private boolean isLocalHost(Node host) { - return localHostAddresses.contains(driverUtils.getSocketAddress(host)); + return localHostAddresses.contains(MetadataUtils.resolveEndpoint(host)); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java index c70a69080..09e7c7964 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java @@ -22,6 +22,7 @@ import java.net.UnknownHostException; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -38,14 +39,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import org.apache.cassandra.sidecar.cluster.InstancesMetadata; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException; +import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.jetbrains.annotations.NotNull; /** @@ -61,9 +63,9 @@ public class CachedLocalTokenRanges implements LocalTokenRangesProvider @GuardedBy("this") private Set localInstanceIdsCache; @GuardedBy("this") - private Set allInstancesCache; + private Set allInstancesCache; @GuardedBy("this") - private Set localInstancesCache; + private Set localInstancesCache; @GuardedBy("this") private ImmutableMap>> localTokenRangesCache; @@ -104,7 +106,7 @@ public Map> localTokenRanges(String keyspace, boolean f return Collections.emptyMap(); } - if (metadata.getKeyspace(keyspace) == null) + if (metadata.getKeyspace(keyspace).isEmpty()) { throw new NoSuchElementException("Keyspace does not exist. keyspace: " + keyspace); } @@ -112,7 +114,7 @@ public Map> localTokenRanges(String keyspace, boolean f Set localInstanceIds = localInstances.stream() .map(InstanceMetadata::id) .collect(Collectors.toSet()); - Set allInstances = metadata.getAllHosts(); + Set allInstances = new HashSet<>(metadata.getNodes().values()); return getCacheOrReload(metadata, keyspace, localInstanceIds, localInstances, allInstances); } @@ -121,12 +123,12 @@ public Map> localTokenRanges(String keyspace, boolean f * The result set is unmodifiable. */ @Nullable - private Pair> tokenRangesOfHost(Metadata metadata, + private Pair> tokenRangesOfHost(Metadata metadata, String keyspace, InstanceMetadata instance, - Map allHosts) + Map allHosts) { - Host host; + Node host; try { final IpAddressAndPort ip = IpAddressAndPort.of(dnsResolver.resolve(instance.host()), instance.port()); @@ -145,9 +147,9 @@ private Pair> tokenRangesOfHost(Metadata metadata, return Pair.of(host, tokenRangesOfHost(metadata, keyspace, host)); } - public Set tokenRangesOfHost(Metadata metadata, String keyspace, Host host) + public Set tokenRangesOfHost(Metadata metadata, String keyspace, Node host) { - return metadata.getTokenRanges(keyspace, host) + return metadata.getTokenMap().get().getTokenRanges(keyspace, host) .stream() .flatMap(range -> TokenRange.from(range).stream()) .collect(Collectors.toSet()); @@ -160,7 +162,7 @@ private synchronized Map> getCacheOrReload(Metadata met String keyspace, Set localInstanceIds, List localInstances, - Set allInstances) + Set allInstances) { // exit early if no change is found boolean isClusterTheSame = allInstances.equals(allInstancesCache) @@ -179,49 +181,49 @@ private synchronized Map> getCacheOrReload(Metadata met { LOGGER.warn("No instances found in client session"); } - Map allHosts = new HashMap<>(allInstancesCache.size()); - BiConsumer putNullSafe = (endpoint, host) -> { + Map allHosts = new HashMap<>(allInstancesCache.size()); + BiConsumer putNullSafe = (endpoint, host) -> { if (endpoint != null) { allHosts.put(IpAddressAndPort.of(endpoint), host); } }; - for (Host host : allInstancesCache) + for (Node host : allInstancesCache) { - putNullSafe.accept(host.getSocketAddress(), host); - putNullSafe.accept(host.getListenSocketAddress(), host); - putNullSafe.accept(host.getBroadcastSocketAddress(), host); + putNullSafe.accept(MetadataUtils.resolveEndpoint(host), host); + putNullSafe.accept(host.getListenAddress().orElse(null), host); + putNullSafe.accept(host.getBroadcastAddress().orElse(null), host); } ImmutableMap.Builder>> perKeyspaceBuilder = ImmutableMap.builder(); - ImmutableSet.Builder hostBuilder = ImmutableSet.builder(); + ImmutableSet.Builder hostBuilder = ImmutableSet.builder(); if (isClusterTheSame && localInstancesCache != null) { hostBuilder.addAll(localInstancesCache); } - for (KeyspaceMetadata ks : metadata.getKeyspaces()) + for (KeyspaceMetadata ks : metadata.getKeyspaces().values()) { - if (isClusterTheSame && localTokenRangesCache != null && localTokenRangesCache.containsKey(ks.getName())) + if (isClusterTheSame && localTokenRangesCache != null && localTokenRangesCache.containsKey(ks.getName().asInternal())) { // we don't need to rebuild if already cached - Map> value = localTokenRangesCache.get(ks.getName()); + Map> value = localTokenRangesCache.get(ks.getName().asInternal()); if (value != null) - perKeyspaceBuilder.put(ks.getName(), value); + perKeyspaceBuilder.put(ks.getName().asInternal(), value); } else { ImmutableMap.Builder> resultBuilder = ImmutableMap.builder(); for (InstanceMetadata instance : localInstances) { - Pair> pair = tokenRangesOfHost(metadata, keyspace, instance, allHosts); + Pair> pair = tokenRangesOfHost(metadata, keyspace, instance, allHosts); if (pair != null) { hostBuilder.add(pair.getKey()); resultBuilder.put(instance.id(), Collections.unmodifiableSet(pair.getValue())); } } - perKeyspaceBuilder.put(ks.getName(), resultBuilder.build()); + perKeyspaceBuilder.put(ks.getName().asInternal(), resultBuilder.build()); } } localTokenRangesCache = perKeyspaceBuilder.build(); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/codecs/DcLocalTopologyChangeEventCodec.java b/server/src/main/java/org/apache/cassandra/sidecar/codecs/DcLocalTopologyChangeEventCodec.java index 775392d87..2a914ed38 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/codecs/DcLocalTopologyChangeEventCodec.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/codecs/DcLocalTopologyChangeEventCodec.java @@ -36,7 +36,8 @@ /** * Message codec for encoding and decoding datacenter-local topology change events over the Vert.x event bus. */ -public class DcLocalTopologyChangeEventCodec implements MessageCodec +public class DcLocalTopologyChangeEventCodec implements MessageCodec { public static final DcLocalTopologyChangeEventCodec INSTANCE = new DcLocalTopologyChangeEventCodec(); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java index ed55de856..97f8fc9b0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java @@ -21,6 +21,7 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -40,11 +41,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.Token; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.token.Token; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.client.SidecarInstance; @@ -69,9 +71,9 @@ public class CassandraClientTokenRingProvider extends TokenRingProvider implemen @GuardedBy("this") private volatile Map>> assignedRangesOfAllInstancesByDcCache = null; @GuardedBy("this") - private volatile Map localHostsCache = null; + private volatile Map localHostsCache = null; @GuardedBy("this") - private volatile Set allInstancesCache = null; + private volatile Set allInstancesCache = null; @Inject public CassandraClientTokenRingProvider(InstancesMetadata instancesMetadata, InstanceMetadataFetcher instanceMetadataFetcher, DnsResolver dnsResolver) @@ -85,7 +87,7 @@ public Map> localTokenRanges(String keyspace, boolean f { checkAndReloadReloadCaches(); Metadata metadata = instancesMetadata.instances().get(0).delegate().metadata(); - if (keyspace == null || metadata.getKeyspace(keyspace) == null) + if (keyspace == null || metadata.getKeyspace(keyspace).isEmpty()) { throw new NoSuchElementException("Keyspace does not exist. keyspace: " + keyspace); } @@ -96,13 +98,13 @@ public Map> localTokenRanges(String keyspace, boolean f .collect(Collectors.toMap(entry -> localHostsCache.get(entry.getKey()), Map.Entry::getValue)); } - public Set localInstances() + public Set localInstances() { checkAndReloadReloadCaches(); return localHostsCache.keySet(); } - public Set allInstances() + public Set allInstances() { checkAndReloadReloadCaches(); return allInstancesCache; @@ -138,7 +140,7 @@ public Set dcs() { List localInstances = instancesMetadata.instances(); Metadata metadata = validatedMetadata(localInstances); - return metadata.getAllHosts().stream().map(Host::getDatacenter).collect(Collectors.toSet()); + return metadata.getNodes().values().stream().map(Node::getDatacenter).collect(Collectors.toSet()); } @Override @@ -149,7 +151,7 @@ public Partitioner partitioner() public static Partitioner extractPartitioner(Metadata metadata) { - String[] tokens = metadata.getPartitioner().split("\\."); + String[] tokens = metadata.getTokenMap().get().getPartitionerName().split("\\."); return Partitioners.from(tokens[tokens.length - 1]); } @@ -162,13 +164,13 @@ private void checkAndReloadReloadCaches() if (localHostsCache == null || !new HashSet<>(localHostsCache.values()).equals(localInstanceIds) || allInstancesCache == null - || !allInstancesCache.equals(metadata.getAllHosts())) + || !allInstancesCache.equals(metadata.getNodes().values())) { synchronized (this) { // If cluster configuration changes. localHostsCache = localInstanceIds(); - allInstancesCache = metadata.getAllHosts(); + allInstancesCache = new HashSet<>(metadata.getNodes().values()); assignedRangesOfAllInstancesByDcCache = assignedRangesOfAllInstancesByDc(metadata); } } @@ -189,9 +191,10 @@ public static Map>> assignedRangesOfAllInst { Partitioner partitioner = extractPartitioner(metadata); Map> perDcHosts = new HashMap<>(4); - for (Host host : metadata.getAllHosts()) + for (Node host : metadata.getNodes().values()) { - Token minToken = host.getTokens().stream().min(Comparable::compareTo).orElseThrow(() -> new RuntimeException("No token found for host: " + host)); + Token minToken = metadata.getTokenMap().get().getTokens(host).stream().min(Comparable::compareTo) + .orElseThrow(() -> new RuntimeException("No token found for host: " + host)); perDcHosts.computeIfAbsent(host.getDatacenter(), (dc) -> new ArrayList<>()) .add(new CassandraInstance(tokenToString(minToken), getIpFromHost(dnsResolver, host))); } @@ -201,17 +204,19 @@ public static Map>> assignedRangesOfAllInst .collect(Collectors.toMap(Map.Entry::getKey, e -> calculateTokenRanges(partitioner, e.getValue()))); } - protected static String tokenToString(Token token) + public static String tokenToString(Token token) { - if (token.getType() == DataType.bigint()) + if (token instanceof Murmur3Token) { - return Long.toString((long) token.getValue()); + Murmur3Token t = (Murmur3Token) token; + return Long.toString(t.getValue()); } - else if (token.getType() == DataType.varint()) + else if (token instanceof RandomToken) { - return token.getValue().toString(); + RandomToken t = (RandomToken) token; + return t.getValue().toString(); } - throw new UnsupportedOperationException("Unsupported token type: " + token.getType()); + throw new UnsupportedOperationException("Unsupported token type: " + token.getClass().getName()); } protected static Map> calculateTokenRanges(Partitioner partitioner, List sortedPerDcHosts) @@ -222,13 +227,13 @@ protected static Map> calculateTokenRanges(Partitioner .collect(Collectors.groupingBy(e -> e.getKey().node, Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); } - private Map localInstanceIds() + private Map localInstanceIds() { List localInstances = instancesMetadata.instances(); - Set hosts = localInstances.get(0).delegate().metadata().getAllHosts(); + Collection hosts = localInstances.get(0).delegate().metadata().getNodes().values(); Map localIps = localInstances.stream() .collect(Collectors.toMap(instanceMetadata -> getIp(instanceMetadata.host()), InstanceMetadata::id)); - Map ipToHost = hosts.stream() + Map ipToHost = hosts.stream() .collect(Collectors.toMap(this::getIpFromHost, Function.identity())); return localIps.entrySet() @@ -246,21 +251,21 @@ private Metadata validatedMetadata(List localInstances) return fetcher.callOnFirstAvailableInstance(instanceMetadata -> instanceMetadata.delegate().metadata()); } - private static Map>> perKeySpaceTokenRangesOfAllInstances(Metadata metadata) + private static Map>> perKeySpaceTokenRangesOfAllInstances(Metadata metadata) { - Map>> perKeyspaceTokenRanges = new HashMap<>(); - for (KeyspaceMetadata ks : metadata.getKeyspaces()) + Map>> perKeyspaceTokenRanges = new HashMap<>(); + for (KeyspaceMetadata ks : metadata.getKeyspaces().values()) { - Map> perHostTokenRanges = new HashMap<>(); - for (Host host : metadata.getAllHosts()) + Map> perHostTokenRanges = new HashMap<>(); + for (Node host : metadata.getNodes().values()) { - Set tokenRanges = metadata.getTokenRanges(ks.getName(), host) + Set tokenRanges = metadata.getTokenMap().get().getTokenRanges(ks.getName(), host) .stream() .flatMap(range -> TokenRange.from(range).stream()) .collect(Collectors.toSet()); perHostTokenRanges.put(host, tokenRanges); } - perKeyspaceTokenRanges.put(ks.getName(), perHostTokenRanges); + perKeyspaceTokenRanges.put(ks.getName().asInternal(), perHostTokenRanges); } return perKeyspaceTokenRanges; } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java index 6177ec64b..949ac760a 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java @@ -26,8 +26,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.exceptions.NoHostAvailableException; -import com.datastax.driver.core.exceptions.QueryConsistencyException; +import com.datastax.oss.driver.api.core.NoNodeAvailableException; +import com.datastax.oss.driver.api.core.servererrors.QueryConsistencyException; import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.eventbus.EventBus; @@ -217,7 +217,7 @@ protected String executeLeaseAction(String actionName, LOGGER.debug("Attempting to {} lease for sidecarHostId={}", actionName, sidecarHostId); return actionFn.apply(sidecarHostId).currentOwner; } - catch (QueryConsistencyException | NoHostAvailableException | IllegalArgumentException e) + catch (QueryConsistencyException | NoNodeAvailableException | IllegalArgumentException e) { LOGGER.debug("Unable to {} lease for sidecarHostId={}", actionName, sidecarHostId, e); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ContentionFreeRangeManager.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ContentionFreeRangeManager.java index 33035d280..cac5c65c7 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ContentionFreeRangeManager.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ContentionFreeRangeManager.java @@ -29,7 +29,8 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; /** - * Stub implementation of the RangeManager that provides contention-free failover for token ranges without coordinating with other Sidecar instances, at the cost of consistency. + * Stub implementation of the RangeManager that provides contention-free failover for token ranges without + * coordinating with other Sidecar instances, at the cost of consistency. */ @Singleton public class ContentionFreeRangeManager extends RangeManager diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java index 9ca0df430..22dfc37a8 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java @@ -37,10 +37,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.TokenMap; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.client.SidecarInstance; @@ -56,7 +58,6 @@ import static org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl.DEFAULT_FORBIDDEN_KEYSPACES; - /** * Return Sidecar(s) adjacent to current Sidecar in the token ring within the same datacenter. */ @@ -99,10 +100,10 @@ public Set get() return Set.of(); } - List keyspaces = metadata.getKeyspaces() + List keyspaces = metadata.getKeyspaces().values() .stream() - // TODO: this should be from configured - .filter(ks -> !DEFAULT_FORBIDDEN_KEYSPACES.contains(ks.getName())) + // TODO: Refactor forbidden keyspaces to be configurable. + .filter(ks -> !DEFAULT_FORBIDDEN_KEYSPACES.contains(ks.getName().asInternal())) .collect(Collectors.toList()); if (keyspaces.isEmpty()) { @@ -110,10 +111,11 @@ public Set get() return Set.of(); } - Set localHosts = cassandraClientTokenRingProvider.localInstances(); + Set localHosts = cassandraClientTokenRingProvider.localInstances(); + TokenMap tokenMap = metadata.getTokenMap().get(); String localDc = Objects.requireNonNull(localHosts, "CachedLocalTokenRanges not initialized") .stream() - .map(Host::getDatacenter) + .map(Node::getDatacenter) .filter(Objects::nonNull) .findAny() .orElseThrow(() -> new RuntimeException("No local instances found.")); @@ -128,14 +130,14 @@ public Set get() int rf = Integer.parseInt(maxRfKeyspace.get().getReplication().get(localDc)); int quorum = rf / 2; - List> sortedLocalDcHosts = Objects.requireNonNull(cassandraClientTokenRingProvider.allInstances(), + List> sortedLocalDcHosts = Objects.requireNonNull(cassandraClientTokenRingProvider.allInstances(), "CachedLocalTokenRanges not initialized").stream() - .filter(host -> host.getDatacenter().equals(localDc)) - .map(host -> Pair.of(host, minToken(host))) + .filter(host -> localDc.equals(host.getDatacenter())) + .map(host -> Pair.of(host, minToken(tokenMap, host))) .sorted(Comparator.comparing(Pair::getRight)) .collect(Collectors.toList()); - BigInteger localMinToken = minToken(localHosts); + BigInteger localMinToken = minToken(tokenMap, localHosts); return adjacentHosts(driverUtils, localHosts::contains, localMinToken, sortedLocalDcHosts, quorum) .stream() .map(host -> driverUtils.getSocketAddress(host).getAddress().getHostAddress()) @@ -160,34 +162,36 @@ protected int sidecarServicePort(String sidecarHostname) return serviceConfiguration.port(); } - public static BigInteger minToken(Collection hosts) + public static BigInteger minToken(TokenMap tokenMap, Collection hosts) { return hosts.stream() - .map(InnerDcTokenAdjacentPeerProvider::minToken) + .map(h -> minToken(tokenMap, h)) .min(BigInteger::compareTo) .orElseThrow(() -> new RuntimeException("No min token found on hosts")); } - public static BigInteger minToken(Host host) + public static BigInteger minToken(TokenMap tokenMap, Node host) { - return host.getTokens() + return tokenMap.getTokens(host) .stream() .map(InnerDcTokenAdjacentPeerProvider::tokenToBigInteger) .min(BigInteger::compareTo) .orElseThrow(() -> new RuntimeException("No min token found on host: " + host.getHostId())); } - public static BigInteger tokenToBigInteger(com.datastax.driver.core.Token token) + public static BigInteger tokenToBigInteger(com.datastax.oss.driver.api.core.metadata.token.Token token) { - if (token.getType() == DataType.varint()) // BigInteger - RandomPartitioner + if (token instanceof RandomToken) // BigInteger - RandomPartitioner { - return (BigInteger) token.getValue(); + RandomToken t = (RandomToken) token; + return t.getValue(); } - else if (token.getType() == DataType.bigint()) // Long - Murmur3Partitioner + else if (token instanceof Murmur3Token) // Long - Murmur3Partitioner { - return BigInteger.valueOf((Long) token.getValue()); + Murmur3Token t = (Murmur3Token) token; + return BigInteger.valueOf(t.getValue()); } - throw new IllegalArgumentException("Unsupported token type: " + token.getType() + + throw new IllegalArgumentException("Unsupported token type: " + token.getClass().getName() + ". Only tokens of Murmur3Partitioner and RandomPartitioner are supported."); } @@ -209,13 +213,13 @@ protected static BigInteger minToken(Stream tokenRanges) * @param quorum minimum availability required to meet maximum replication factor in DC * @return set of hosts that are adjacent to current Sidecar */ - protected static Set adjacentHosts(DriverUtils driverUtils, - Predicate isLocal, + protected static Set adjacentHosts(DriverUtils driverUtils, + Predicate isLocal, BigInteger localMinToken, - List> sortedLocalDcHosts, + List> sortedLocalDcHosts, int quorum) { - Set adjacentHosts = new HashSet<>(quorum); + Set adjacentHosts = new HashSet<>(quorum); // all hosts in token order int idx = Collections.binarySearch(sortedLocalDcHosts, null, (o1, o2) -> { @@ -233,7 +237,7 @@ protected static Set adjacentHosts(DriverUtils driverUtils, { // if max RF is greater than the number of other available hosts then it will wrap around int nextIdx = (idx + i) % (sortedLocalDcHosts.size()); - Host nextHost = sortedLocalDcHosts.get(nextIdx).getKey(); + Node nextHost = sortedLocalDcHosts.get(nextIdx).getKey(); if (isLocal.test(nextHost)) { LOGGER.warn("Insufficient other hosts to satisfy quorum quorum={} numHosts={}", quorum, i); @@ -249,7 +253,7 @@ protected static Set adjacentHosts(DriverUtils driverUtils, } Preconditions.checkArgument(adjacentHosts.size() == quorum, String.format("Failed to find %d adjacent node(s) in the ring", quorum)); - for (Host host : adjacentHosts) + for (Node host : adjacentHosts) { if (isLocal.test(host)) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java index 8d9f2fae0..f36d0aa13 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java @@ -24,8 +24,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.config.SidecarConfiguration; import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException; @@ -77,7 +77,7 @@ String highestReplicationFactorKeyspace() return null; } - Session activeSession; + CqlSession activeSession; try { activeSession = cqlSessionProvider.get(); @@ -91,15 +91,15 @@ String highestReplicationFactorKeyspace() Set forbiddenKeyspaces = configuration.cassandraInputValidationConfiguration().forbiddenKeyspaces(); String sidecarKeyspaceName = configuration.serviceConfiguration().schemaKeyspaceConfiguration().keyspace(); - return activeSession.getCluster().getMetadata().getKeyspaces().stream() - .filter(keyspace -> !forbiddenKeyspaces.contains(keyspace.getName())) + return activeSession.getMetadata().getKeyspaces().values().stream() + .filter(keyspace -> !forbiddenKeyspaces.contains(keyspace.getName().asInternal())) // Sort by the keyspace with the highest replication factor // and then sort by the keyspace name to guarantee in the // sorting order across all Sidecar instances .sorted(Comparator.comparingInt(this::aggregateReplicationFactor) .reversed() - .thenComparing(KeyspaceMetadata::getName)) - .map(KeyspaceMetadata::getName) + .thenComparing(i -> i.getName().asInternal())) + .map(i -> i.getName().asInternal()) .findFirst() .orElse(sidecarKeyspaceName); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/RangeManager.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/RangeManager.java index 47e0005a7..f438e7d21 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/RangeManager.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/RangeManager.java @@ -48,8 +48,9 @@ import static org.apache.cassandra.sidecar.tasks.ClusterTopologyMonitor.ClusterTopologyEventType.ON_DC_TOPOLOGY_CHANGE; /** - * This class manages the token ranges owned by this Sidecar instance and listens on the DownDetector for other Sidecar instances going up/down. - * The underlying implementation can implement a consensus algorithm to provide strong guarantees around gaining/releasing token range ownership. + * This class manages the token ranges owned by this Sidecar instance and listens on the DownDetector for other + * Sidecar instances going up/down. The underlying implementation can implement a consensus algorithm to provide + * strong guarantees around gaining/releasing token range ownership. */ public abstract class RangeManager implements Handler> { @@ -167,7 +168,8 @@ public Map> ownedTokenRanges() /** * @param primaryOwner SidecarInstance that is the primary owner for the token ranges. * @param ranges token ranges this SidecarInstance wishes to gain ownership. - * @return a future that completes when propose request completes, returning the ranges that were successfully gained as part of the request. + * @return a future that completes when propose request completes, returning the ranges that were successfully + * gained as part of the request. */ /** * Proposes to gain ownership of the specified token ranges. @@ -177,7 +179,8 @@ public Map> ownedTokenRanges() /** * @param primaryOwner SidecarInstance that is the primary owner for the token ranges. * @param ranges token ranges this SidecarInstance wishes to release. - * @return a future that completes when release request completes, returning the ranges that were released as part of the request. + * @return a future that completes when release request completes, returning the ranges + * that were released as part of the request. */ /** * Proposes to release ownership of the specified token ranges. @@ -253,7 +256,8 @@ protected synchronized void onSidecarUp(SidecarInstance instance) } else { - LOGGER.warn("Failed to release ownership of instance primary range host={} port={} ranges='{}'", instance.hostname(), instance.port(), primaryRanges); + LOGGER.warn("Failed to release ownership of instance primary range host={} port={} ranges='{}'", + instance.hostname(), instance.port(), primaryRanges); } }) .onFailure(throwable -> LOGGER.warn("Error attempting to release range ownership", throwable)); @@ -286,7 +290,8 @@ protected synchronized void onSidecarDown(SidecarInstance instance) } else { - LOGGER.warn("Failed to gain ownership of instance primary range host={} port={} ranges='{}'", instance.hostname(), instance.port(), primaryRanges); + LOGGER.warn("Failed to gain ownership of instance primary range host={} port={} ranges='{}'", + instance.hostname(), instance.port(), primaryRanges); } }) .onFailure(throwable -> LOGGER.warn("Error attempting to gain range ownership", throwable)); @@ -336,7 +341,8 @@ public synchronized void onRangesLost(Map> lostRanges) // utils - protected static Map> unionRangeMap(@NotNull Map> currRanges, Map> newRanges) + protected static Map> unionRangeMap(@NotNull Map> currRanges, + Map> newRanges) { if (newRanges == null || newRanges.isEmpty()) { @@ -378,7 +384,8 @@ protected static Set differenceRangeMap(@NotNull Set cur return Sets.difference(current, lost).immutableCopy(); } - protected static Map> differenceRangeMap(@NotNull Map> curr, Map> lost) + protected static Map> differenceRangeMap(@NotNull Map> curr, + Map> lost) { return curr.entrySet().stream() .map(e -> Pair.of(e.getKey(), differenceRangeMap(e.getValue(), lost.get(e.getKey())))) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java index 59f1ea864..bd6747aea 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java @@ -30,7 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Host; +import com.datastax.oss.driver.api.core.metadata.Node; import org.apache.cassandra.sidecar.client.SidecarInstance; import org.apache.cassandra.sidecar.cluster.InstancesMetadata; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; @@ -40,6 +40,7 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.jetbrains.annotations.Nullable; /** @@ -110,7 +111,7 @@ public Map> getPrimaryTokenRanges(@Nullable String dc) @Nullable public String localDc() { - NodeSettings nodeSettings = fetcher.callOnFirstAvailableInstance(instance-> instance.delegate().nodeSettings()); + NodeSettings nodeSettings = fetcher.callOnFirstAvailableInstance(instance -> instance.delegate().nodeSettings()); return nodeSettings.datacenter(); } @@ -128,18 +129,18 @@ public Partitioner partitioner() // Helpers - protected String getIpFromHost(Host host) + protected String getIpFromHost(Node host) { return getIpFromHost(dnsResolver, host); } - protected static String getIpFromHost(DnsResolver dnsResolver, Host host) + protected static String getIpFromHost(DnsResolver dnsResolver, Node host) { // if the IP address is already resolved for the host (it generally should be), use it. // this also avoids the case where the driver connects to the local node with an IPv6 or IPv4 address and is // able to resolve its host name, we want to avoid attempting to resolve by host name here in the event // that the configured DNS resolver resolves the wrong IP class for the configured node. - @SuppressWarnings("deprecation") InetAddress address = host.getAddress(); + @SuppressWarnings("deprecation") InetAddress address = MetadataUtils.resolveEndpoint(host).getAddress(); String hostAddress = address.getHostAddress(); if (hostAddress != null) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToAspectConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToAspectConverter.java index bd23f88f8..2e676cc94 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToAspectConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToAspectConverter.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; import com.linkedin.data.template.RecordTemplate; import datahub.event.MetadataChangeProposalWrapper; import org.jetbrains.annotations.NotNull; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInfoConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInfoConverter.java index d16c4e074..d38cd69c8 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInfoConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInfoConverter.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; import com.linkedin.dataplatform.DataPlatformInfo; import com.linkedin.dataplatform.PlatformType; import datahub.event.MetadataChangeProposalWrapper; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInstancePropertiesConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInstancePropertiesConverter.java index faf93b07c..2281c304b 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInstancePropertiesConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/ClusterToDataPlatformInstancePropertiesConverter.java @@ -20,7 +20,7 @@ import com.google.common.collect.ImmutableMap; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; import com.linkedin.data.template.SetMode; import com.linkedin.data.template.StringMap; import com.linkedin.dataplatforminstance.DataPlatformInstanceProperties; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/IdentifiersProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/IdentifiersProvider.java index 189d51893..c1c6cf02c 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/IdentifiersProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/IdentifiersProvider.java @@ -26,8 +26,8 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -192,7 +192,7 @@ public String urnDataset(@NotNull TableMetadata table) DATASET, urnDataPlatform(), identifier(), - table.getKeyspace().getName(), + table.getKeyspace(), table.getName(), PROD); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToAspectConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToAspectConverter.java index 6ffbafc6d..a30b32366 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToAspectConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToAspectConverter.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.linkedin.data.template.RecordTemplate; import datahub.event.MetadataChangeProposalWrapper; import org.jetbrains.annotations.NotNull; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToBrowsePathsV2Converter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToBrowsePathsV2Converter.java index 43ce4cdd4..502527339 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToBrowsePathsV2Converter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToBrowsePathsV2Converter.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.linkedin.common.BrowsePathEntry; import com.linkedin.common.BrowsePathEntryArray; import com.linkedin.common.BrowsePathsV2; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToContainerPropertiesConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToContainerPropertiesConverter.java index d43fcd7fd..577c45cc9 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToContainerPropertiesConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToContainerPropertiesConverter.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.linkedin.container.ContainerProperties; import com.linkedin.data.template.SetMode; import datahub.event.MetadataChangeProposalWrapper; @@ -41,7 +41,7 @@ public MetadataChangeProposalWrapper convert(@NotNull Keysp String urn = identifiers.urnContainer(keyspace); ContainerProperties aspect = new ContainerProperties() - .setName(keyspace.getName()) + .setName(keyspace.getName().asInternal()) .setDescription(null, SetMode.REMOVE_IF_NULL); // Keyspace-level comments are not supported by Cassandra return wrap(urn, aspect); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToDataPlatformInstanceConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToDataPlatformInstanceConverter.java index f861d5509..87e4b5416 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToDataPlatformInstanceConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToDataPlatformInstanceConverter.java @@ -20,7 +20,7 @@ import java.net.URISyntaxException; -import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.linkedin.common.DataPlatformInstance; import com.linkedin.common.urn.Urn; import datahub.event.MetadataChangeProposalWrapper; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToSubTypesConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToSubTypesConverter.java index fbc2d12e5..47c210505 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToSubTypesConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/KeyspaceToSubTypesConverter.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.linkedin.common.SubTypes; import com.linkedin.data.template.StringArray; import datahub.event.MetadataChangeProposalWrapper; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReporter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReporter.java index 832980b84..1713129c0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReporter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReporter.java @@ -27,10 +27,10 @@ import org.slf4j.LoggerFactory; import com.codahale.metrics.Timer; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.google.inject.Inject; import com.google.inject.Singleton; import com.linkedin.data.template.RecordTemplate; @@ -145,11 +145,11 @@ protected SchemaReporter(@NotNull IdentifiersProvider identifiersProvider, /** * Public method for converting and reporting the Cassandra schema when triggered by a scheduled periodic task * - * @param cluster the {@link Cluster} to extract Cassandra schema from + * @param session the {@link CqlSession} to extract Cassandra schema from */ - public void processScheduled(@NotNull Cluster cluster) + public void processScheduled(@NotNull CqlSession session) { - process(cluster.getMetadata(), reportingMetrics.startedSchedule.metric); + process(session.getMetadata(), reportingMetrics.startedSchedule.metric); } /** @@ -208,7 +208,7 @@ protected Stream> stream return Streams.concat( clusterConverters.stream() .map(ThrowableUtils.function(converter -> converter.convert(metadata))), - metadata.getKeyspaces() + metadata.getKeyspaces().values() .stream() .filter(this::neitherVirtualNorSystem) .flatMap(this::stream)); @@ -227,9 +227,9 @@ protected Stream> stream return Streams.concat( keyspaceConverters.stream() .map(ThrowableUtils.function(converter -> converter.convert(keyspace))), - keyspace.getTables() + keyspace.getTables().values() .stream() - .flatMap(this::stream)); + .flatMap(f -> stream(keyspace, f))); } /** @@ -240,10 +240,11 @@ protected Stream> stream * @return non-empty {@link Stream} of DataHub aspects */ @NotNull - protected Stream> stream(@NotNull TableMetadata table) + protected Stream> stream(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) { return tableConverters.stream() - .map(ThrowableUtils.function(converter -> converter.convert(table))); + .map(ThrowableUtils.function(converter -> converter.convert(keyspace, table))); } /** @@ -261,7 +262,7 @@ protected boolean neitherVirtualNorSystem(@NotNull KeyspaceMetadata keyspace) return false; } - String name = keyspace.getName(); + String name = keyspace.getName().asInternal(); return !name.equals("system") && !name.startsWith("system_") && !name.equals("sidecar_internal"); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReportingTask.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReportingTask.java index d91dd8fb5..71ed75d3c 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReportingTask.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/SchemaReportingTask.java @@ -108,7 +108,7 @@ protected void execute(@NotNull Promise promise, { try { - reporter.processScheduled(session.get().getCluster()); + reporter.processScheduled(session.get()); LOGGER.info("Schema report has been completed successfully on attempt {}", attempt); promise.complete(); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToAspectConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToAspectConverter.java index d932f417a..9191af7da 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToAspectConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToAspectConverter.java @@ -18,7 +18,8 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.data.template.RecordTemplate; import datahub.event.MetadataChangeProposalWrapper; import org.jetbrains.annotations.NotNull; @@ -53,5 +54,6 @@ protected MetadataChangeProposalWrapper wrap(@NotNull String urn, } @NotNull - public abstract MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) throws Exception; + public abstract MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) throws Exception; } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsConverter.java index 14b8c73b3..8fe37922b 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsConverter.java @@ -18,7 +18,8 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.common.BrowsePaths; import com.linkedin.data.template.StringArray; import datahub.event.MetadataChangeProposalWrapper; @@ -38,7 +39,8 @@ public TableToBrowsePathsConverter(@NotNull IdentifiersProvider identifiers) @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) { String urn = identifiers.urnDataset(table); @@ -48,7 +50,7 @@ public MetadataChangeProposalWrapper convert(@NotNull TableMetadata identifiers.environment(), identifiers.application(), identifiers.cluster(), - table.getKeyspace().getName()); + table.getKeyspace().asInternal()); BrowsePaths aspect = new BrowsePaths() .setPaths(new StringArray(path)); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsV2Converter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsV2Converter.java index 70f17c433..6635be1f0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsV2Converter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToBrowsePathsV2Converter.java @@ -20,7 +20,8 @@ import java.net.URISyntaxException; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.common.BrowsePathEntry; import com.linkedin.common.BrowsePathEntryArray; import com.linkedin.common.BrowsePathsV2; @@ -41,11 +42,12 @@ public TableToBrowsePathsV2Converter(@NotNull IdentifiersProvider identifiers) @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) throws URISyntaxException + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) throws URISyntaxException { String urn = identifiers.urnDataset(table); - String container = identifiers.urnContainer(table.getKeyspace()); + String container = identifiers.urnContainer(keyspace); BrowsePathsV2 aspect = new BrowsePathsV2() .setPath(new BrowsePathEntryArray( diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToContainerConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToContainerConverter.java index 660a1c1c9..136f4d3c3 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToContainerConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToContainerConverter.java @@ -20,7 +20,8 @@ import java.net.URISyntaxException; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.common.urn.Urn; import com.linkedin.container.Container; import datahub.event.MetadataChangeProposalWrapper; @@ -38,11 +39,12 @@ public TableToContainerConverter(@NotNull IdentifiersProvider identifiers) @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) throws URISyntaxException + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) throws URISyntaxException { String urn = identifiers.urnDataset(table); - String container = identifiers.urnContainer(table.getKeyspace()); + String container = identifiers.urnContainer(keyspace); Container aspect = new Container() .setContainer(new Urn(container)); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDataPlatformInstanceConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDataPlatformInstanceConverter.java index afabee48e..c4967c8b0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDataPlatformInstanceConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDataPlatformInstanceConverter.java @@ -20,7 +20,8 @@ import java.net.URISyntaxException; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.common.DataPlatformInstance; import com.linkedin.common.urn.Urn; import datahub.event.MetadataChangeProposalWrapper; @@ -38,7 +39,8 @@ public TableToDataPlatformInstanceConverter(@NotNull IdentifiersProvider identif @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) throws URISyntaxException + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) throws URISyntaxException { String urn = identifiers.urnDataset(table); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDatasetPropertiesConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDatasetPropertiesConverter.java index b4b356983..85c2ca5d6 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDatasetPropertiesConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToDatasetPropertiesConverter.java @@ -20,7 +20,9 @@ import java.time.Instant; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.common.TimeStamp; import com.linkedin.data.template.SetMode; import com.linkedin.dataset.DatasetProperties; @@ -32,6 +34,8 @@ */ public class TableToDatasetPropertiesConverter extends TableToAspectConverter { + private static final CqlIdentifier COMMENT = CqlIdentifier.fromCql("comment"); + public TableToDatasetPropertiesConverter(@NotNull IdentifiersProvider identifiers) { super(identifiers); @@ -39,15 +43,16 @@ public TableToDatasetPropertiesConverter(@NotNull IdentifiersProvider identifier @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) { String urn = identifiers.urnDataset(table); DatasetProperties aspect = new DatasetProperties() - .setName(table.getName()) - .setQualifiedName(table.getKeyspace().getName() + DELIMITER + table.getName()); + .setName(table.getName().asInternal()) + .setQualifiedName(keyspace.getName().asInternal() + DELIMITER + table.getName()); - String comment = table.getOptions().getComment(); + String comment = (String) table.getOptions().get(COMMENT); if (comment != null) { aspect = aspect diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java index ed7ef0e1f..02e12565f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java @@ -18,6 +18,8 @@ package org.apache.cassandra.sidecar.datahub; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.stream.Stream; import com.google.common.collect.ImmutableMap; @@ -25,11 +27,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.AbstractTableMetadata; -import com.datastax.driver.core.ColumnMetadata; -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.TableMetadata; -import com.datastax.driver.core.UserType; +import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; +import com.datastax.oss.driver.api.core.type.DataType; +import com.datastax.oss.driver.api.core.type.ListType; +import com.datastax.oss.driver.api.core.type.SetType; +import com.datastax.oss.driver.api.core.type.TupleType; +import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.linkedin.common.urn.DataPlatformUrn; import com.linkedin.data.template.SetMode; import com.linkedin.schema.ArrayType; @@ -68,31 +73,27 @@ public class TableToSchemaMetadataConverter extends TableToAspectConverter TYPES = new ImmutableMap.Builder() - .put(DataType.Name.ASCII, STRING) - .put(DataType.Name.BIGINT, NUMBER) - .put(DataType.Name.BLOB, BYTES) - .put(DataType.Name.BOOLEAN, BOOLEAN) - .put(DataType.Name.COUNTER, NUMBER) - .put(DataType.Name.DATE, DATE) - .put(DataType.Name.DECIMAL, NUMBER) - .put(DataType.Name.DOUBLE, NUMBER) - .put(DataType.Name.FLOAT, NUMBER) - .put(DataType.Name.INET, STRING) - .put(DataType.Name.INT, NUMBER) - .put(DataType.Name.LIST, ARRAY) - .put(DataType.Name.MAP, MAP) - .put(DataType.Name.SET, ARRAY) - .put(DataType.Name.SMALLINT, NUMBER) - .put(DataType.Name.TEXT, STRING) - .put(DataType.Name.TIME, TIME) - .put(DataType.Name.TIMESTAMP, DATE) - .put(DataType.Name.TIMEUUID, STRING) - .put(DataType.Name.TINYINT, NUMBER) - .put(DataType.Name.TUPLE, ARRAY) - .put(DataType.Name.UUID, STRING) - .put(DataType.Name.VARCHAR, STRING) - .put(DataType.Name.VARINT, NUMBER) + protected static final Map PRIMITIVE_TYPES = new ImmutableMap.Builder() + .put("ascii", STRING) + .put("bigint", NUMBER) + .put("blob", BYTES) + .put("boolean", BOOLEAN) + .put("counter", NUMBER) + .put("date", DATE) + .put("decimal", NUMBER) + .put("double", NUMBER) + .put("float", NUMBER) + .put("inet", STRING) + .put("int", NUMBER) + .put("smallint", NUMBER) + .put("text", STRING) + .put("time", TIME) + .put("timestamp", DATE) + .put("timeuuid", STRING) + .put("tinyint", NUMBER) + .put("uuid", STRING) + .put("varchar", STRING) + .put("varint", NUMBER) .build(); public TableToSchemaMetadataConverter(@NotNull IdentifiersProvider identifiers) @@ -102,24 +103,25 @@ public TableToSchemaMetadataConverter(@NotNull IdentifiersProvider identifiers) @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) { String urn = identifiers.urnDataset(table); SchemaFieldArray fields = new SchemaFieldArray(); - table.getColumns().stream() - .flatMap(this::convertColumn) + table.getColumns().values().stream() + .flatMap(c -> convertColumn(table, c)) .forEach(fields::add); // Use {@code CREATE TABLE} CQL statement with all associated indexes and views but without // UDTs as the native schema; using {@code asCQLQuery()} does not allow formatting produced CQL - String cql = table.exportAsString(); + String cql = table.describeWithChildren(true); // TODO(lantoniak): Test true or false. SchemaMetadata.PlatformSchema schema = new SchemaMetadata.PlatformSchema(); schema.setOtherSchema(new OtherSchema().setRawSchema(cql)); String hash = DigestUtils.sha1Hex(cql); SchemaMetadata aspect = new SchemaMetadata() - .setSchemaName(table.getName()) + .setSchemaName(table.getName().asInternal()) .setPlatform(new DataPlatformUrn(identifiers.urnDataPlatform())) .setVersion(VERSION) .setFields(fields) @@ -137,14 +139,13 @@ public MetadataChangeProposalWrapper convert(@NotNull TableMetad * @return non-empty {@link Stream} of DataHub schema field definitions */ @NotNull - protected Stream convertColumn(@NotNull ColumnMetadata column) + protected Stream convertColumn(@NotNull TableMetadata table, @NotNull ColumnMetadata column) { DataType type = column.getType(); - AbstractTableMetadata table = column.getParent(); boolean partition = table.getPartitionKey().contains(column); - boolean key = partition || table.getClusteringColumns().contains(column); // Only check clustering key if needed + boolean key = partition || table.getClusteringColumns().containsKey(column); // Only check clustering key if needed - return convertType(column.getName(), type, partition, key); + return convertType(column.getName().asInternal(), type, partition, key); } /** @@ -163,19 +164,23 @@ protected Stream convertType(@NotNull String name, boolean partition, boolean key) { - if (type instanceof UserType) + if (type instanceof UserDefinedType) { - UserType udt = (UserType) type; - - return udt.getFieldNames().stream() - .flatMap(field -> convertType(name + DELIMITER + field, udt.getFieldType(field), partition, key)); + UserDefinedType udt = (UserDefinedType) type; + List> streams = new ArrayList<>(udt.getFieldNames().size()); + for (int i = 0; i < udt.getFieldNames().size(); i++) + { + Stream subFields = convertType(name + DELIMITER + udt.getFieldNames().get(i), + udt.getFieldTypes().get(i), partition, key); + streams.add(subFields); + } + return streams.stream().flatMap(f -> f); } else { - DataType.Name cassandraType = type.getName(); - SchemaFieldDataType datahubType = convertType(cassandraType); + SchemaFieldDataType datahubType = convertType(type); String description = datahubType.getType().isNullType() - ? "Unknown Cassandra data type " + cassandraType + ? "Unknown Cassandra data type " + type.asCql(true, true) : null; // Column-level comments are not supported by Cassandra return Stream.of(new SchemaField() @@ -183,7 +188,7 @@ protected Stream convertType(@NotNull String name, .setNullable(!partition) // Everything is potentially nullable in Cassandra except for the partition key .setDescription(description, SetMode.REMOVE_IF_NULL) .setType(datahubType) - .setNativeDataType(cassandraType.toString().toLowerCase()) + .setNativeDataType(type.asCql(true, true)) .setIsPartitioningKey(partition) .setIsPartOfKey(key)); } @@ -197,9 +202,24 @@ protected Stream convertType(@NotNull String name, * @return DataHub data type, or {@code NullType} if unknown/unsupported */ @NotNull - protected SchemaFieldDataType convertType(@NotNull DataType.Name cassandraType) + protected SchemaFieldDataType convertType(@NotNull DataType cassandraType) { - SchemaFieldDataType.Type datahubType = TYPES.get(cassandraType); + SchemaFieldDataType.Type datahubType = null; + if (cassandraType instanceof ListType + || cassandraType instanceof TupleType + || cassandraType instanceof SetType) + { + datahubType = ARRAY; + } + else if (cassandraType instanceof com.datastax.oss.driver.api.core.type.MapType) + { + datahubType = MAP; + } + else + { + datahubType = PRIMITIVE_TYPES.get(cassandraType.asCql(false, false)); + } + if (datahubType == null) { datahubType = NULL; // Use the null type as an indicator of an unknown data type diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSubTypesConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSubTypesConverter.java index 62d065365..fbb7d3518 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSubTypesConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSubTypesConverter.java @@ -18,7 +18,8 @@ package org.apache.cassandra.sidecar.datahub; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.linkedin.common.SubTypes; import com.linkedin.data.template.StringArray; import datahub.event.MetadataChangeProposalWrapper; @@ -38,7 +39,8 @@ public TableToSubTypesConverter(@NotNull IdentifiersProvider identifiers) @Override @NotNull - public MetadataChangeProposalWrapper convert(@NotNull TableMetadata table) + public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMetadata keyspace, + @NotNull TableMetadata table) { String urn = identifiers.urnDataset(table); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java index 472a4cf8a..0ae8565c2 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java @@ -20,9 +20,11 @@ package org.apache.cassandra.sidecar.db; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -32,8 +34,8 @@ import org.slf4j.LoggerFactory; -import com.datastax.driver.core.ResultSetFuture; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; +import com.datastax.oss.driver.api.core.cql.Row; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.ProvisionException; @@ -45,6 +47,7 @@ import org.apache.cassandra.sidecar.db.schema.SidecarSchema; import org.apache.cassandra.sidecar.utils.ByteBufUtils; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.apache.cassandra.sidecar.utils.TokenSplitUtil; import org.apache.cassandra.spark.data.partitioner.Partitioner; import org.apache.cassandra.spark.utils.TableIdentifier; @@ -99,19 +102,19 @@ protected TokenSplitUtil tokenSplitUtil() @NotNull public String fullSchema() { - return session().getCluster().getMetadata().exportSchemaAsString(); + return MetadataUtils.describe(session().getMetadata()); } @NotNull public UUID getTableId(TableIdentifier id) { - return session().getCluster().getMetadata().getKeyspace(id.keyspace()).getTable(id.table()).getId(); + return session().getMetadata().getKeyspace(id.keyspace()).get().getTable(id.table()).get().getId().get(); } - public List storeStateAsync(String jobId, - TokenRange range, - ByteBuffer buf, - long timestamp) + public List> storeStateAsync(String jobId, + TokenRange range, + ByteBuffer buf, + long timestamp) { // write state into all overlapping splits int[] splits = tokenSplitUtil().findOverlappingSplitIds(partitioner(), range); @@ -126,7 +129,7 @@ public List storeStateAsync(String jobId, range.upperEndpoint(), buf, timestamp - ))) + )).toCompletableFuture()) .collect(Collectors.toList()); } @@ -144,27 +147,42 @@ public Stream loadStateForRange(String jobId, TokenRange range) LOGGER.info("Reading CDC state from splits lower={} upper={} splits='{}'", range.lowerEndpoint(), range.upperEndpoint(), Arrays.stream(splits).mapToObj(Integer::toString).collect(Collectors.joining(","))); - Stream futures = Arrays.stream(splits) - .mapToObj(split -> selectCdcRange(jobId, split)); + Stream> futures = Arrays.stream(splits) + .mapToObj(split -> selectCdcRange(jobId, split)); Stream rows = await(futures); return rows.filter(row -> !row.isNull(0) && !row.isNull(1) && !row.isNull(2)) - .filter(row -> TokenSplitUtil.overlaps(range, row.getVarint(0), row.getVarint(1))) - .map(row -> ByteBufUtils.getArray(row.getBytes(2))); + .filter(row -> TokenSplitUtil.overlaps(range, row.getBigInteger(0), row.getBigInteger(1))) + .map(row -> ByteBufUtils.getArray(row.getByteBuffer(2))); } @NotNull public Partitioner partitioner() { - String[] tokens = session().getCluster().getMetadata().getPartitioner().split("\\."); + String[] tokens = session().getMetadata().getTokenMap().get().getPartitionerName().split("\\."); return Partitioner.valueOf(tokens[tokens.length - 1]); } - public static Stream await(Stream futures) + public static Stream await(Stream> futures) { return futures.flatMap(f -> { try { - return f.get().all().stream(); + // TODO(lantoniak): Fid a better implementation of loading Stream? + List rows = new ArrayList<>(); + do + { + AsyncResultSet r = f.get(); + for (Row row : r.currentPage()) + { + rows.add(row); + } + if (!r.hasMorePages()) + { + break; + } + f = r.fetchNextPage().toCompletableFuture(); + } while (true); + return rows.stream(); } catch (InterruptedException e) { @@ -178,8 +196,8 @@ public static Stream await(Stream futures) }); } - ResultSetFuture selectCdcRange(String jobId, int split) + CompletableFuture selectCdcRange(String jobId, int split) { - return session().executeAsync(tableSchema.select().bind(jobId, (short) split)); + return session().executeAsync(tableSchema.select().bind(jobId, (short) split)).toCompletableFuture(); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java b/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java index 8dcb8f19d..676a41b32 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java @@ -22,10 +22,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.db.schema.ConfigsSchema; import org.apache.cassandra.sidecar.db.schema.SidecarSchema; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJob.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJob.java index f04367fcd..7c0e8382f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJob.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJob.java @@ -20,16 +20,16 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Date; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.LocalDate; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.utils.Bytes; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.datastax.oss.protocol.internal.util.Bytes; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.cassandra.sidecar.common.DataObjectBuilder; import org.apache.cassandra.sidecar.common.data.ConsistencyConfig; @@ -43,6 +43,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static org.apache.cassandra.sidecar.db.RestoreJobDatabaseAccessor.ONE_DAY_MILLISECONDS; + /** * RestoreJob is the in-memory representation of a restore job */ @@ -86,14 +88,14 @@ public static RestoreJob from(@NotNull Row row) throws DataObjectMappingExceptio Builder builder = new Builder(); ConsistencyConfig consistencyConfig = ConsistencyConfig.parseString(row.getString("consistency_level"), row.getString("local_datacenter")); - builder.createdAt(row.getDate("created_at")) - .jobId(row.getUUID("job_id")).jobAgent(row.getString("job_agent")) + builder.createdAt(row.getLocalDate("created_at")) + .jobId(row.getUuid("job_id")).jobAgent(row.getString("job_agent")) .bucketCount((short) 0) // always use 0 for now; TODO - Add bucketCount field to CreateRestoreJobRequestPayload .keyspace(row.getString("keyspace_name")).table(row.getString("table_name")) .jobStatusText(row.getString("status")) - .jobSecrets(decodeJobSecrets(row.getBytes("blob_secrets"))) - .expireAt(row.getTimestamp("expire_at")) - .sstableImportOptions(decodeSSTableImportOptions(row.getBytes("import_options"))) + .jobSecrets(decodeJobSecrets(row.getByteBuffer("blob_secrets"))) + .expireAt(row.isNull("expire_at") ? null : Date.from(row.getInstant("expire_at"))) + .sstableImportOptions(decodeSSTableImportOptions(row.getByteBuffer("import_options"))) .consistencyLevel(consistencyConfig.consistencyLevel) .localDatacenter(consistencyConfig.localDatacenter) .shouldRestoreToLocalDatacenterOnly(row.getBool("local_datacenter_only")) @@ -240,7 +242,7 @@ public String toString() public static LocalDate toLocalDate(UUID jobId) { - return LocalDate.fromMillisSinceEpoch(UUIDs.unixTimestamp(jobId)); + return LocalDate.ofEpochDay(Uuids.unixTimestamp(jobId) / ONE_DAY_MILLISECONDS); } private static T deserializeJsonBytes(ByteBuffer byteBuffer, Class type, String fieldNameHint) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java index e596fcb0a..2990d8ae3 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java @@ -19,6 +19,7 @@ package org.apache.cassandra.sidecar.db; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -27,12 +28,12 @@ import com.google.common.base.Preconditions; -import com.datastax.driver.core.BatchStatement; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.LocalDate; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.cql.BatchStatement; +import com.datastax.oss.driver.api.core.cql.BatchType; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Inject; @@ -55,7 +56,7 @@ public class RestoreJobDatabaseAccessor extends DatabaseAccessor { private static final ObjectMapper MAPPER = new ObjectMapper(); - private static final long ONE_DAY_MILLISECONDS = TimeUnit.DAYS.toMillis(1); + public static final long ONE_DAY_MILLISECONDS = TimeUnit.DAYS.toMillis(1); public final SidecarSchema sidecarSchema; @Inject @@ -72,7 +73,7 @@ public RestoreJob create(CreateRestoreJobRequestPayload payload, QualifiedTableN sidecarSchema.ensureInitialized(); UUID jobIdFromRequest = payload.jobId(); - UUID jobId = jobIdFromRequest == null ? UUIDs.timeBased() : jobIdFromRequest; + UUID jobId = jobIdFromRequest == null ? Uuids.timeBased() : jobIdFromRequest; RestoreJob job = RestoreJob.builder() .createdAt(RestoreJob.toLocalDate(jobId)) .jobId(jobId) @@ -101,7 +102,7 @@ public RestoreJob create(CreateRestoreJobRequestPayload payload, QualifiedTableN job.consistencyLevelText(), job.localDatacenter, job.shouldRestoreToLocalDatacenterOnly, - job.expireAt); + job.expireAt.toInstant()); execute(statement); return job; @@ -131,7 +132,7 @@ public RestoreJob update(UpdateRestoreJobRequestPayload payload, UUID jobId) Long sliceCount = payload.sliceCount(); // all updates are going to the same partition. We use unlogged explicitly. // Cassandra internally combine those updates into the same mutation. - BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED); + BatchStatement batchStatement = BatchStatement.newInstance(BatchType.UNLOGGED); ByteBuffer wrappedSecrets; if (secrets != null) { @@ -139,8 +140,8 @@ public RestoreJob update(UpdateRestoreJobRequestPayload payload, UUID jobId) { byte[] secretBytes = MAPPER.writeValueAsBytes(secrets); wrappedSecrets = ByteBuffer.wrap(secretBytes); - batchStatement.add(tableSchema.updateBlobSecrets() - .bind(createdAt, jobId, wrappedSecrets)); + batchStatement = batchStatement.add(tableSchema.updateBlobSecrets() + .bind(createdAt, jobId, wrappedSecrets)); } catch (JsonProcessingException e) { @@ -150,22 +151,22 @@ public RestoreJob update(UpdateRestoreJobRequestPayload payload, UUID jobId) } if (status != null) { - batchStatement.add(tableSchema.updateStatus().bind(createdAt, jobId, status.name())); + batchStatement = batchStatement.add(tableSchema.updateStatus().bind(createdAt, jobId, status.name())); updateBuilder.jobStatus(status); } if (jobAgent != null) { - batchStatement.add(tableSchema.updateJobAgent().bind(createdAt, jobId, jobAgent)); + batchStatement = batchStatement.add(tableSchema.updateJobAgent().bind(createdAt, jobId, jobAgent)); updateBuilder.jobAgent(jobAgent); } if (expireAt != null) { - batchStatement.add(tableSchema.updateExpireAt().bind(createdAt, jobId, expireAt)); + batchStatement = batchStatement.add(tableSchema.updateExpireAt().bind(createdAt, jobId, expireAt.toInstant())); updateBuilder.expireAt(expireAt); } if (sliceCount != null) { - batchStatement.add(tableSchema.updateSliceCount().bind(createdAt, jobId, sliceCount)); + batchStatement = batchStatement.add(tableSchema.updateSliceCount().bind(createdAt, jobId, sliceCount)); updateBuilder.sliceCount(sliceCount); } @@ -222,12 +223,13 @@ public List findAllByCreationDate(LocalDate date) List result = new ArrayList<>(); for (Row row : resultSet) { - if (resultSet.getAvailableWithoutFetching() == 100 && !resultSet.isFullyFetched()) - { - // trigger an async fetch sooner when there are more to fetch, - // and it still has around 100 available to consume from the resultSet - resultSet.fetchMoreResults(); - } + // TODO(lantoniak): Feature not supported in new driver. +// if (resultSet.getAvailableWithoutFetching() == 100 && !resultSet.isFullyFetched()) +// { +// // trigger an async fetch sooner when there are more to fetch, +// // and it still has around 100 available to consume from the resultSet +// resultSet.fetchMoreResults(); +// } result.add(RestoreJob.from(row)); } return result; @@ -272,7 +274,7 @@ public List findAllRecent(long referenceTimestampMillis, int days) static LocalDate dateInPast(long referenceTimestampMillis, int days) { long daysInMillis = days * ONE_DAY_MILLISECONDS; - return LocalDate.fromMillisSinceEpoch(referenceTimestampMillis - daysInMillis); + return LocalDate.ofEpochDay((referenceTimestampMillis - daysInMillis) / ONE_DAY_MILLISECONDS); } private static ByteBuffer serializeValue(T value, String type) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRange.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRange.java index 2bb52438f..1e3a52270 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRange.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRange.java @@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.Row; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; import org.apache.cassandra.sidecar.cluster.locator.LocalTokenRangesProvider; import org.apache.cassandra.sidecar.common.DataObjectBuilder; @@ -127,10 +127,10 @@ public class RestoreRange public static RestoreRange from(Row row) { return new Builder() - .jobId(row.getUUID("job_id")) + .jobId(row.getUuid("job_id")) .bucketId(row.getShort("bucket_id")) - .startToken(row.getVarint("start_token")) - .endToken(row.getVarint("end_token")) + .startToken(row.getBigInteger("start_token")) + .endToken(row.getBigInteger("end_token")) .replicaStatusText(row.getMap("status_by_replica", String.class, String.class)) .sliceId(row.getString("slice_id")) .sliceBucket(row.getString("slice_bucket")) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java index ecc2a3bb7..643fa35b3 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java @@ -25,9 +25,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; @@ -87,6 +87,7 @@ public RestoreRange updateStatus(RestoreRange range) } // todo: change to stream api and paginate + // TODO(lantoniak): Maybe implement above? public List findAll(UUID jobId, short bucketId) { sidecarSchema.ensureInitialized(); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java index 5caa4be46..acace7ee8 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java @@ -22,7 +22,7 @@ import java.util.Objects; import java.util.UUID; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.Row; import org.apache.cassandra.sidecar.common.DataObjectBuilder; import org.apache.cassandra.sidecar.common.request.data.CreateSliceRequestPayload; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; @@ -215,7 +215,7 @@ public long creationTimeNanos() public static RestoreSlice from(Row row, RestoreJob restoreJob) { Builder builder = new Builder(); - builder.jobId(row.getUUID("job_id")); + builder.jobId(row.getUuid("job_id")); builder.keyspace(restoreJob.keyspaceName); builder.table(restoreJob.tableName); builder.sliceId(row.getString("slice_id")); @@ -223,8 +223,8 @@ public static RestoreSlice from(Row row, RestoreJob restoreJob) builder.storageBucket(row.getString("bucket")); builder.storageKey(row.getString("key")); builder.checksum(row.getString("checksum")); - builder.startToken(row.getVarint("start_token")); - builder.endToken(row.getVarint("end_token")); + builder.startToken(row.getBigInteger("start_token")); + builder.endToken(row.getBigInteger("end_token")); builder.compressedSize(row.getLong("compressed_size")); builder.uncompressedSize(row.getLong("uncompressed_size")); return builder.build(); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java index c621b1435..e258f06c0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java @@ -21,9 +21,9 @@ import java.util.ArrayList; import java.util.List; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/ServiceConfig.java b/server/src/main/java/org/apache/cassandra/sidecar/db/ServiceConfig.java index 8d2c0d865..6a71c4f55 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/ServiceConfig.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/ServiceConfig.java @@ -18,7 +18,8 @@ package org.apache.cassandra.sidecar.db; import java.util.Map; -import com.datastax.driver.core.Row; + +import com.datastax.oss.driver.api.core.cql.Row; import org.jetbrains.annotations.Nullable; /** diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java index 94ce415ea..476ad876d 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java index b7618caf8..e933c9d45 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java @@ -23,9 +23,9 @@ import java.util.Map; import java.util.Set; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; import com.google.inject.Inject; import com.google.inject.Singleton; import io.vertx.ext.auth.authorization.Authorization; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java index b79da180d..c11e3d246 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java @@ -25,11 +25,11 @@ import java.util.Set; import java.util.stream.Collectors; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.SimpleStatement; -import com.datastax.driver.core.Statement; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; import com.google.inject.Inject; import com.google.inject.Singleton; import io.vertx.ext.auth.authorization.Authorization; @@ -139,7 +139,7 @@ public Map> findAllRolesAndPermissions() */ public boolean isSuperUser(String role) { - Statement statement = new SimpleStatement(String.format(tableSchema.unpreparedListRoles(), role)); + Statement statement = SimpleStatement.newInstance(String.format(tableSchema.unpreparedListRoles(), role)); ResultSet result = execute(statement); for (Row row : result) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SystemViewsDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SystemViewsDatabaseAccessor.java index db79ae241..eecd800b1 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SystemViewsDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SystemViewsDatabaseAccessor.java @@ -25,8 +25,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ResultSet; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java index be80e386c..40c752a2a 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java @@ -21,8 +21,9 @@ import java.nio.charset.StandardCharsets; import java.util.UUID; +import java.util.concurrent.CompletableFuture; -import com.datastax.driver.core.ResultSetFuture; +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; @@ -43,11 +44,12 @@ public TableHistoryDatabaseAccessor(SidecarSchema sidecarSchema, super(sidecarSchema.tableSchema(TableHistorySchema.class), sessionProvider); } - public ResultSetFuture insertTableSchemaHistory(String keyspace, String tableName, String schema) + // TODO(lantoniak): Callers do not wait for future to complete. + public CompletableFuture insertTableSchemaHistory(String keyspace, String tableName, String schema) { UUID schemaUuid = UUID.nameUUIDFromBytes(schema.getBytes(StandardCharsets.UTF_8)); return session().executeAsync(tableSchema .insertTableSchema() - .bind(keyspace, tableName, schemaUuid, schema)); + .bind(keyspace, tableName, schemaUuid, schema)).toCompletableFuture(); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/VirtualTablesDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/VirtualTablesDatabaseAccessor.java index c814aaaea..5980799c3 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/VirtualTablesDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/VirtualTablesDatabaseAccessor.java @@ -18,16 +18,15 @@ package org.apache.cassandra.sidecar.db; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.querybuilder.QueryBuilder; -import com.datastax.driver.core.querybuilder.Select; +import com.datastax.oss.driver.api.core.cql.Row; +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.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.db.schema.TableSchema; -import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; - /** * Database accessor for querying Cassandra virtual tables in the system_views keyspace. */ @@ -52,10 +51,10 @@ public VirtualTablesDatabaseAccessor(TableSchema tableSchema, CQLSessionProvider */ public boolean isCdcOnRepairEnabled() { - Select.Where query = QueryBuilder.select("value") - .from(SYSTEM_VIEWS_KS, SYSTEM_VIEWS_SETTINGS_TBL) - .where(eq("name", CDC_ON_REPAIR_ENABLED_FLAG)); - Row row = session().execute(query).one(); + Select query = QueryBuilder.selectFrom(SYSTEM_VIEWS_KS, SYSTEM_VIEWS_SETTINGS_TBL) + .column("value") + .where(Relation.column("name").isEqualTo(QueryBuilder.literal(CDC_ON_REPAIR_ENABLED_FLAG))); + Row row = session().execute(query.build()).one(); return row != null && !row.isNull(0) && "true".equalsIgnoreCase(row.getString(0)); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/CdcStatesSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/CdcStatesSchema.java index 325b9b5e5..dcb71d01e 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/CdcStatesSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/CdcStatesSchema.java @@ -19,12 +19,13 @@ package org.apache.cassandra.sidecar.db.schema; +import java.util.Optional; import java.util.concurrent.TimeUnit; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; @@ -63,7 +64,7 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { this.insertState = prepare(insertState, session, CqlLiterals.insertState(keyspaceConfig)); this.selectState = prepare(selectState, session, CqlLiterals.select(keyspaceConfig)); @@ -78,10 +79,9 @@ protected String tableName() @Override protected boolean exists(@NotNull Metadata metadata) { - KeyspaceMetadata ksMetadata = metadata.getKeyspace(keyspaceConfig.keyspace()); - if (ksMetadata == null) - return false; - return ksMetadata.getTable(CDC_STATE_TABLE_NAME) != null; + Optional ksMetadata = metadata.getKeyspace(keyspaceConfig.keyspace()); + return ksMetadata.map(keyspaceMetadata -> keyspaceMetadata.getTable(CDC_STATE_TABLE_NAME).isPresent()) + .orElse(false); } @Override diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/ConfigsSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/ConfigsSchema.java index ebf922d66..2d67145c0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/ConfigsSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/ConfigsSchema.java @@ -17,10 +17,12 @@ */ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import java.util.Optional; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.apache.cassandra.sidecar.config.ServiceConfiguration; import org.apache.cassandra.sidecar.coordination.ExecuteOnClusterLeaseholderOnly; @@ -53,7 +55,7 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { selectConfig = prepare(selectConfig, session, CqlLiterals.selectConfig(keyspaceConfig)); insertConfig = prepare(insertConfig, session, CqlLiterals.insertConfig(keyspaceConfig)); @@ -70,10 +72,8 @@ protected String tableName() @Override protected boolean exists(@NotNull Metadata metadata) { - KeyspaceMetadata ksMetadata = metadata.getKeyspace(keyspaceConfig.keyspace()); - if (ksMetadata == null) - return false; - return ksMetadata.getTable(CONFIGS_TABLE_NAME) != null; + Optional ksMetadata = metadata.getKeyspace(keyspaceConfig.keyspace()); + return ksMetadata.filter(keyspaceMetadata -> keyspaceMetadata.getTable(CONFIGS_TABLE_NAME).isPresent()).isPresent(); } @Override diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreJobsSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreJobsSchema.java index 15ccb5b9d..b2b3a61fb 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreJobsSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreJobsSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.common.server.utils.SecondBoundConfiguration; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.apache.cassandra.sidecar.coordination.ExecuteOnClusterLeaseholderOnly; @@ -60,7 +60,7 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { insertJob = prepare(insertJob, session, CqlLiterals.insertJob(keyspaceConfig)); updateBlobSecrets = prepare(updateBlobSecrets, session, CqlLiterals.updateBlobSecrets(keyspaceConfig)); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreRangesSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreRangesSchema.java index 7ad57b631..527e43c92 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreRangesSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreRangesSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.common.server.utils.SecondBoundConfiguration; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.apache.cassandra.sidecar.coordination.ExecuteOnClusterLeaseholderOnly; @@ -53,7 +53,7 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { createRange = prepare(createRange, session, CqlLiterals.createRange(keyspaceConfig)); findAll = prepare(findAll, session, CqlLiterals.findAll(keyspaceConfig)); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreSlicesSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreSlicesSchema.java index 095ea4130..9284be110 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreSlicesSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/RestoreSlicesSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.common.server.utils.SecondBoundConfiguration; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.apache.cassandra.sidecar.coordination.ExecuteOnClusterLeaseholderOnly; @@ -54,7 +54,7 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { insertSlice = prepare(insertSlice, session, CqlLiterals.insertSlice(keyspaceConfig)); findAllByTokenRange = prepare(findAllByTokenRange, session, CqlLiterals.findAllByTokenRange(keyspaceConfig)); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java index e0abc4536..ef7919eda 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java @@ -22,8 +22,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Metadata; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.apache.cassandra.sidecar.config.SidecarConfiguration; import org.jetbrains.annotations.NotNull; @@ -63,18 +63,18 @@ public T tableSchema(Class type) } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { } @Override protected boolean exists(@NotNull Metadata metadata) { - return metadata.getKeyspace(keyspaceName()) != null; + return metadata.getKeyspace(keyspaceName()).isPresent(); } @Override - protected boolean initializeInternal(@NotNull Session session, + protected boolean initializeInternal(@NotNull CqlSession session, @NotNull Predicate shouldCreateSchema) { super.initializeInternal(session, shouldCreateSchema); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarLeaseSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarLeaseSchema.java index 4ce7a9228..f4f65a9a0 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarLeaseSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarLeaseSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.VisibleForTesting; @@ -65,7 +65,7 @@ protected String keyspaceName() */ @Override @VisibleForTesting - public void prepareStatements(@NotNull Session session) + public void prepareStatements(@NotNull CqlSession session) { // TODO: revisit decision to make TTL a bind parameter instead of burning into the prepared statement // which means it cannot be changed dynamically during the lifetime of the Sidecar process. diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarRolePermissionsSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarRolePermissionsSchema.java index d0cbfc10d..a50ec4de9 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarRolePermissionsSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarRolePermissionsSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; import org.apache.cassandra.sidecar.config.SidecarConfiguration; import org.jetbrains.annotations.NotNull; @@ -54,7 +54,7 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { allRolesAndPermissions = prepare(allRolesAndPermissions, session, CqlLiterals.allRolesAndPermissions(keyspaceConfig)); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarSchemaInitializer.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarSchemaInitializer.java index b00929431..38ee009d5 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarSchemaInitializer.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarSchemaInitializer.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; @@ -106,7 +106,7 @@ public void execute(Promise promise) { try { - Session session = cqlSessionProvider.get(); + CqlSession session = cqlSessionProvider.get(); boolean isInitialized = sidecarInternalKeyspace.initialize(session, this::shouldCreateSchema); if (isInitialized) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemAuthSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemAuthSchema.java index d6a8d9cad..7faf50919 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemAuthSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemAuthSchema.java @@ -18,9 +18,11 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import java.util.Optional; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import org.apache.cassandra.sidecar.exceptions.SchemaUnavailableException; import org.jetbrains.annotations.NotNull; @@ -44,15 +46,15 @@ protected String keyspaceName() } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { allRoles = prepare(allRoles, session, "SELECT role, is_superuser, member_of FROM system_auth.roles"); unpreparedListRoles = "LIST ROLES OF \"%s\""; allRolesAndPermissions = prepare(allRolesAndPermissions, session, "SELECT * FROM system_auth.role_permissions"); - KeyspaceMetadata keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(keyspaceName()); + Optional keyspaceMetadata = session.getMetadata().getKeyspace(keyspaceName()); // identity_to_role table exists in Cassandra versions starting 5.x - if (keyspaceMetadata == null || keyspaceMetadata.getTable(IDENTITY_TO_ROLE_TABLE) == null) + if (keyspaceMetadata.isEmpty() || keyspaceMetadata.get().getTable(IDENTITY_TO_ROLE_TABLE).isEmpty()) { logger.info("system_auth.identity_to_role does not exist. Skip preparing. table={}.{}", keyspaceName(), IDENTITY_TO_ROLE_TABLE); return; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemViewsSchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemViewsSchema.java index fddf0356d..728d9cc42 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemViewsSchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SystemViewsSchema.java @@ -18,8 +18,8 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.exceptions.SchemaUnavailableException; import org.jetbrains.annotations.NotNull; @@ -60,7 +60,7 @@ public PreparedStatement selectAllSettings() throws SchemaUnavailableException } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { this.selectSettings = session.prepare("SELECT name, value FROM system_views.settings WHERE name IN ?"); this.selectAllSettings = session.prepare("SELECT name, value FROM system_views.settings"); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/TableHistorySchema.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/TableHistorySchema.java index da6499e12..8532a559f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/TableHistorySchema.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/TableHistorySchema.java @@ -19,10 +19,12 @@ package org.apache.cassandra.sidecar.db.schema; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; +import java.util.Optional; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; @@ -53,7 +55,7 @@ public TableHistorySchema(ServiceConfiguration configuration) } @Override - protected void prepareStatements(@NotNull Session session) + protected void prepareStatements(@NotNull CqlSession session) { insertTableSchema = prepare(insertTableSchema, session, CqlLiterals.insertTableSchema(keyspaceConfig)); selectVersionTableSchema = prepare(selectVersionTableSchema, session, CqlLiterals.selectVersionTableSchema(keyspaceConfig)); @@ -74,13 +76,8 @@ protected String tableName() @Override protected boolean exists(@NotNull Metadata metadata) { - KeyspaceMetadata ksMetadata = metadata.getKeyspace(keyspaceConfig.keyspace()); - if (ksMetadata == null) - { - return false; - } - - return ksMetadata.getTable(TABLE_SCHEMA_HISTORY) != null; + Optional ksMetadata = metadata.getKeyspace(keyspaceConfig.keyspace()); + return ksMetadata.filter(keyspaceMetadata -> keyspaceMetadata.getTable(TABLE_SCHEMA_HISTORY).isPresent()).isPresent(); } @Override diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/KeyspaceSchemaHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/KeyspaceSchemaHandler.java index c9446fe69..a271c5c6e 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/KeyspaceSchemaHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/KeyspaceSchemaHandler.java @@ -20,8 +20,8 @@ import java.util.Collections; import java.util.Set; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.google.inject.Inject; import com.google.inject.Singleton; import io.netty.handler.codec.http.HttpResponseStatus; @@ -94,7 +94,7 @@ private void handleWithMetadata(RoutingContext context, Name keyspace, Metadata { if (keyspace == null) { - SchemaResponse schemaResponse = new SchemaResponse(metadata.exportSchemaAsString()); + SchemaResponse schemaResponse = new SchemaResponse(MetadataUtils.describe(metadata)); context.json(schemaResponse); return; } @@ -112,7 +112,7 @@ private void handleWithMetadata(RoutingContext context, Name keyspace, Metadata } SchemaResponse schemaResponse = new SchemaResponse(keyspace.name(), - ksMetadata.exportAsString()); + ksMetadata.describeWithChildren(true)); context.json(schemaResponse); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/LifecycleUpdateHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/LifecycleUpdateHandler.java index 6f69fcec3..8777a9d52 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/LifecycleUpdateHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/LifecycleUpdateHandler.java @@ -89,7 +89,8 @@ protected void handleInternal(RoutingContext context, response.setStatusCode(HttpResponseStatus.ACCEPTED.code()); break; default: - logger.warn("{} request failed with unexpected result. request={}, remoteAddress={}, instance={}, operationStatus={}", + logger.warn("{} request failed with unexpected result. " + + "request={}, remoteAddress={}, instance={}, operationStatus={}", this.getClass().getSimpleName(), request, remoteAddress, host, info.status()); response.setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()); } @@ -99,7 +100,8 @@ protected void handleInternal(RoutingContext context, } @Override - protected void processFailure(Throwable cause, RoutingContext context, String host, SocketAddress remoteAddress, NodeCommandRequestPayload request) + protected void processFailure(Throwable cause, RoutingContext context, String host, SocketAddress remoteAddress, + NodeCommandRequestPayload request) { if (cause instanceof LifecycleTaskConflictException) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDecommissionHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDecommissionHandler.java index d2c522eb9..38a5a8a7f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDecommissionHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDecommissionHandler.java @@ -21,7 +21,7 @@ import java.util.Collections; import java.util.Set; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.net.SocketAddress; @@ -84,7 +84,7 @@ public void handleInternal(RoutingContext context, Boolean isForce) { StorageOperations operations = metadataFetcher.delegate(host).storageOperations(); - NodeDecommissionJob job = new NodeDecommissionJob(UUIDs.timeBased(), operations, isForce); + NodeDecommissionJob job = new NodeDecommissionJob(Uuids.timeBased(), operations, isForce); this.jobManager.trySubmitJob(job, (completedJob, exception) -> OperationalJobUtils.sendStatusBasedResponse(context, completedJob, exception), diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDrainHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDrainHandler.java index b0de67532..a859ace6e 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDrainHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeDrainHandler.java @@ -21,7 +21,7 @@ import java.util.Collections; import java.util.Set; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.net.SocketAddress; @@ -82,7 +82,7 @@ public void handleInternal(RoutingContext context, Void unused) { StorageOperations operations = metadataFetcher.delegate(host).storageOperations(); - NodeDrainJob job = new NodeDrainJob(UUIDs.timeBased(), operations); + NodeDrainJob job = new NodeDrainJob(Uuids.timeBased(), operations); this.jobManager.trySubmitJob(job, (completedJob, exception) -> OperationalJobUtils.sendStatusBasedResponse(context, completedJob, exception), diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeMoveHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeMoveHandler.java index c76798695..56ae10380 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeMoveHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/NodeMoveHandler.java @@ -21,7 +21,7 @@ import java.util.Collections; import java.util.Set; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import com.google.inject.Singleton; import io.netty.handler.codec.http.HttpResponseStatus; @@ -100,7 +100,7 @@ public void handleInternal(RoutingContext context, String newToken) { StorageOperations operations = metadataFetcher.delegate(host).storageOperations(); - NodeMoveJob job = new NodeMoveJob(UUIDs.timeBased(), newToken, operations); + NodeMoveJob job = new NodeMoveJob(Uuids.timeBased(), newToken, operations); this.jobManager.trySubmitJob(job, (completedJob, exception) -> OperationalJobUtils.sendStatusBasedResponse(context, completedJob, exception), diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/RepairHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/RepairHandler.java index 17b684914..943dee16d 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/RepairHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/RepairHandler.java @@ -22,7 +22,7 @@ import java.util.Collections; import java.util.Set; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.http.HttpServerRequest; @@ -125,7 +125,7 @@ protected void handleInternal(RoutingContext context, RepairRequestParam repairRequestParam) { StorageOperations operations = metadataFetcher.delegate(host).storageOperations(); - RepairJob job = new RepairJob(periodicTaskExecutor, config.repairConfiguration(), UUIDs.timeBased(), operations, repairRequestParam); + RepairJob job = new RepairJob(periodicTaskExecutor, config.repairConfiguration(), Uuids.timeBased(), operations, repairRequestParam); jobManager.trySubmitJob(job, (completedJob, exception) -> diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandler.java index 614e7353c..4beb71d41 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandler.java @@ -21,7 +21,7 @@ import java.util.Collections; import java.util.Set; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; import com.google.inject.Inject; import com.google.inject.Singleton; import io.vertx.core.http.HttpServerRequest; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/restore/UpdateRestoreJobHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/restore/UpdateRestoreJobHandler.java index 566603dd0..2dae242eb 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/restore/UpdateRestoreJobHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/restore/UpdateRestoreJobHandler.java @@ -22,7 +22,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import com.google.inject.Singleton; import io.netty.handler.codec.http.HttpResponseStatus; @@ -105,7 +105,7 @@ protected void handleInternal(RoutingContext context, if (job.status == RestoreJobStatus.SUCCEEDED) { metrics.successfulJobs.metric.update(1); - long startMillis = UUIDs.unixTimestamp(job.jobId); + long startMillis = Uuids.unixTimestamp(job.jobId); long durationMillis = System.currentTimeMillis() - startMillis; // toNanos does not overflow. Nanos in `long` can at most represent 106,751 days. metrics.jobCompletionTime.metric.update(durationMillis, TimeUnit.MILLISECONDS); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/sstableuploads/SSTableUploadHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/sstableuploads/SSTableUploadHandler.java index d6c81e456..b105da3c6 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/sstableuploads/SSTableUploadHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/sstableuploads/SSTableUploadHandler.java @@ -22,7 +22,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; -import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.google.inject.Inject; import com.google.inject.Singleton; import io.netty.handler.codec.http.HttpResponseStatus; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/handlers/validations/ValidateTableExistenceHandler.java b/server/src/main/java/org/apache/cassandra/sidecar/handlers/validations/ValidateTableExistenceHandler.java index 24a3ec9db..a0631ded8 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/handlers/validations/ValidateTableExistenceHandler.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/handlers/validations/ValidateTableExistenceHandler.java @@ -18,8 +18,10 @@ package org.apache.cassandra.sidecar.handlers.validations; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.TableMetadata; +import java.util.Optional; + +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.google.inject.Inject; import com.google.inject.Singleton; import io.netty.handler.codec.http.HttpResponseStatus; @@ -96,15 +98,15 @@ protected void handleInternal(RoutingContext context, return; } - TableMetadata tableMetadata = keyspaceMetadata.getTable(table); - if (tableMetadata == null) + Optional tableMetadata = keyspaceMetadata.getTable(table); + if (tableMetadata.isEmpty()) { String errMsg = "Table " + input.tableName() + " was not found for keyspace " + input.keyspace(); context.fail(wrapHttpException(HttpResponseStatus.NOT_FOUND, errMsg)); } else { - RoutingContextUtils.put(context, RoutingContextUtils.SC_TABLE_METADATA, tableMetadata); + RoutingContextUtils.put(context, RoutingContextUtils.SC_TABLE_METADATA, tableMetadata.get()); // keyspace / [table] exists context.next(); } @@ -116,6 +118,6 @@ private Future getKeyspaceMetadata(String host, String keyspac return executorPools.service().executeBlocking(() -> metadataFetcher.instance(host) .delegate() .metadata() - .getKeyspace(keyspace)); + .getKeyspace(keyspace).orElse(null)); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/job/OperationalJob.java b/server/src/main/java/org/apache/cassandra/sidecar/job/OperationalJob.java index 660f7db0d..c0a4f7ac5 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/job/OperationalJob.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/job/OperationalJob.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Future; import io.vertx.core.Promise; import org.apache.cassandra.sidecar.common.data.OperationalJobStatus; @@ -77,7 +77,7 @@ public final Void result() */ public long creationTime() { - return UUIDs.unixTimestamp(jobId); + return Uuids.unixTimestamp(jobId); } /** diff --git a/server/src/main/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManager.java b/server/src/main/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManager.java index faf87080b..b763f1d75 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManager.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManager.java @@ -27,7 +27,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import com.google.inject.Singleton; import io.vertx.core.Future; @@ -181,7 +181,7 @@ LiveMigrationTask createTask(LiveMigrationDataCopyRequest request, InstanceMetadata localInstanceMetadata) { - return liveMigrationTaskFactory.create(UUIDs.timeBased().toString(), request, source, port, localInstanceMetadata); + return liveMigrationTaskFactory.create(Uuids.timeBased().toString(), request, source, port, localInstanceMetadata); } /** diff --git a/server/src/main/java/org/apache/cassandra/sidecar/modules/ConfigurationModule.java b/server/src/main/java/org/apache/cassandra/sidecar/modules/ConfigurationModule.java index 785104b6a..e4feea963 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/modules/ConfigurationModule.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/modules/ConfigurationModule.java @@ -28,7 +28,6 @@ import org.slf4j.LoggerFactory; import com.codahale.metrics.MetricRegistry; -import com.datastax.driver.core.NettyOptions; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; @@ -120,7 +119,6 @@ CQLSessionProvider cqlSessionProvider(Vertx vertx, DriverUtils driverUtils) { CQLSessionProviderImpl cqlSessionProvider = new CQLSessionProviderImpl(sidecarConfiguration, - NettyOptions.DEFAULT_INSTANCE, driverUtils); vertx.eventBus().localConsumer(ON_SERVER_STOP.address(), message -> cqlSessionProvider.close()); return cqlSessionProvider; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscoverer.java b/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscoverer.java index a720ad359..39724e48a 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscoverer.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscoverer.java @@ -19,6 +19,7 @@ package org.apache.cassandra.sidecar.restore; import java.nio.file.Paths; +import java.time.LocalDate; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -32,10 +33,10 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Sets; +import com.google.common.primitives.Ints; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.LocalDate; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; @@ -67,6 +68,8 @@ import org.apache.cassandra.sidecar.tasks.ScheduleDecision; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import static org.apache.cassandra.sidecar.db.RestoreJobDatabaseAccessor.ONE_DAY_MILLISECONDS; + /** * {@link RestoreJobDiscoverer} handles background restore job discovery and handling it according to job status */ @@ -547,7 +550,7 @@ private boolean abortJob(RestoreJob job) // get the number of days delta between 2 dates. Always return non-negative values private int delta(LocalDate date1, LocalDate date2) { - return Math.abs(date1.getDaysSinceEpoch() - date2.getDaysSinceEpoch()); + return Ints.checkedCast(Math.abs(date1.toEpochDay() - date2.toEpochDay())); } static class JobIdsByDay @@ -616,7 +619,7 @@ void cleanupMaybe() private int populateDiscoveredDay(RestoreJob job) { - int day = job.createdAt.getDaysSinceEpoch(); + int day = Ints.checkedCast(job.createdAt.toEpochDay()); discoveredDays.add(day); return day; } @@ -643,7 +646,7 @@ int jobDiscoveryRecencyDays() static class RunContext { long nowMillis = System.currentTimeMillis(); - LocalDate today = LocalDate.fromMillisSinceEpoch(nowMillis); + LocalDate today = LocalDate.ofEpochDay(nowMillis / ONE_DAY_MILLISECONDS); int earliestInDays = 0; int abortedJobs = 0; int expiredJobs = 0; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java b/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java index be488ae4f..ba175bba1 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java @@ -33,7 +33,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.inject.name.Named; @@ -125,7 +125,7 @@ public static long timestampFromRestoreJobDir(String fileName) try { UUID id = UUID.fromString(fileName.substring(RESTORE_JOB_PREFIX_LEN)); - return UUIDs.unixTimestamp(id); + return Uuids.unixTimestamp(id); } catch (IllegalArgumentException e) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/routes/RoutingContextUtils.java b/server/src/main/java/org/apache/cassandra/sidecar/routes/RoutingContextUtils.java index 32ac0527c..c062b1c56 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/routes/RoutingContextUtils.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/routes/RoutingContextUtils.java @@ -21,8 +21,8 @@ import java.util.Objects; import java.util.Optional; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import io.vertx.core.Future; import io.vertx.ext.web.RoutingContext; import org.apache.cassandra.sidecar.common.server.data.QualifiedTableName; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/tasks/CdcConfigRefresherNotifierTask.java b/server/src/main/java/org/apache/cassandra/sidecar/tasks/CdcConfigRefresherNotifierTask.java index 19f1d0b08..b4beb0d7f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/tasks/CdcConfigRefresherNotifierTask.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/tasks/CdcConfigRefresherNotifierTask.java @@ -93,7 +93,8 @@ public void execute(Promise promise) @Override public ScheduleDecision scheduleDecision() { - if (!sidecarConfiguration.serviceConfiguration().schemaKeyspaceConfiguration().isEnabled() || !sidecarConfiguration.serviceConfiguration().cdcConfiguration().isEnabled()) + if (!sidecarConfiguration.serviceConfiguration().schemaKeyspaceConfiguration().isEnabled() + || !sidecarConfiguration.serviceConfiguration().cdcConfiguration().isEnabled()) { LOGGER.trace("Skipping config refreshing"); return ScheduleDecision.SKIP; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/tasks/ClusterTopologyMonitor.java b/server/src/main/java/org/apache/cassandra/sidecar/tasks/ClusterTopologyMonitor.java index 8b9677a6b..e3ddf7eba 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/tasks/ClusterTopologyMonitor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/tasks/ClusterTopologyMonitor.java @@ -304,12 +304,14 @@ protected static boolean changeInInstanceTopology(String instanceId, List { + builder.append(ks.describeWithChildren(true)).append("\n"); + }); + return builder.toString(); + } + + // TODO(lantoniak): Move to driver utils? + public static InetSocketAddress resolveEndpoint(Node node) + { + SocketAddress socketAddress = node.getEndPoint().resolve(); + Preconditions.checkState(socketAddress instanceof InetSocketAddress, "Unsupported endpoint type: " + node.getEndPoint()); + return (InetSocketAddress) socketAddress; } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/utils/TokenSplitUtil.java b/server/src/main/java/org/apache/cassandra/sidecar/utils/TokenSplitUtil.java index 709b9a1d7..762b6906a 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/utils/TokenSplitUtil.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/utils/TokenSplitUtil.java @@ -34,7 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Host; +import com.datastax.oss.driver.api.core.metadata.Node; import com.google.inject.Singleton; import org.apache.cassandra.bridge.TokenRange; import org.apache.cassandra.sidecar.cdc.CdcConfig; @@ -89,10 +89,10 @@ protected static int getOrInsert(TokenSplitConfigAccessor tokenSplitConfigAccess } int maxDcSize = fetcher.callOnFirstAvailableInstance(instanceMetadata -> instanceMetadata.delegate().metadata()) - .getAllHosts() + .getNodes().values() .stream() - .filter(host -> host.getDatacenter().equals(cdcConfig.datacenter())) - .collect(Collectors.groupingBy(Host::getDatacenter, Collectors.toList())) + .filter(host -> cdcConfig.datacenter().equals(host.getDatacenter())) + .collect(Collectors.groupingBy(Node::getDatacenter, Collectors.toList())) .values().stream() .mapToInt(List::size) .max() diff --git a/server/src/test/containerTest/org/apache/cassandra/sidecar/restore/StorageClientTest.java b/server/src/test/containerTest/org/apache/cassandra/sidecar/restore/StorageClientTest.java index aada2612e..d0cb65720 100644 --- a/server/src/test/containerTest/org/apache/cassandra/sidecar/restore/StorageClientTest.java +++ b/server/src/test/containerTest/org/apache/cassandra/sidecar/restore/StorageClientTest.java @@ -39,7 +39,7 @@ import org.junit.jupiter.api.io.TempDir; import com.adobe.testing.s3mock.testcontainers.S3MockContainer; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Vertx; import org.apache.cassandra.sidecar.TestResourceReaper; import org.apache.cassandra.sidecar.common.data.RestoreJobSecrets; @@ -111,7 +111,7 @@ static void setup() throws Exception .sessionToken("session") .region("us-west-1").build(); restoreJob = RestoreJob.builder() - .jobId(UUIDs.timeBased()) + .jobId(Uuids.timeBased()) .jobStatus(RestoreJobStatus.CREATED) .jobSecrets(new RestoreJobSecrets(credentials, credentials)) .sstableImportOptions(SSTableImportOptions.defaults()) @@ -169,7 +169,7 @@ static S3AsyncClient buildS3AsyncClient(Duration apiCallTimeout) throws Exceptio void testUnauthenticated() { // slice from a new job that has not been authenticated - RestoreRange unauthed = getMockRange(UUIDs.timeBased(), "newBucket", "newKey", null, null); + RestoreRange unauthed = getMockRange(Uuids.timeBased(), "newBucket", "newKey", null, null); assertThatThrownBy(() -> client.objectExists(unauthed).get()) .isInstanceOf(ExecutionException.class) .hasCauseInstanceOf(IllegalStateException.class) diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/acl/MutualTLSAuthenticationIntegrationTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/acl/MutualTLSAuthenticationIntegrationTest.java index db67b2d6e..519c9365f 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/acl/MutualTLSAuthenticationIntegrationTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/acl/MutualTLSAuthenticationIntegrationTest.java @@ -26,7 +26,7 @@ import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.client.HttpRequest; @@ -166,7 +166,7 @@ void testTransitiveSuperUser(VertxTestContext context, CassandraTestContext cass assertThat(authorized.await(30, TimeUnit.SECONDS)).isTrue(); // drop superuser role, during cache refresh nonsuperuser role will lose superuser status - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("DROP role superuser"); // wait for cache refreshes @@ -264,7 +264,7 @@ private void insertIdentityRole(CassandraTestContext cassandraContext, String id private void grantSidecarPermission(String role, String resource, String permission) { - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute(String.format("INSERT INTO sidecar_internal.role_permissions_v1 (role, resource, permissions) " + "VALUES ('%s', '%s', {'%s'})", role, resource, permission)); } diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java index 5bf7b9856..756fb58d9 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java @@ -19,6 +19,7 @@ package org.apache.cassandra.sidecar.cluster.driver; import java.net.InetSocketAddress; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; @@ -30,7 +31,7 @@ import org.junit.jupiter.api.Assertions; import com.datastax.driver.core.DriverUtils; -import com.datastax.driver.core.Host; +import com.datastax.oss.driver.api.core.metadata.Node; import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; import org.apache.cassandra.sidecar.testing.IntegrationTestBase; @@ -47,7 +48,7 @@ public class SidecarLoadBalancingPolicyTest extends IntegrationTestBase public static final int SIDECAR_MANAGED_INSTANCES = 2; - private static List getConnectedHosts(Set hosts) + private static List getConnectedHosts(Collection hosts) { return hosts.stream() .filter(DriverUtils::hasActiveConnections) @@ -63,8 +64,8 @@ protected int[] getInstancesToManage(int clusterSize) @CassandraIntegrationTest(nodesPerDc = 6) public void shouldMaintainMinimumConnections() throws ExecutionException, InterruptedException { - Set hosts = sidecarTestContext.session().getCluster().getMetadata().getAllHosts(); - List connectedHosts = getConnectedHosts(hosts); + Collection hosts = sidecarTestContext.session().getMetadata().getNodes().values(); + List connectedHosts = getConnectedHosts(hosts); // We manage 2 hosts, and ask for an additional 2 (the default) for connections. // Therefore, we expect 4 hosts to have connections at startup. int expectedConnections = SIDECAR_MANAGED_INSTANCES + SidecarLoadBalancingPolicy.MIN_NON_LOCAL_CONNECTIONS; @@ -81,12 +82,12 @@ public void shouldMaintainMinimumConnections() throws ExecutionException, Interr private void assertConnectionsWithRetry(InetSocketAddress downInstanceAddress, int expectedConnections) { - List connectedHosts = Collections.emptyList(); + List connectedHosts = Collections.emptyList(); int attempts = 0; // Retry for up to 2 minutes, but passes much more quickly most of the time, so this should be safe. while (attempts <= 24) { - Set hosts = sidecarTestContext.session().getCluster().getMetadata().getAllHosts(); + Collection hosts = sidecarTestContext.session().getMetadata().getNodes().values(); connectedHosts = getConnectedHosts(hosts); List connectedAddresses = getAddresses(connectedHosts); if (connectedHosts.size() == expectedConnections && !connectedAddresses.contains(downInstanceAddress)) @@ -108,10 +109,10 @@ private void assertConnectionsWithRetry(InetSocketAddress downInstanceAddress, i Assertions.fail(message); } - private List getAddresses(List connectedHosts) + private List getAddresses(List connectedHosts) { return connectedHosts.stream() - .map(h -> h.getEndPoint().resolve()) + .map(h -> (InetSocketAddress) h.getEndPoint().resolve()) .collect(Collectors.toList()); } diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/datahub/SchemaReporterIntegrationTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/datahub/SchemaReporterIntegrationTest.java index eaa4fdcbe..5cac0404f 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/datahub/SchemaReporterIntegrationTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/datahub/SchemaReporterIntegrationTest.java @@ -23,11 +23,13 @@ import java.io.StringReader; import java.util.Collections; import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import com.codahale.metrics.SharedMetricRegistries; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import com.linkedin.data.DataList; import com.linkedin.data.codec.JacksonDataCodec; import org.apache.cassandra.sidecar.common.server.utils.IOUtils; @@ -120,9 +122,9 @@ void testSchemaConverter() throws IOException // First, ensure the returned schema matches the reference one // (while ignoring name suffixes and whitespace characters) JsonEmitter emitter = new JsonEmitter(); - try (Session session = maybeGetSession()) + try (CqlSession session = maybeGetSession()) { - new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processScheduled(session.getCluster()); + new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processScheduled(session); } String actualJson = normalizeNames(emitter.content()); String expectedJson = IOUtils.readFully("/datahub/integration_test.json"); @@ -130,8 +132,8 @@ void testSchemaConverter() throws IOException // Second, make sure the returned schema produces the same tree of // DataHub objects after having been normalized and deserialized - DataList actualData = CODEC.readList(new StringReader(actualJson)); - DataList expectedData = CODEC.readList(new StringReader(expectedJson)); + DataList actualData = CODEC.readList(new StringReader(StringUtils.normalizeSpace(actualJson))); + DataList expectedData = CODEC.readList(new StringReader(StringUtils.normalizeSpace(expectedJson))); assertThat(actualData).isEqualTo(expectedData); // Third, validate the captured metrics: one execution triggered by the schedule and diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorIntTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorIntTest.java index 8f8fbe717..63ff15c6c 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorIntTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorIntTest.java @@ -23,7 +23,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.data.ConsistencyLevel; import org.apache.cassandra.sidecar.common.data.RestoreJobSecrets; import org.apache.cassandra.sidecar.common.data.RestoreJobStatus; @@ -46,7 +46,7 @@ class RestoreJobDatabaseAccessorIntTest extends IntegrationTestBase @CassandraIntegrationTest void testCrudOperations() { - waitForSchemaReady(10, TimeUnit.SECONDS); + waitForSchemaReady(30, TimeUnit.SECONDS); RestoreJobDatabaseAccessor accessor = injector.getInstance(RestoreJobDatabaseAccessor.class); assertThat(accessor.findAllRecent(now, 3)).isEmpty(); @@ -102,7 +102,7 @@ private UUID createJob(RestoreJobDatabaseAccessor accessor) private UUID createJob(RestoreJobDatabaseAccessor accessor, boolean restoreToLocalDatacenterOnly) { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); CreateRestoreJobRequestPayload.Builder builder = CreateRestoreJobRequestPayload.builder(secrets, expiresAtMillis) .jobId(jobId) .jobAgent("agent"); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessorIntTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessorIntTest.java index 3872530ed..2107598e2 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessorIntTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessorIntTest.java @@ -24,7 +24,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.server.data.RestoreRangeStatus; import org.apache.cassandra.sidecar.testing.IntegrationTestBase; import org.apache.cassandra.testing.CassandraIntegrationTest; @@ -37,10 +37,10 @@ class RestoreRangeDatabaseAccessorIntTest extends IntegrationTestBase @CassandraIntegrationTest void testCrudOperations() { - waitForSchemaReady(10, TimeUnit.SECONDS); + waitForSchemaReady(30, TimeUnit.SECONDS); RestoreRangeDatabaseAccessor accessor = injector.getInstance(RestoreRangeDatabaseAccessor.class); - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); assertThat(accessor.findAll(jobId, (short) 0)).isEmpty(); // create range diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessorIntTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessorIntTest.java index 80b8a4d27..4e9bd4017 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessorIntTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessorIntTest.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.testing.IntegrationTestBase; import org.apache.cassandra.testing.CassandraIntegrationTest; @@ -33,10 +33,10 @@ class RestoreSliceDatabaseAccessorIntTest extends IntegrationTestBase @CassandraIntegrationTest void testCrudOperations() { - waitForSchemaReady(10, TimeUnit.SECONDS); + waitForSchemaReady(30, TimeUnit.SECONDS); RestoreSliceDatabaseAccessor accessor = injector.getInstance(RestoreSliceDatabaseAccessor.class); - RestoreJob testJob = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob testJob = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); List fetchedSlices = accessor.selectByJobByBucketByTokenRange(testJob, (short) 0, new TokenRange(0, 10)); assertThat(fetchedSlices).isEmpty();; diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/restore/RestoreJobTestUtils.java b/server/src/test/integration/org/apache/cassandra/sidecar/restore/RestoreJobTestUtils.java index cbb35a225..7f85e1a59 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/restore/RestoreJobTestUtils.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/restore/RestoreJobTestUtils.java @@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.AbstractModule; import com.google.inject.Module; import com.google.inject.Provides; @@ -87,7 +87,7 @@ public static void assertRestoreRange(RestoreRange range, long startToken, long public static UUID createJob(RestoreJobTestUtils.RestoreJobClient testClient, QualifiedTableName tableName) { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); long expireAt = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(2); CreateRestoreJobRequestPayload payload = CreateRestoreJobRequestPayload .builder(RestoreJobSecretsGen.genRestoreJobSecrets(), expireAt) diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/restore/jobdiscoverer/RestoreJobDiscovererNodeLeavingIntTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/restore/jobdiscoverer/RestoreJobDiscovererNodeLeavingIntTest.java index f8704ba5b..f93cddded 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/restore/jobdiscoverer/RestoreJobDiscovererNodeLeavingIntTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/restore/jobdiscoverer/RestoreJobDiscovererNodeLeavingIntTest.java @@ -166,7 +166,9 @@ protected String subjectAlternativeNameIpAddress() return MANAGED_CASSANDRA_NODE_IP; } - private static IClusterExtension startCluster(TokenSupplier tokenSupplier, ConfigurableCassandraTestContext cassandraTestContext, int leavingNodeNum) + private static IClusterExtension startCluster(TokenSupplier tokenSupplier, + ConfigurableCassandraTestContext cassandraTestContext, + int leavingNodeNum) { BBHelperLeavingNode.reset(); return cassandraTestContext.configureAndStartCluster(builder -> { diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/StreamSSTableComponentHandlerIntegrationTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/StreamSSTableComponentHandlerIntegrationTest.java index d234c4513..c2968ca35 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/StreamSSTableComponentHandlerIntegrationTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/StreamSSTableComponentHandlerIntegrationTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; @@ -141,7 +141,7 @@ QualifiedTableName createTestTableAndPopulate() " rank int, \n" + " PRIMARY KEY ((race_year, race_name), rank) \n" + ");"); - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("CREATE INDEX ryear ON " + tableName + " (race_year);"); session.execute("INSERT INTO " + tableName + " (race_year, race_name, rank, cyclist_name) " + diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/CreateSnapshotHandlerIntegrationTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/CreateSnapshotHandlerIntegrationTest.java index 9a5e933d0..7b48b569a 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/CreateSnapshotHandlerIntegrationTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/CreateSnapshotHandlerIntegrationTest.java @@ -30,7 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -301,7 +301,7 @@ private QualifiedTableName createTestTableAndPopulate(String tableNamePrefix) { QualifiedTableName tableName = createTestTable(tableNamePrefix, "CREATE TABLE %s (id text PRIMARY KEY, name text)" + WITH_COMPACTION_DISABLED + ";"); - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("INSERT INTO " + tableName + " (id, name) VALUES ('1', 'Francisco');"); session.execute("INSERT INTO " + tableName + " (id, name) VALUES ('2', 'Saranya');"); @@ -313,7 +313,7 @@ private QualifiedTableName createTestTableAndPopulate() { QualifiedTableName tableName = createTestTable( "CREATE TABLE %s (id text PRIMARY KEY, name text)" + WITH_COMPACTION_DISABLED + ";"); - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("INSERT INTO " + tableName + " (id, name) VALUES ('1', 'Francisco');"); session.execute("INSERT INTO " + tableName + " (id, name) VALUES ('2', 'Saranya');"); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/ListSnapshotHandlerIntegrationTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/ListSnapshotHandlerIntegrationTest.java index 1d935f2c1..173b147d3 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/ListSnapshotHandlerIntegrationTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/snapshots/ListSnapshotHandlerIntegrationTest.java @@ -24,7 +24,7 @@ import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.vertx.core.Future; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.client.HttpResponse; @@ -47,7 +47,7 @@ class ListSnapshotHandlerIntegrationTest extends IntegrationTestBase void testListSnapshot(VertxTestContext context) throws Exception { createTestKeyspace(); - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("CREATE TABLE " + TEST_KEYSPACE + ".rank_by_year_and_name ( \n" + " race_year int, \n" + " race_name text, \n" + @@ -139,7 +139,7 @@ void testListSnapshot(VertxTestContext context) throws Exception .onFailure(context::failNow); } - private void populateTable(Session session, String tableName) + private void populateTable(CqlSession session, String tableName) { for (int i = 0; i < 1000; i++) { diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableImportHandlerIntegrationTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableImportHandlerIntegrationTest.java index a393a4242..ef8e429d6 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableImportHandlerIntegrationTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableImportHandlerIntegrationTest.java @@ -31,8 +31,8 @@ import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.ResultSet; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.AsyncResult; import io.vertx.core.Future; @@ -78,7 +78,7 @@ void testSSTableImport(VertxTestContext vertxTestContext) // Test the import SSTable endpoint by importing data that was originally truncated. // Verify by querying the table contains all the results before truncation and after truncation. createTestKeyspace(); - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); QualifiedTableName tableName = createTestTableAndPopulate(sidecarTestContext, Arrays.asList("a", "b")); // create a snapshot called -snapshot for tbl1 @@ -162,7 +162,7 @@ private void sendRequest(VertxTestContext vertxTestContext, Supplier queryValues(QualifiedTableName tableName) { - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); return session.execute("SELECT id FROM " + tableName) .all() .stream() @@ -189,12 +189,12 @@ private QualifiedTableName createTestTableAndPopulate(CassandraSidecarTestContex { QualifiedTableName tableName = createTestTable( "CREATE TABLE IF NOT EXISTS %s (id text, PRIMARY KEY(id))" + WITH_COMPACTION_DISABLED + ";"); - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); populateTable(session, tableName, values); return tableName; } - private void populateTable(Session session, QualifiedTableName tableName, List values) + private void populateTable(CqlSession session, QualifiedTableName tableName, List values) { for (String value : values) { diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/JoiningMultiDCTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/JoiningMultiDCTest.java index 260e37dba..36a958e01 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/JoiningMultiDCTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/JoiningMultiDCTest.java @@ -64,14 +64,16 @@ void retrieveMappingMultiDCJoiningTest(VertxTestContext context, TestTokenSupplier tokenSupplier = TestTokenSupplier.evenlyDistributedTokens(6, 0, 2, 1); tokenSupplier.swap(5, 10); - IClusterExtension cluster = getMultiDCCluster(BBHelperDoubleClusterMultiDC::install, cassandraTestContext, tokenSupplier, null); + IClusterExtension cluster = getMultiDCCluster(BBHelperDoubleClusterMultiDC::install, + cassandraTestContext, tokenSupplier, null); runJoiningTestScenario(context, BBHelperDoubleClusterMultiDC.transientStateStart, BBHelperDoubleClusterMultiDC.transientStateEnd, cluster, generateExpectedRanges(tokenSupplier), - generateExpectedRangeDoubleClusterSizeMultiDC(tokenSupplier, sidecarTestContext.cassandraTestContext().annotation), + generateExpectedRangeDoubleClusterSizeMultiDC(tokenSupplier, + sidecarTestContext.cassandraTestContext().annotation), true, tokenSupplier); } @@ -98,7 +100,8 @@ void retrieveMappingMultiDCJoiningTest(VertxTestContext context, * Expected Range 2 - B, C, D, A (With A remaining as a replica during the join) *

    */ - private Map, List>> generateExpectedRangeDoubleClusterSizeMultiDC(TokenSupplier tokenSupplier, CassandraIntegrationTest annotation) + private Map, List>> generateExpectedRangeDoubleClusterSizeMultiDC(TokenSupplier tokenSupplier, + CassandraIntegrationTest annotation) { List> expectedRanges = generateExpectedRanges(true, tokenSupplier, annotation); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTest.java index aa02257c9..4865d649e 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTest.java @@ -167,7 +167,8 @@ private Map, List>> generateExpectedRangeM * Expected Range 2 - B, C, D, A (With A taking over the range of the leaving node) */ - private Map, List>> generateExpectedRangeMappingMultipleLeavingNodes(TokenSupplier tokenSupplier, CassandraIntegrationTest annotation) + private Map, List>> generateExpectedRangeMappingMultipleLeavingNodes(TokenSupplier tokenSupplier, + CassandraIntegrationTest annotation) { List> expectedRanges = generateExpectedRanges(false, tokenSupplier, annotation); Map, List> mapping = new HashMap<>(); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTestMultiDC.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTestMultiDC.java index 34d7f5880..0b45a5adc 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTestMultiDC.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/LeavingTestMultiDC.java @@ -62,7 +62,8 @@ void retrieveMappingWithLeavingNodesMultiDC(VertxTestContext context, // We'll manually swap around tokens, so use 0 as number of new DCs TestTokenSupplier tokenSupplier = TestTokenSupplier.evenlyDistributedTokens(6, 0, 2, 1); tokenSupplier.swap(5, 10); - IClusterExtension cluster = getMultiDCCluster(BBHelperLeavingNodesMultiDC::install, cassandraTestContext, tokenSupplier, null); + IClusterExtension cluster = getMultiDCCluster(BBHelperLeavingNodesMultiDC::install, + cassandraTestContext, tokenSupplier, null); runLeavingTestScenario(context, leavingNodesPerDC, BBHelperLeavingNodesMultiDC.transientStateStart, @@ -96,7 +97,8 @@ void retrieveMappingWithLeavingNodesMultiDC(VertxTestContext context, * Note: Cassandra now returns token boundaries as separate single-token ranges, so the total * number of ranges is 13 (6 regular ranges + 6 token boundary ranges + 1 wraparound). */ - private Map, List>> generateExpectedRangeMappingLeavingNodeMultiDC(TokenSupplier tokenSupplier, CassandraIntegrationTest annotation) + private Map, List>> generateExpectedRangeMappingLeavingNodeMultiDC(TokenSupplier tokenSupplier, + CassandraIntegrationTest annotation) { List> expectedRanges = generateExpectedRanges(true, tokenSupplier, annotation); Map, List> dc1Mapping = new HashMap<>(); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/MultiDCSingleReplicatedJoiningTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/MultiDCSingleReplicatedJoiningTest.java index 6f92a59af..4f559319b 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/MultiDCSingleReplicatedJoiningTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/MultiDCSingleReplicatedJoiningTest.java @@ -64,12 +64,13 @@ void retrieveMappingsSingleDCReplicatedKeyspace(VertxTestContext context, // We'll manually swap around tokens, so use 0 as number of new DCs TestTokenSupplier tokenSupplier = TestTokenSupplier.evenlyDistributedTokens(6, 0, 2, 1); tokenSupplier.swap(5, 10); - IClusterExtension cluster = getMultiDCCluster(BBHelperMultiDC::install, cassandraTestContext, tokenSupplier, - builder -> builder.additionalInstanceConfig(Map.of("progress_barrier_default_consistency_level", "QUORUM", - "progress_barrier_timeout", "30s", - "cms_await_timeout", "60s", - "accord.enabled", "false", - "write_request_timeout", "10s"))); + IClusterExtension cluster = + getMultiDCCluster(BBHelperMultiDC::install, cassandraTestContext, tokenSupplier, + builder -> builder.additionalInstanceConfig(Map.of("progress_barrier_default_consistency_level", "QUORUM", + "progress_barrier_timeout", "30s", + "cms_await_timeout", "60s", + "accord.enabled", "false", + "write_request_timeout", "10s"))); CassandraIntegrationTest annotation = sidecarTestContext.cassandraTestContext().annotation; runJoiningTestScenario(context, BBHelperMultiDC.transientStateStart, @@ -98,7 +99,8 @@ void retrieveMappingsSingleDCReplicatedKeyspace(VertxTestContext context, * Range 2 - B, C, D (with E being the joining node) * Expected Range 2 - B, C, D, E */ - private Map, List>> generateExpectedRangeMappingOneOf2DCs(TokenSupplier tokenSupplier, CassandraIntegrationTest annotation) + private Map, List>> generateExpectedRangeMappingOneOf2DCs(TokenSupplier tokenSupplier, + CassandraIntegrationTest annotation) { List> expectedRanges = generateExpectedRanges(false, tokenSupplier, annotation); Map, List> dc1Mapping = new HashMap<>(); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/ReplacementMultiDCTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/ReplacementMultiDCTest.java index e9c70dd8c..818ae3d73 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/ReplacementMultiDCTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/routes/tokenrange/ReplacementMultiDCTest.java @@ -60,12 +60,13 @@ void retrieveMappingWithNodeReplacementMultiDC(VertxTestContext context, BBHelperReplacementsMultiDC.reset(); TestTokenSupplier tokenSupplier = getTestTokenSupplier(); Map, List>> expectedRangeMappings = generateExpectedRangeMappingReplacementMultiDC(); - IClusterExtension cluster = getMultiDCCluster(BBHelperReplacementsMultiDC::install, cassandraTestContext, tokenSupplier, - builder -> builder.additionalInstanceConfig(Map.of("progress_barrier_default_consistency_level", "QUORUM", - "progress_barrier_timeout", "30s", - "cms_await_timeout", "60s", - "accord.enabled", "false", - "write_request_timeout", "10s"))); + IClusterExtension cluster = + getMultiDCCluster(BBHelperReplacementsMultiDC::install, cassandraTestContext, tokenSupplier, + builder -> builder.additionalInstanceConfig(Map.of("progress_barrier_default_consistency_level", "QUORUM", + "progress_barrier_timeout", "30s", + "cms_await_timeout", "60s", + "accord.enabled", "false", + "write_request_timeout", "10s"))); int initialClusterSize = cluster.size(); List nodesToRemove = Arrays.asList(cluster.get(initialClusterSize - 1), cluster.get(initialClusterSize)); diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java b/server/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java index 0cd964033..e92675e1b 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java @@ -30,7 +30,7 @@ import java.util.stream.IntStream; import com.codahale.metrics.MetricRegistry; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.vertx.core.Vertx; import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.distributed.api.IInstanceConfig; @@ -190,7 +190,7 @@ public synchronized InstancesMetadata refreshInstancesMetadata() return this.instancesMetadata; } - public Session session() + public CqlSession session() { return sessionProvider == null ? null : sessionProvider.get(); } @@ -239,9 +239,9 @@ public CQLSessionProviderImpl buildNewCqlSessionProvider() IClusterExtension cluster = cluster(); List configs = buildInstanceConfigs(cluster); List addresses = buildContactList(configs); - return new CQLSessionProviderImpl(addresses, addresses, 500, null, + return new CQLSessionProviderImpl(addresses, addresses, 500, "datacenter1", 0, username, password, - sslConfiguration, SharedExecutorNettyOptions.INSTANCE); + sslConfiguration); } private synchronized InstancesMetadata buildInstancesMetadata(CassandraVersionProvider versionProvider, @@ -252,9 +252,9 @@ private synchronized InstancesMetadata buildInstancesMetadata(CassandraVersionPr jmxClients = new ArrayList<>(); List configs = buildInstanceConfigs(cluster); List addresses = buildContactList(configs); - sessionProvider = new CQLSessionProviderImpl(addresses, addresses, 500, null, + sessionProvider = new CQLSessionProviderImpl(addresses, addresses, 500, "datacenter1", 0, username, password, - sslConfiguration, SharedExecutorNettyOptions.INSTANCE); + sslConfiguration); for (int i = 0; i < configs.size(); i++) { if (configs.get(i) == null) diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestBase.java b/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestBase.java index ae69ca2d6..fc7ec4164 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestBase.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestBase.java @@ -44,9 +44,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.ResultSet; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; @@ -72,6 +71,7 @@ import org.apache.cassandra.sidecar.modules.SidecarModules; import org.apache.cassandra.sidecar.server.Server; import org.apache.cassandra.sidecar.server.SidecarServerEvents; +import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.apache.cassandra.testing.AbstractCassandraTestContext; import org.apache.cassandra.testing.AuthMode; import org.apache.cassandra.testing.utils.tls.CertificateBuilder; @@ -305,7 +305,7 @@ protected void createKeyspace(String keyspaceName, Map rf) { try { - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); ResultSet rs = session.execute("CREATE KEYSPACE " + IF_NOT_EXISTS + " " + keyspaceName + " WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', " + generateRfString(rf) + " };"); @@ -340,7 +340,7 @@ protected QualifiedTableName createTestTable(String createTableStatement) protected QualifiedTableName createTestTable(String tablePrefix, String createTableStatement) { - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); QualifiedTableName tableName = uniqueTestTableFullName(tablePrefix); session.execute(String.format(createTableStatement, tableName)); return tableName; @@ -384,7 +384,7 @@ protected String createTestUdt(@NotNull String name, statement.append(schema); statement.append(");"); - Session session = maybeGetSession(); // Leave session open to enable its subsequent use by the test + CqlSession session = maybeGetSession(); // Leave session open to enable its subsequent use by the test session.execute(statement.toString()); return udt; @@ -397,13 +397,13 @@ protected void createRole(String role, boolean superUser) protected void createRole(String role, String password, boolean superUser) { - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("CREATE ROLE \"" + role + "\" WITH PASSWORD ='" + password + "' AND SUPERUSER = " + superUser + " AND LOGIN = true;"); } protected void grantRole(String role, String roleToAssign) { - Session session = maybeGetSession(); + CqlSession session = maybeGetSession(); session.execute("GRANT " + roleToAssign + " TO " + role + ";"); } @@ -434,9 +434,9 @@ public static void awaitLatchOrTimeout(CountDownLatch latch, long duration, Time awaitLatchOrTimeout(latch, duration, timeUnit, null); } - protected Session maybeGetSession() + protected CqlSession maybeGetSession() { - Session session = sidecarTestContext.session(); + CqlSession session = sidecarTestContext.session(); assertThat(session).isNotNull(); return session; } @@ -483,8 +483,8 @@ protected void completeContextOrThrow(VertxTestContext context) private static QualifiedTableName uniqueTestTableFullName(String tablePrefix) { String uniqueTableName = tablePrefix + TEST_TABLE_ID.getAndIncrement(); - return new QualifiedTableName(new Name(Metadata.quoteIfNecessary(TEST_KEYSPACE)), - new Name(Metadata.quoteIfNecessary(uniqueTableName))); + return new QualifiedTableName(new Name(MetadataUtils.quoteIfNecessary(TEST_KEYSPACE)), + new Name(MetadataUtils.quoteIfNecessary(uniqueTableName))); } /** diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java b/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java index 7d985e2d4..e5d932ef7 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java @@ -25,7 +25,8 @@ import java.util.Map; import java.util.Set; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.NodeStateListener; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; @@ -225,7 +226,7 @@ public CQLSessionProvider cqlSessionProvider(Vertx vertx) { @Override @NotNull - public Session get() + public CqlSession get() { return cassandraSidecarTestContext.session(); } @@ -237,10 +238,20 @@ public void close() } @Override - public Session getIfConnected() + public CqlSession getIfConnected() { return get(); } + + @Override + public void registerNodeStateListener(NodeStateListener nodeStateListener) + { + } + + @Override + public void unregisterNodeStateListener(NodeStateListener nodeStateListener) + { + } }; vertx.eventBus().localConsumer(ON_SERVER_STOP.address(), message -> cqlSessionProvider.close()); return cqlSessionProvider; diff --git a/server/src/test/integration/org/apache/cassandra/testing/CassandraTestTemplate.java b/server/src/test/integration/org/apache/cassandra/testing/CassandraTestTemplate.java index 1ecfc9de2..e5abd4a2c 100644 --- a/server/src/test/integration/org/apache/cassandra/testing/CassandraTestTemplate.java +++ b/server/src/test/integration/org/apache/cassandra/testing/CassandraTestTemplate.java @@ -200,8 +200,10 @@ private BeforeEachCallback beforeEach() if (requestedVersion.version.getMajor() >= MIN_VERSION_WITH_MTLS) { additionalInstanceConfig.put("authenticator.class_name", "org.apache.cassandra.auth.MutualTlsWithPasswordFallbackAuthenticator"); - additionalInstanceConfig.put("authenticator.parameters", Collections.singletonMap("validator_class_name", - "org.apache.cassandra.auth.SpiffeCertificateValidator")); + additionalInstanceConfig.put( + "authenticator.parameters", + Collections.singletonMap("validator_class_name", "org.apache.cassandra.auth.SpiffeCertificateValidator") + ); additionalInstanceConfig.put("role_manager", "CassandraRoleManager"); additionalInstanceConfig.put("authorizer", "CassandraAuthorizer"); additionalInstanceConfig.put("client_encryption_options.enabled", "true"); diff --git a/server/src/test/integration/org/apache/cassandra/testing/ConfigurableCassandraTestContext.java b/server/src/test/integration/org/apache/cassandra/testing/ConfigurableCassandraTestContext.java index 81e219c45..29c05e592 100644 --- a/server/src/test/integration/org/apache/cassandra/testing/ConfigurableCassandraTestContext.java +++ b/server/src/test/integration/org/apache/cassandra/testing/ConfigurableCassandraTestContext.java @@ -52,7 +52,8 @@ public ConfigurableCassandraTestContext(SimpleCassandraVersion version, public IClusterExtension configureAndStartCluster(Consumer configurator) { configurator.accept(clusterConfiguration); - IClusterExtension cluster = CassandraTestTemplate.retriableStartCluster(classLoaderWrapper, versionString, clusterConfiguration, 3); + IClusterExtension cluster = + CassandraTestTemplate.retriableStartCluster(classLoaderWrapper, versionString, clusterConfiguration, 3); setCluster(cluster); return cluster; } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/TestCassandraAdapterDelegate.java b/server/src/test/java/org/apache/cassandra/sidecar/TestCassandraAdapterDelegate.java index af4d97d53..9b0496d0c 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/TestCassandraAdapterDelegate.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/TestCassandraAdapterDelegate.java @@ -18,7 +18,7 @@ package org.apache.cassandra.sidecar; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; import io.vertx.core.Vertx; import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate; import org.apache.cassandra.sidecar.common.response.NodeSettings; diff --git a/server/src/test/java/org/apache/cassandra/sidecar/TestModule.java b/server/src/test/java/org/apache/cassandra/sidecar/TestModule.java index 87c33d606..ee95ae3ec 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/TestModule.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/TestModule.java @@ -22,14 +22,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Function; import com.google.common.util.concurrent.SidecarRateLimiter; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; @@ -202,9 +204,11 @@ private InstanceMetadata mockInstance(TestCassandraAdapterDelegate delegate, when(mockStorageOperations.dataFileLocations()).thenReturn(List.of(dataDir)); Metadata metadata = CassandraClientTokenRingProviderTest.getMetadata(); KeyspaceMetadata keyspaceMetadata = mock(KeyspaceMetadata.class); - when(metadata.getKeyspace(any())).thenReturn(keyspaceMetadata); + when(metadata.getKeyspace(any(String.class))).thenReturn(Optional.of(keyspaceMetadata)); + when(metadata.getKeyspace(any(CqlIdentifier.class))).thenReturn(Optional.of(keyspaceMetadata)); TableMetadata tableMetadata = mock(TableMetadata.class); - when(keyspaceMetadata.getTable(any())).thenReturn(tableMetadata); + when(keyspaceMetadata.getTable(any(String.class))).thenReturn(Optional.of(tableMetadata)); + when(keyspaceMetadata.getTable(any(CqlIdentifier.class))).thenReturn(Optional.of(tableMetadata)); delegate.setMetadata(metadata); delegate.setStorageOperations(mockStorageOperations); if (isUp) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/MutualTLSAuthenticationHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/MutualTLSAuthenticationHandlerTest.java index 744c1551a..a4e7d0709 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/MutualTLSAuthenticationHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/MutualTLSAuthenticationHandlerTest.java @@ -387,13 +387,14 @@ public SidecarConfigurationImpl abstractConfig() .expireAfterAccess(MillisecondBoundConfiguration.parse("30s")) .maximumSize(100) .build(); - AccessControlConfiguration accessControlConfiguration = AccessControlConfigurationImpl.builder() - .enabled(true) - .authenticatorsConfiguration(authenticatorsConfiguration()) - .authorizerConfiguration(new ParameterizedClassConfigurationImpl(className, Collections.emptyMap())) - .adminIdentities(Set.of(ADMIN_IDENTITY)) - .permissionCacheConfiguration(permissionCacheConfiguration) - .build(); + AccessControlConfiguration accessControlConfiguration = + AccessControlConfigurationImpl.builder() + .enabled(true) + .authenticatorsConfiguration(authenticatorsConfiguration()) + .authorizerConfiguration(new ParameterizedClassConfigurationImpl(className, Collections.emptyMap())) + .adminIdentities(Set.of(ADMIN_IDENTITY)) + .permissionCacheConfiguration(permissionCacheConfiguration) + .build(); return super.abstractConfig(sslConfiguration, builder -> builder.accessControlConfiguration(accessControlConfiguration)); } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/ReloadingJwtAuthenticationHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/ReloadingJwtAuthenticationHandlerTest.java index 8737b56d3..4c246b4d7 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/ReloadingJwtAuthenticationHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/acl/authentication/ReloadingJwtAuthenticationHandlerTest.java @@ -134,9 +134,10 @@ void testStatelessJwtAuthenticationWithValidToken() throws Exception // Configure for stateless authentication String site = String.format("http://localhost:%d/jwks", mockServer.actualPort()); - JwtParameterExtractor parameterExtractor = new JwtParameterExtractor(Map.of("enabled", "true", - "site", site, - "jwt_auth_type", JwtParameters.AuthType.STATELESS.toString().toLowerCase())); + JwtParameterExtractor parameterExtractor = + new JwtParameterExtractor(Map.of("enabled", "true", + "site", site, + "jwt_auth_type", JwtParameters.AuthType.STATELESS.toString().toLowerCase())); JwtRoleProcessor mockRoleProcessor = mock(JwtRoleProcessor.class); when(mockRoleProcessor.processRoles(any())).thenReturn(Future.succeededFuture(List.of("test_role"))); ReloadingJwtAuthenticationHandler handler = getReloadingJwtAuthenticationHandler(vertx, parameterExtractor, mockRoleProcessor); @@ -179,7 +180,9 @@ void testStatelessJwtAuthenticationWithValidToken() throws Exception } } - private static @NotNull ReloadingJwtAuthenticationHandler getReloadingJwtAuthenticationHandler(Vertx vertx, JwtParameterExtractor parameterExtractor, JwtRoleProcessor mockRoleProcessor) + private static @NotNull ReloadingJwtAuthenticationHandler getReloadingJwtAuthenticationHandler(Vertx vertx, + JwtParameterExtractor parameterExtractor, + JwtRoleProcessor mockRoleProcessor) { ExecutorPools executorPools = new ExecutorPools(vertx, new ServiceConfigurationImpl()); ClusterLease clusterLease = new ClusterLease(); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationProviderTest.java b/server/src/test/java/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationProviderTest.java index d22c628f6..9589a9457 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationProviderTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/acl/authorization/RoleBasedAuthorizationProviderTest.java @@ -31,8 +31,8 @@ import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; -import static com.datastax.driver.core.Assertions.assertThat; import static org.apache.cassandra.sidecar.utils.AuthUtils.CASSANDRA_ROLES_ATTRIBUTE_NAME; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegateTest.java b/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegateTest.java index 86acf0f8d..606ae488f 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegateTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegateTest.java @@ -26,17 +26,17 @@ import org.junit.jupiter.api.Test; import com.codahale.metrics.MetricRegistry; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.SimpleStatement; -import com.datastax.driver.core.Statement; -import com.datastax.driver.core.exceptions.NoHostAvailableException; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.NoNodeAvailableException; +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.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.internal.core.context.InternalDriverContext; import io.vertx.core.Vertx; import io.vertx.core.eventbus.EventBus; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; @@ -90,7 +90,7 @@ public void setUp() private static @NotNull DriverUtils getMockDriverUtils(String host, int port, Metadata metadata) { DriverUtils driverUtils = Mockito.mock(DriverUtils.class); - Host mockHost = Mockito.mock(Host.class); + Node mockHost = Mockito.mock(Node.class); InetSocketAddress mockAddress = new InetSocketAddress(host, port); when(driverUtils.getHost(metadata, mockAddress)).thenReturn(mockHost); return driverUtils; @@ -98,14 +98,17 @@ public void setUp() private static @NotNull CQLSessionProvider getMockCqlSessionProvider(Metadata metadata) { - Session session = Mockito.mock(Session.class); - Cluster cluster = Mockito.mock(Cluster.class); - when(cluster.isClosed()).thenReturn(false); - when(cluster.getMetadata()).thenReturn(metadata); - when(session.getCluster()).thenReturn(cluster); + CqlSession session = Mockito.mock(CqlSession.class); + InternalDriverContext driverContext = Mockito.mock(InternalDriverContext.class); + com.datastax.oss.driver.internal.core.context.EventBus eventBus = + Mockito.mock(com.datastax.oss.driver.internal.core.context.EventBus.class); + when(session.isClosed()).thenReturn(false); + when(session.getMetadata()).thenReturn(metadata); PreparedStatement preparedStatement = Mockito.mock(PreparedStatement.class); when(preparedStatement.bind()).thenReturn(Mockito.mock(BoundStatement.class)); when(session.prepare(any(String.class))).thenReturn(preparedStatement); + when(driverContext.getEventBus()).thenReturn(eventBus); + when(session.getContext()).thenReturn(driverContext); Row row = Mockito.mock(Row.class); when(row.getString("name")).thenReturn("concurrent_reads"); @@ -113,13 +116,13 @@ public void setUp() ResultSet resultSet = Mockito.mock(ResultSet.class); when(resultSet.all()).thenReturn(List.of(row)); when(resultSet.one()).thenReturn(row); - when(session.execute(argThat((Statement s) -> - (s instanceof SimpleStatement) && "SELECT name, value FROM system_views.settings".equals( - ((SimpleStatement) s).getQueryString() + when(session.execute(argThat((Statement s) -> + (s instanceof SimpleStatement) && "SELECT name, value FROM system_views.settings".equals( + ((SimpleStatement) s).getQuery() ) ))) .thenReturn(resultSet) - .thenThrow(NoHostAvailableException.class); + .thenThrow(NoNodeAvailableException.class); CQLSessionProvider cqlSessionProvider = Mockito.mock(CQLSessionProvider.class); when(cqlSessionProvider.get()).thenReturn(session); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java b/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java index e4283280c..784afe26c 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java @@ -22,27 +22,29 @@ import java.lang.reflect.Field; import java.math.BigInteger; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.UnknownHostException; -import java.nio.ByteBuffer; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Range; import org.junit.jupiter.api.Test; - -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.ProtocolVersion; -import com.datastax.driver.core.Token; - +import com.datastax.oss.driver.api.core.metadata.EndPoint; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.TokenMap; +import com.datastax.oss.driver.api.core.metadata.token.Token; +import com.datastax.oss.driver.internal.core.metadata.DefaultNode; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; import org.apache.cassandra.sidecar.common.response.NodeSettings; import org.apache.cassandra.sidecar.common.server.cluster.locator.Partitioners; @@ -52,8 +54,6 @@ import org.apache.cassandra.sidecar.coordination.CassandraClientTokenRingProvider; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; import org.apache.cassandra.sidecar.utils.SimpleCassandraVersion; -import org.jetbrains.annotations.NotNull; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -78,7 +78,9 @@ public class CassandraClientTokenRingProviderTest public void testPrimaryRangesOfAllInstancesByDc() { Metadata metadata = mock(Metadata.class); - when(metadata.getPartitioner()).thenReturn(Partitioners.MURMUR3.getClass().getSimpleName().toLowerCase()); + TokenMap tokenMap = mock(TokenMap.class); + when(tokenMap.getPartitionerName()).thenReturn(Partitioners.MURMUR3.name()); + when(metadata.getTokenMap()).thenReturn(Optional.of(tokenMap)); DnsResolver dnsResolver = new DnsResolver() { public String resolve(String s) @@ -91,58 +93,114 @@ public String reverseResolve(String s) return null; } }; - Set allHosts = Set.of( - mockHost("localhost1", "127.0.0.1", "-9223372036854775808", "DC1"), - mockHost("localhost2", "127.0.0.2", "-8301034833169298228", "DC1"), - mockHost("localhost3", "127.0.0.3", "-7378697629483820647", "DC1"), - mockHost("localhost4", "127.0.0.4", "-6456360425798343066", "DC1"), - mockHost("localhost5", "127.0.0.5", "-5534023222112865485", "DC1"), - mockHost("localhost6", "127.0.0.6", "-4611686018427387904", "DC1"), - mockHost("localhost7", "127.0.0.7", "-3689348814741910324", "DC1"), - mockHost("localhost8", "127.0.0.8", "-2767011611056432743", "DC1"), - mockHost("localhost9", "127.0.0.9", "-1844674407370955162", "DC1"), - mockHost("localhost10", "127.0.0.10", "-922337203685477581", "DC1"), - mockHost("localhost11", "127.0.0.11", "0", "DC1"), - mockHost("localhost12", "127.0.0.12", "922337203685477580", "DC1"), - mockHost("localhost13", "127.0.0.13", "1844674407370955161", "DC1"), - mockHost("localhost14", "127.0.0.14", "2767011611056432742", "DC1"), - mockHost("localhost15", "127.0.0.15", "3689348814741910323", "DC1"), - mockHost("localhost16", "127.0.0.16", "4611686018427387904", "DC1"), - mockHost("localhost17", "127.0.0.17", "5534023222112865484", "DC1"), - mockHost("localhost18", "127.0.0.18", "6456360425798343065", "DC1"), - mockHost("localhost19", "127.0.0.19", "7378697629483820646", "DC1"), - mockHost("localhost20", "127.0.0.20", "8301034833169298227", "DC1"), - mockHost("localhost21", "127.0.0.21", "-9223372036854775807", "DC2"), - mockHost("localhost22", "127.0.0.22", "-8301034833169298227", "DC2"), - mockHost("localhost23", "127.0.0.23", "-7378697629483820646", "DC2"), - mockHost("localhost24", "127.0.0.24", "-6456360425798343065", "DC2"), - mockHost("localhost25", "127.0.0.25", "-5534023222112865484", "DC2"), - mockHost("localhost26", "127.0.0.26", "-4611686018427387903", "DC2"), - mockHost("localhost27", "127.0.0.27", "-3689348814741910323", "DC2"), - mockHost("localhost28", "127.0.0.28", "-2767011611056432742", "DC2"), - mockHost("localhost29", "127.0.0.29", "-1844674407370955161", "DC2"), - mockHost("localhost30", "127.0.0.30", "-922337203685477580", "DC2"), - mockHost("localhost31", "127.0.0.31", "1", "DC2"), - mockHost("localhost32", "127.0.0.32", "922337203685477581", "DC2"), - mockHost("localhost33", "127.0.0.33", "1844674407370955162", "DC2"), - mockHost("localhost34", "127.0.0.34", "2767011611056432743", "DC2"), - mockHost("localhost35", "127.0.0.35", "3689348814741910324", "DC2"), - mockHost("localhost36", "127.0.0.36", "4611686018427387905", "DC2"), - mockHost("localhost37", "127.0.0.37", "5534023222112865485", "DC2"), - mockHost("localhost38", "127.0.0.38", "6456360425798343066", "DC2"), - mockHost("localhost39", "127.0.0.39", "7378697629483820647", "DC2"), - mockHost("localhost40", "127.0.0.40", "8301034833169298228", "DC2") - ); - when(metadata.getAllHosts()).thenReturn(allHosts); - - Set result = new HashSet<>(); - Map> hostByDc = allHosts.stream().collect(Collectors.groupingBy(Host::getDatacenter)); - for (Map.Entry> entry : hostByDc.entrySet()) + Map allHosts = ImmutableMap.builder() + .put(UUID.fromString("ea25ffc7-d403-402b-9cb3-587c133d70ec"), + mockHost("localhost1", "127.0.0.1", "-9223372036854775808", "DC1")) + .put(UUID.fromString("e970f7b6-6e8a-46aa-9b84-2fe651a20719"), + mockHost("localhost2", "127.0.0.2", "-8301034833169298228", "DC1")) + .put(UUID.fromString("de8e64f8-2b46-49bb-b67a-f73492ad03de"), + mockHost("localhost3", "127.0.0.3", "-7378697629483820647", "DC1")) + .put(UUID.fromString("c1bc2650-fb11-4cf5-ac19-f70a9b6d1405"), + mockHost("localhost4", "127.0.0.4", "-6456360425798343066", "DC1")) + .put(UUID.fromString("e71e12a9-602e-47c5-a115-164162987245"), + mockHost("localhost5", "127.0.0.5", "-5534023222112865485", "DC1")) + .put(UUID.fromString("f3cf243d-ecd2-43da-8422-38de850501ad"), + mockHost("localhost6", "127.0.0.6", "-4611686018427387904", "DC1")) + .put(UUID.fromString("4f0b650c-69c0-4441-a6f7-68da8ff074bd"), + mockHost("localhost7", "127.0.0.7", "-3689348814741910324", "DC1")) + .put(UUID.fromString("395ca8fc-e964-41c1-b338-c5ed3efda1b7"), + mockHost("localhost8", "127.0.0.8", "-2767011611056432743", "DC1")) + .put(UUID.fromString("3ef8fc97-f5f9-4323-8038-4d5584ba3785"), + mockHost("localhost9", "127.0.0.9", "-1844674407370955162", "DC1")) + .put(UUID.fromString("e862d1f1-3ec3-40f1-b4ba-622ae0da26bf"), + mockHost("localhost10", "127.0.0.10", "-922337203685477581", "DC1")) + .put(UUID.fromString("60796ffd-a023-477b-8a08-d81d2d42d327"), + mockHost("localhost11", "127.0.0.11", "0", "DC1")) + .put(UUID.fromString("57fd2f22-14fb-457f-9545-ab93d5d608a4"), + mockHost("localhost12", "127.0.0.12", "922337203685477580", "DC1")) + .put(UUID.fromString("a90bae6a-7ba8-4c32-8570-54570de720e4"), + mockHost("localhost13", "127.0.0.13", "1844674407370955161", "DC1")) + .put(UUID.fromString("fddc822f-fbad-4050-916b-1021a4c27d2c"), + mockHost("localhost14", "127.0.0.14", "2767011611056432742", "DC1")) + .put(UUID.fromString("df1bdb81-5472-432f-8340-41df4fff3d5d"), + mockHost("localhost15", "127.0.0.15", "3689348814741910323", "DC1")) + .put(UUID.fromString("9148875c-1f6b-4310-82e0-fc369f8857b7"), + mockHost("localhost16", "127.0.0.16", "4611686018427387904", "DC1")) + .put(UUID.fromString("69893624-32dd-4940-b929-45c619873823"), + mockHost("localhost17", "127.0.0.17", "5534023222112865484", "DC1")) + .put(UUID.fromString("3ba1d0bc-e333-47da-b2f1-27ab248b6ddf"), + mockHost("localhost18", "127.0.0.18", "6456360425798343065", "DC1")) + .put(UUID.fromString("3c4c4342-52bb-49f2-9e5b-2140cd1e5783"), + mockHost("localhost19", "127.0.0.19", "7378697629483820646", "DC1")) + .put(UUID.fromString("178af717-ddf3-4e04-8828-a2b7ee65c6ac"), + mockHost("localhost20", "127.0.0.20", "8301034833169298227", "DC1")) + .put(UUID.fromString("9bb8e91a-bd8c-4322-8784-bc30a3bcc884"), + mockHost("localhost21", "127.0.0.21", "-9223372036854775807", "DC2")) + .put(UUID.fromString("a2a7373c-4f65-4604-90b0-9af4b77dfeca"), + mockHost("localhost22", "127.0.0.22", "-8301034833169298227", "DC2")) + .put(UUID.fromString("81765e01-2e57-4432-b7a7-1832493216ef"), + mockHost("localhost23", "127.0.0.23", "-7378697629483820646", "DC2")) + .put(UUID.fromString("556c9144-5545-4962-942d-336cc7d297ea"), + mockHost("localhost24", "127.0.0.24", "-6456360425798343065", "DC2")) + .put(UUID.fromString("1ca09b9a-3609-48c5-978a-5d735b6e42bf"), + mockHost("localhost25", "127.0.0.25", "-5534023222112865484", "DC2")) + .put(UUID.fromString("0232a64c-f470-4bcd-8e19-9c3a04cb9eec"), + mockHost("localhost26", "127.0.0.26", "-4611686018427387903", "DC2")) + .put(UUID.fromString("4cd0c7c5-cd2c-4f3e-be73-d118769133e5"), + mockHost("localhost27", "127.0.0.27", "-3689348814741910323", "DC2")) + .put(UUID.fromString("a79f23b3-f1f3-46d1-9756-55382b91d61a"), + mockHost("localhost28", "127.0.0.28", "-2767011611056432742", "DC2")) + .put(UUID.fromString("75b4575d-1e99-4a6e-ab5a-9a9e160b25ba"), + mockHost("localhost29", "127.0.0.29", "-1844674407370955161", "DC2")) + .put(UUID.fromString("26a2b85d-8c78-4668-8d60-941d65fec129"), + mockHost("localhost30", "127.0.0.30", "-922337203685477580", "DC2")) + .put(UUID.fromString("58c67a76-3b48-4199-a2cf-e2debaaffa3e"), + mockHost("localhost31", "127.0.0.31", "1", "DC2")) + .put(UUID.fromString("b830f9b7-6000-4e93-8b10-ed7c60b7552b"), + mockHost("localhost32", "127.0.0.32", "922337203685477581", "DC2")) + .put(UUID.fromString("a83081ae-2866-4486-828a-196e792f096e"), + mockHost("localhost33", "127.0.0.33", "1844674407370955162", "DC2")) + .put(UUID.fromString("674a1c95-901f-4345-a4e4-702c18421c7e"), + mockHost("localhost34", "127.0.0.34", "2767011611056432743", "DC2")) + .put(UUID.fromString("a242e66d-4bd5-45aa-bd0e-acba91db20e7"), + mockHost("localhost35", "127.0.0.35", "3689348814741910324", "DC2")) + .put(UUID.fromString("7235e1bc-448a-41d1-8e3d-a2f81c8895ea"), + mockHost("localhost36", "127.0.0.36", "4611686018427387905", "DC2")) + .put(UUID.fromString("cb490c16-e9ab-480b-941b-a27a934ffdb1"), + mockHost("localhost37", "127.0.0.37", "5534023222112865485", "DC2")) + .put(UUID.fromString("dd629f81-2798-4e58-b2ec-857ce0e02aa6"), + mockHost("localhost38", "127.0.0.38", "6456360425798343066", "DC2")) + .put(UUID.fromString("8681e804-5d5c-4a66-8575-c62f161f7a80"), + mockHost("localhost38", "127.0.0.38", "6456360425798343066", "DC2")) + .put(UUID.fromString("0fde1da0-ce7c-4ffd-be47-9fe7fd354da3"), + mockHost("localhost39", "127.0.0.39", "7378697629483820647", "DC2")) + .put(UUID.fromString("2fbbc34e-6ad0-4d17-8d3c-ae48d907c427"), + mockHost("localhost40", "127.0.0.40", "8301034833169298228", "DC2")) + .build(); + when(metadata.getNodes()).thenReturn(allHosts); + + Set allTokenRange = new HashSet<>(); + Map> nodeTokens = allHosts.values().stream() + .map(n -> (DefaultNode) n) + .collect(Collectors.toMap(n -> n, n -> n.getRawTokens().stream() + .map(MockToken::new) + .collect(Collectors.toSet()))); + Map> hostByDc = allHosts.values().stream().collect(Collectors.groupingBy(Node::getDatacenter)); + for (Map.Entry> entry : hostByDc.entrySet()) { String dc = entry.getKey(); - List tokens = hostByDc.get(dc).stream().map(Host::getTokens).flatMap(Collection::stream) + List tokens = hostByDc.get(dc).stream().map(n -> ((DefaultNode) n).getRawTokens()).flatMap(Collection::stream) + .map(MockToken::new) .sorted(((Comparator) Comparable::compareTo).reversed()) .collect(Collectors.toList()); + for (Node node : entry.getValue()) + { + DefaultNode defaultNode = (DefaultNode) node; + for (String rawToken : defaultNode.getRawTokens()) + { + nodeTokens.put(node, Set.of(new MockToken(rawToken))); + } + } for (int i = 0; i < tokens.size(); i++) { Token end = tokens.get(i); @@ -155,7 +213,7 @@ public String reverseResolve(String s) { // Handle the special case where prev() would fail for MIN_VALUE MockToken mockEnd = (MockToken) end; - if (mockEnd.token == Long.MIN_VALUE) + if (mockEnd.getValue() == Long.MIN_VALUE) { // For MIN_VALUE, wrap around to MAX_VALUE start = new MockToken(Long.MAX_VALUE); @@ -168,10 +226,14 @@ public String reverseResolve(String s) // Create TokenRange with reflection-based mocking to handle final field TokenRange tokenRange = createMockTokenRange(start, end); - result.add(tokenRange); + allTokenRange.add(tokenRange); } } - when(metadata.getTokenRanges()).thenAnswer(invocation -> result); + when(metadata.getTokenMap().get().getTokenRanges()).thenAnswer(invocation -> allTokenRange); + when(metadata.getTokenMap().get().getTokens(any())).thenAnswer(invocation -> { + Node n = invocation.getArgument(0); + return nodeTokens.get(n); + }); Map>> tokens = CassandraClientTokenRingProvider.assignedRangesOfAllInstancesByDc(dnsResolver, metadata); assertFalse(tokens.isEmpty()); @@ -208,22 +270,29 @@ public String reverseResolve(String s) .compareTo(BigInteger.ONE) > 0)); } - public static Host mockHost(String node, String ip, String token, String dc) + public static DefaultNode mockHost(String node, String ip, String token, String dc) { - Host host = mock(Host.class, RETURNS_DEEP_STUBS); - when(host.getTokens()).thenAnswer(invocation -> Set.of(new MockToken(token))); + DefaultNode host = mock(DefaultNode.class, RETURNS_DEEP_STUBS); + when(host.getRawTokens()).thenAnswer(invocation -> Set.of(token)); when(host.getDatacenter()).thenReturn(dc); - InetAddress addressMock = mock(InetAddress.class); - when(addressMock.getHostAddress()).thenReturn(ip); - when(addressMock.getHostName()).thenReturn(node); - when(host.getAddress()).thenReturn(addressMock); + EndPoint endpoint = mock(EndPoint.class); + InetAddress inetAddress = mock(InetAddress.class); + when(inetAddress.getHostAddress()).thenReturn(ip); + when(inetAddress.getHostName()).thenReturn(node); + InetSocketAddress socketAddress = mock(InetSocketAddress.class); + when(socketAddress.getHostName()).thenReturn(node); + when(socketAddress.getAddress()).thenReturn(inetAddress); + when(socketAddress.getPort()).thenReturn(9042); + when(endpoint.resolve()).thenReturn(socketAddress); + when(host.getEndPoint()).thenReturn(endpoint); + when(host.toString()).thenReturn(node); return host; } @Test public void testLocalInstances() { - Set localInstances = tokenRingProvider.localInstances(); + Set localInstances = tokenRingProvider.localInstances(); assertEquals(3, localInstances.size()); } @@ -237,9 +306,9 @@ private static TokenRange createMockTokenRange(Token start, Token end) { // Convert Datastax tokens to sidecar tokens org.apache.cassandra.sidecar.common.server.cluster.locator.Token sidecarStart = - org.apache.cassandra.sidecar.common.server.cluster.locator.Token.from(((MockToken) start).token); + org.apache.cassandra.sidecar.common.server.cluster.locator.Token.from(((MockToken) start).getValue()); org.apache.cassandra.sidecar.common.server.cluster.locator.Token sidecarEnd = - org.apache.cassandra.sidecar.common.server.cluster.locator.Token.from(((MockToken) end).token); + org.apache.cassandra.sidecar.common.server.cluster.locator.Token.from(((MockToken) end).getValue()); // Create mock sidecar tokens with proper behavior org.apache.cassandra.sidecar.common.server.cluster.locator.Token mockSidecarStart = @@ -307,7 +376,6 @@ public static DnsResolver mockDnsResolver() private InstancesMetadata mockInstancesMetadata() { InstancesMetadata instancesMetadata = mock(InstancesMetadata.class); - InstanceMetadata instance1 = getMockInstanceMetaData(101000101, "localhost", getMetadata()); InstanceMetadata instance2 = getMockInstanceMetaData(101000201, "localhost2", getMetadata()); InstanceMetadata instance3 = getMockInstanceMetaData(101000301, "localhost3", getMetadata()); @@ -318,13 +386,24 @@ private InstancesMetadata mockInstancesMetadata() public static Metadata getMetadata() { Metadata metadata = mock(Metadata.class); - when(metadata.getPartitioner()).thenReturn(Partitioners.MURMUR3.getClass().getSimpleName().toLowerCase()); - Set allHosts = Set.of( - mockHost("localhost", "127.0.0.1", "-9223372036854775808", "DC1"), - mockHost("localhost2", "127.0.0.2", "-8301034833169298228", "DC1"), - mockHost("localhost3", "127.0.0.3", "-7378697629483820647", "DC1") + TokenMap tokenMap = mock(TokenMap.class); + when(tokenMap.getPartitionerName()).thenReturn(Partitioners.MURMUR3.name()); + when(metadata.getTokenMap()).thenReturn(Optional.of(tokenMap)); + Map allHosts = Map.of( + UUID.fromString("7091a44c-efc2-44c7-9834-12c2fa090d07"), mockHost("localhost", "127.0.0.1", "-9223372036854775808", "DC1"), + UUID.fromString("cfba7f8b-0e4c-441f-91fb-6b05c2bc917a"), mockHost("localhost2", "127.0.0.2", "-8301034833169298228", "DC1"), + UUID.fromString("3eeac2bd-b334-4b3d-a5a4-877d52c4e527"), mockHost("localhost3", "127.0.0.3", "-7378697629483820647", "DC1") ); - when(metadata.getAllHosts()).thenReturn(allHosts); + Map> nodeTokens = allHosts.values().stream() + .map(n -> (DefaultNode) n) + .collect(Collectors.toMap(n -> n, n -> n.getRawTokens().stream() + .map(MockToken::new) + .collect(Collectors.toSet()))); + when(metadata.getNodes()).thenReturn(allHosts); + when(metadata.getTokenMap().get().getTokens(any())).thenAnswer(invocation -> { + Node n = invocation.getArgument(0); + return nodeTokens.get(n); + }); return metadata; } @@ -352,72 +431,31 @@ private InstanceMetadataFetcher mockInstanceMetadataFetcher() return fetcher; } - private static class MockToken extends Token + private static class MockToken extends Murmur3Token { - final Long token; - private MockToken(String token) { - this(Long.parseLong(token)); + super(Long.parseLong(token)); } private MockToken(long token) { - this.token = token; - } - - @Override - public DataType getType() - { - return DataType.bigint(); - } - - @Override - public Object getValue() - { - return token; - } - - @Override - public ByteBuffer serialize(ProtocolVersion protocolVersion) - { - return null; - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MockToken mockToken = (MockToken) o; - return Objects.equals(token, mockToken.token); - } - - @Override - public int hashCode() - { - return Objects.hash(token); - } - - @Override - public int compareTo(@NotNull Token o) - { - return ((MockToken) o).token.compareTo(token); + super(token); } public MockToken prev() { - if (token == Long.MIN_VALUE) + if (getValue() == Long.MIN_VALUE) { throw new IllegalStateException(); } - return new MockToken(token - 1); + return new MockToken(getValue() - 1); } public String toString() { return "MockToken{" + - "token=" + token + + "token=" + getValue() + '}'; } } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProviderTests.java b/server/src/test/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProviderTests.java index ea208db7c..000672bfd 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProviderTests.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProviderTests.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -35,12 +36,16 @@ import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.EndPoint; -import com.datastax.driver.core.Host; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.Token; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.metadata.EndPoint; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.Node; +import com.datastax.oss.driver.api.core.metadata.TokenMap; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.token.Token; +import com.datastax.oss.driver.internal.core.metadata.DefaultNode; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3TokenRange; import org.apache.cassandra.sidecar.client.SidecarInstance; import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; @@ -99,15 +104,30 @@ public void testInnerDcTokenAdjacentBuddyProvider() when(serviceConfiguration.port()).thenReturn(9043); Metadata metadata = mock(Metadata.class); - List keyspaces = List.of(mockKeyspace("ks1", Map.of("DC1", "3", "DC2", "3")), - mockKeyspace("ks2", Map.of("DC2", "5")), - mockKeyspace("ks3", Map.of("DC1", "3"))); + TokenMap tokenMap = mock(TokenMap.class); + Map keyspaces = Map.of( + CqlIdentifier.fromCql("ks1"), mockKeyspace("ks1", Map.of("DC1", "3", "DC2", "3")), + CqlIdentifier.fromCql("ks2"), mockKeyspace("ks2", Map.of("DC2", "5")), + CqlIdentifier.fromCql("ks3"), mockKeyspace("ks3", Map.of("DC1", "3"))); when(metadata.getKeyspaces()).thenReturn(keyspaces); - Set allHosts = IntStream.range(0, INSTANCES.size()) + Set allHosts = IntStream.range(0, INSTANCES.size()) .mapToObj(i -> List.of(mockHost("dc1-" + INSTANCES.get(i), TOKENS.get(i), "DC1"), mockHost("dc2-" + INSTANCES.get(i), TOKENS.get(i).add(BigInteger.ONE), "DC2") )).flatMap(Collection::stream) .collect(Collectors.toSet()); + Map> nodeTokens = allHosts.stream() + .map(n -> (DefaultNode) n) + .collect(Collectors.toMap(n -> n, n -> n.getRawTokens().stream() + .map(t -> new Murmur3Token(Long.parseLong(t))) + .collect(Collectors.toSet()))); + when(metadata.getTokenMap()).thenReturn(Optional.of(tokenMap)); + when(tokenMap.getTokenRanges()).thenReturn(IntStream.range(0, INSTANCES.size()) + .mapToObj(i -> mockTokenRange(TOKENS.get(i), TOKENS.get(i).add(BigInteger.ONE))) + .collect(Collectors.toSet())); + when(metadata.getTokenMap().get().getTokens(any())).thenAnswer(invocation -> { + Node n = invocation.getArgument(0); + return nodeTokens.get(n); + }); int numHosts = INSTANCES.size() / 4; when(metadataFetcher.callOnFirstAvailableInstance(any())).thenReturn(metadata); @@ -123,7 +143,7 @@ public void testInnerDcTokenAdjacentBuddyProvider() when(metadataFetcher.allLocalInstances()).thenReturn(localInstances); CassandraClientTokenRingProvider cachedLocalTokenRanges = mock(CassandraClientTokenRingProvider.class); - Set localHosts = allHosts.stream().filter(host -> DRIVER_UTILS.getSocketAddress(host) + Set localHosts = allHosts.stream().filter(host -> DRIVER_UTILS.getSocketAddress(host) .getAddress() .getHostName() .startsWith("dc1-host" + hostId + "-")) @@ -165,7 +185,7 @@ public String reverseResolve(String address) @Test public void testAdjacentHosts() { - List> allHosts = IntStream.range(0, TOKENS.size()) + List> allHosts = IntStream.range(0, TOKENS.size()) .mapToObj(idx -> { BigInteger token = tokenAt(idx); return Pair.of(mockHost(INSTANCES.get(idx), token), token); @@ -178,13 +198,13 @@ public void testAdjacentHosts() String localhost = INSTANCES.get(i); BigInteger token = tokenAt(i); test(localhost, token, allHosts, 1, tokenAt(i + 1)); - Set adjacent = InnerDcTokenAdjacentPeerProvider.adjacentHosts(DRIVER_UTILS, + Set adjacent = InnerDcTokenAdjacentPeerProvider.adjacentHosts(DRIVER_UTILS, (host) -> isLocal(localhost, host), token, allHosts, 1); assertEquals(1, adjacent.size()); - String adjacentStr = adjacent.stream().findFirst().map(Host::toString).orElseThrow(); + String adjacentStr = adjacent.stream().findFirst().map(Node::toString).orElseThrow(); assertFalse(adjacentHosts.contains(adjacentStr)); adjacentHosts.add(adjacentStr); } @@ -215,7 +235,7 @@ public void testRfGreaterThanAvailableHosts() "local1-i3", "local2-i3", "local3-i3", "local1-i4", "local2-i4", "local3-i4"); BigInteger token = new BigInteger(tokens.stream().findFirst().orElseThrow()); - List> sortedLocalDcHosts = IntStream.range(0, tokens.size()) + List> sortedLocalDcHosts = IntStream.range(0, tokens.size()) .mapToObj(i -> { BigInteger t = new BigInteger(tokens.get(i)); return Pair.of(mockHost(hosts.get(i), t), t); @@ -227,7 +247,7 @@ public void testRfGreaterThanAvailableHosts() token, sortedLocalDcHosts, quorum) - .stream().map(Host::toString) + .stream().map(Node::toString) .collect(Collectors.toSet()); } @@ -236,14 +256,14 @@ private static BigInteger tokenAt(int idx) return TOKENS.get(idx % TOKENS.size()); } - private static void test(String localhost, BigInteger token, List> allHosts, int quorum, BigInteger... expected) + private static void test(String localhost, BigInteger token, List> allHosts, int quorum, BigInteger... expected) { Set result = InnerDcTokenAdjacentPeerProvider.adjacentHosts(DRIVER_UTILS, (host) -> isLocal(localhost, host), token, allHosts, quorum) - .stream().map(Host::toString) + .stream().map(Node::toString) .collect(Collectors.toSet()); assertFalse(result.contains(token.toString())); for (BigInteger bi : expected) @@ -253,7 +273,7 @@ private static void test(String localhost, BigInteger token, List replication) { KeyspaceMetadata keyspaceMetadata = mock(KeyspaceMetadata.class); - when(keyspaceMetadata.getName()).thenReturn(name); + when(keyspaceMetadata.getName()).thenReturn(CqlIdentifier.fromInternal(name)); when(keyspaceMetadata.getReplication()).thenReturn(replication); return keyspaceMetadata; } @@ -284,14 +304,14 @@ private static InstanceMetadata mockInstanceMetadata(int id, String host, Metada return instanceMetadata; } - private static Host mockHost(String hostname, BigInteger token) + private static Node mockHost(String hostname, BigInteger token) { return mockHost(hostname, token, "DC1"); } - private static Host mockHost(String hostname, BigInteger token, String dc) + private static DefaultNode mockHost(String hostname, BigInteger token, String dc) { - Host host = mock(Host.class); + DefaultNode host = mock(DefaultNode.class); InetAddress addr = mock(InetAddress.class); EndPoint mockEndpoint = mock(EndPoint.class); InetSocketAddress mockInetSocketAddress = mock(InetSocketAddress.class); @@ -302,10 +322,12 @@ private static Host mockHost(String hostname, BigInteger token, String dc) when(mockInetSocketAddress.getAddress()).thenReturn(addr); when(host.toString()).thenReturn(token.toString()); when(host.getDatacenter()).thenReturn(dc); - Token t = mock(Token.class); - when(t.getType()).thenReturn(DataType.bigint()); - when(t.getValue()).thenReturn(token.longValue()); - when(host.getTokens()).thenReturn(Set.of(t)); + when(host.getRawTokens()).thenReturn(Set.of(token.toString())); return host; } + + private com.datastax.oss.driver.api.core.metadata.token.TokenRange mockTokenRange(BigInteger start, BigInteger end) + { + return new Murmur3TokenRange(new Murmur3Token(start.longValue()), new Murmur3Token(end.longValue())); + } } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/datahub/IdentifiersProviderTest.java b/server/src/test/java/org/apache/cassandra/sidecar/datahub/IdentifiersProviderTest.java index 949e79f43..bccad5d22 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/datahub/IdentifiersProviderTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/datahub/IdentifiersProviderTest.java @@ -18,12 +18,13 @@ package org.apache.cassandra.sidecar.datahub; -import java.util.Collections; +import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import org.jetbrains.annotations.NotNull; import static org.assertj.core.api.Assertions.assertThat; @@ -75,17 +76,19 @@ void testUrns() { KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class); TableMetadata table = mock(TableMetadata.class); - when(keyspace.getName()).thenReturn("keyspace"); - when(table.getName()).thenReturn("table"); - when(keyspace.getTables()).thenReturn(Collections.singleton(table)); - when(table.getKeyspace()).thenReturn(keyspace); + CqlIdentifier keyspaceIdentifier = CqlIdentifier.fromCql("keyspace1"); + CqlIdentifier tableIdentifier = CqlIdentifier.fromCql("table1"); + when(keyspace.getName()).thenReturn(keyspaceIdentifier); + when(table.getName()).thenReturn(tableIdentifier); + when(keyspace.getTables()).thenReturn(Map.of(tableIdentifier, table)); + when(table.getKeyspace()).thenReturn(keyspaceIdentifier); String urnDataPlatform = "urn:li:dataPlatform:cassandra"; String urnDataPlatformInstance = "urn:li:dataPlatformInstance:" + "(urn:li:dataPlatform:cassandra,ace3ba6b-49b2-3dd5-955a-1de13730188b)"; - String urnContainer = "urn:li:container:ace3ba6b-49b2-3dd5-955a-1de13730188b_keyspace"; + String urnContainer = "urn:li:container:ace3ba6b-49b2-3dd5-955a-1de13730188b_keyspace1"; String urnDataset = "urn:li:dataset:" + - "(urn:li:dataPlatform:cassandra,ace3ba6b-49b2-3dd5-955a-1de13730188b.keyspace.table,PROD)"; + "(urn:li:dataPlatform:cassandra,ace3ba6b-49b2-3dd5-955a-1de13730188b.keyspace1.table1,PROD)"; assertThat(IDENTIFIERS.urnDataPlatform()).isEqualTo(urnDataPlatform); assertThat(IDENTIFIERS.urnDataPlatformInstance()).isEqualTo(urnDataPlatformInstance); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/datahub/SchemaReporterTest.java b/server/src/test/java/org/apache/cassandra/sidecar/datahub/SchemaReporterTest.java index 387aecdc5..27fa4fd79 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/datahub/SchemaReporterTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/datahub/SchemaReporterTest.java @@ -21,20 +21,29 @@ import java.io.IOException; import java.util.Collections; +import java.util.Map; + import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.codahale.metrics.SharedMetricRegistries; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.ColumnMetadata; -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.TableMetadata; -import com.datastax.driver.core.TableOptionsMetadata; -import com.datastax.driver.core.UserType; +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.core.metadata.schema.ClusteringOrder; +import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; +import com.datastax.oss.driver.api.core.type.UserDefinedType; +import com.datastax.oss.driver.internal.core.type.DefaultListType; +import com.datastax.oss.driver.internal.core.type.DefaultMapType; +import com.datastax.oss.driver.internal.core.type.PrimitiveType; +import com.datastax.oss.driver.internal.core.type.UserDefinedTypeBuilder; +import com.datastax.oss.protocol.internal.ProtocolConstants; import org.apache.cassandra.sidecar.common.server.utils.IOUtils; import org.apache.cassandra.sidecar.metrics.MetricRegistryFactory; import org.apache.cassandra.sidecar.metrics.SidecarMetrics; @@ -42,6 +51,7 @@ import org.apache.cassandra.sidecar.metrics.server.SchemaReportingMetrics; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -74,7 +84,7 @@ void afterEach() void testEmptyCluster() throws IOException { Metadata metadata = mock(Metadata.class); - when(metadata.getKeyspaces()).thenReturn(Collections.emptyList()); + when(metadata.getKeyspaces()).thenReturn(Collections.emptyMap()); JsonEmitter emitter = new JsonEmitter(); new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processRequested(metadata); @@ -98,10 +108,11 @@ void testEmptyCluster() throws IOException void testEmptyKeyspace() throws IOException { Metadata metadata = mock(Metadata.class); + CqlIdentifier keyspaceIdentifier = CqlIdentifier.fromCql("sample_keyspace"); KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class); - when(metadata.getKeyspaces()).thenReturn(Collections.singletonList(keyspace)); - when(keyspace.getName()).thenReturn("sample_keyspace"); - when(keyspace.getTables()).thenReturn(Collections.emptyList()); + when(metadata.getKeyspaces()).thenReturn(Map.of(keyspaceIdentifier, keyspace)); + when(keyspace.getName()).thenReturn(keyspaceIdentifier); + when(keyspace.getTables()).thenReturn(Collections.emptyMap()); JsonEmitter emitter = new JsonEmitter(); new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processRequested(metadata); @@ -127,15 +138,15 @@ void testEmptyTable() throws IOException Metadata metadata = mock(Metadata.class); KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class); TableMetadata table = mock(TableMetadata.class); - TableOptionsMetadata options = mock(TableOptionsMetadata.class); - when(metadata.getKeyspaces()).thenReturn(Collections.singletonList(keyspace)); - when(keyspace.getName()).thenReturn("sample_keyspace"); - when(keyspace.getTables()).thenReturn(Collections.singletonList(table)); - when(table.getKeyspace()).thenReturn(keyspace); - when(table.getName()).thenReturn("sample_table"); - when(table.getOptions()).thenReturn(options); - when(table.exportAsString()).thenReturn("CREATE TABLE sample_keyspace.sample_table (...);"); - when(options.getComment()).thenReturn("table comment"); + CqlIdentifier keyspaceId = CqlIdentifier.fromCql("sample_keyspace"); + when(metadata.getKeyspaces()).thenReturn(Map.of(keyspaceId, keyspace)); + when(keyspace.getName()).thenReturn(keyspaceId); + CqlIdentifier tableId = CqlIdentifier.fromCql("sample_table"); + when(keyspace.getTables()).thenReturn(Map.of(tableId, table)); + when(table.getKeyspace()).thenReturn(keyspaceId); + when(table.getName()).thenReturn(tableId); + when(table.getOptions()).thenReturn(Map.of(CqlIdentifier.fromInternal("comment"), "table comment")); + when(table.describeWithChildren(anyBoolean())).thenReturn("CREATE TABLE sample_keyspace.sample_table (...);"); JsonEmitter emitter = new JsonEmitter(); new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processRequested(metadata); @@ -158,11 +169,10 @@ void testEmptyTable() throws IOException @Test void testPrimitiveTypes() throws IOException { - Cluster cluster = mock(Cluster.class); + CqlSession session = mock(CqlSession.class); Metadata metadata = mock(Metadata.class); KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class); TableMetadata table = mock(TableMetadata.class); - TableOptionsMetadata options = mock(TableOptionsMetadata.class); ColumnMetadata pk1 = mock(ColumnMetadata.class); ColumnMetadata pk2 = mock(ColumnMetadata.class); ColumnMetadata ck1 = mock(ColumnMetadata.class); @@ -175,57 +185,75 @@ void testPrimitiveTypes() throws IOException ColumnMetadata c6 = mock(ColumnMetadata.class); ColumnMetadata c7 = mock(ColumnMetadata.class); ColumnMetadata c8 = mock(ColumnMetadata.class); - when(cluster.getMetadata()).thenReturn(metadata); - when(metadata.getKeyspaces()).thenReturn(Collections.singletonList(keyspace)); - when(keyspace.getName()).thenReturn("sample_keyspace"); - when(keyspace.getTables()).thenReturn(ImmutableList.of(table)); - when(table.getKeyspace()).thenReturn(keyspace); - when(table.getName()).thenReturn("sample_table"); - when(table.getOptions()).thenReturn(options); - when(table.getColumns()).thenReturn(ImmutableList.of(pk1, pk2, ck1, ck2, c1, c2, c3, c4, c5, c6, c7, c8)); + when(session.getMetadata()).thenReturn(metadata); + CqlIdentifier keyspaceId = CqlIdentifier.fromCql("sample_keyspace"); + when(metadata.getKeyspaces()).thenReturn(Map.of(keyspaceId, keyspace)); + when(keyspace.getName()).thenReturn(keyspaceId); + CqlIdentifier tableId = CqlIdentifier.fromCql("sample_table"); + when(keyspace.getTables()).thenReturn(Map.of(tableId, table)); + when(table.getKeyspace()).thenReturn(keyspaceId); + when(table.getName()).thenReturn(tableId); + when(table.getOptions()).thenReturn(Collections.emptyMap()); + when(table.getColumns()).thenReturn(ImmutableMap.builder() + .put(CqlIdentifier.fromInternal("pk1"), pk1) + .put(CqlIdentifier.fromInternal("pk2"), pk2) + .put(CqlIdentifier.fromInternal("ck1"), ck1) + .put(CqlIdentifier.fromInternal("ck2"), ck2) + .put(CqlIdentifier.fromInternal("c1"), c1) + .put(CqlIdentifier.fromInternal("c2"), c2) + .put(CqlIdentifier.fromInternal("c3"), c3) + .put(CqlIdentifier.fromInternal("c4"), c4) + .put(CqlIdentifier.fromInternal("c5"), c5) + .put(CqlIdentifier.fromInternal("c6"), c6) + .put(CqlIdentifier.fromInternal("c7"), c7) + .put(CqlIdentifier.fromInternal("c8"), c8) + .build()); when(table.getPartitionKey()).thenReturn(ImmutableList.of(pk1, pk2)); - when(table.getClusteringColumns()).thenReturn(ImmutableList.of(ck1, ck2)); - when(table.exportAsString()).thenReturn("CREATE TABLE sample_keyspace.sample_table (...);"); - when(options.getComment()).thenReturn("table comment"); - when(pk1.getParent()).thenReturn(table); - when(pk1.getName()).thenReturn("pk1"); - when(pk1.getType()).thenReturn(DataType.cint()); - when(pk2.getParent()).thenReturn(table); - when(pk2.getName()).thenReturn("pk2"); - when(pk2.getType()).thenReturn(DataType.cfloat()); - when(ck1.getParent()).thenReturn(table); - when(ck1.getName()).thenReturn("ck1"); - when(ck1.getType()).thenReturn(DataType.varint()); - when(ck2.getParent()).thenReturn(table); - when(ck2.getName()).thenReturn("ck2"); - when(ck2.getType()).thenReturn(DataType.decimal()); - when(c1.getParent()).thenReturn(table); - when(c1.getName()).thenReturn("c1"); - when(c1.getType()).thenReturn(DataType.cboolean()); - when(c2.getParent()).thenReturn(table); - when(c2.getName()).thenReturn("c2"); - when(c2.getType()).thenReturn(DataType.date()); - when(c3.getParent()).thenReturn(table); - when(c3.getName()).thenReturn("c3"); - when(c3.getType()).thenReturn(DataType.time()); - when(c4.getParent()).thenReturn(table); - when(c4.getName()).thenReturn("c4"); - when(c4.getType()).thenReturn(DataType.ascii()); - when(c5.getParent()).thenReturn(table); - when(c5.getName()).thenReturn("c6"); - when(c5.getType()).thenReturn(DataType.varchar()); - when(c6.getParent()).thenReturn(table); - when(c6.getName()).thenReturn("c6"); - when(c6.getType()).thenReturn(DataType.blob()); - when(c7.getParent()).thenReturn(table); - when(c7.getName()).thenReturn("c7"); - when(c7.getType()).thenReturn(DataType.list(DataType.uuid(), true)); - when(c8.getParent()).thenReturn(table); - when(c8.getName()).thenReturn("c8"); - when(c8.getType()).thenReturn(DataType.map(DataType.timestamp(), DataType.inet(), false)); + when(table.getClusteringColumns()).thenReturn(Map.of( + ck1, ClusteringOrder.ASC, + ck2, ClusteringOrder.ASC)); + when(table.describeWithChildren(anyBoolean())).thenReturn("CREATE TABLE sample_keyspace.sample_table (...);"); + when(table.getOptions()).thenReturn(Map.of(CqlIdentifier.fromInternal("comment"), "table comment")); + when(pk1.getParent()).thenReturn(tableId); + when(pk1.getName()).thenReturn(CqlIdentifier.fromInternal("pk1")); + when(pk1.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.INT)); + when(pk2.getParent()).thenReturn(tableId); + when(pk2.getName()).thenReturn(CqlIdentifier.fromInternal("pk2")); + when(pk2.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.FLOAT)); + when(ck1.getParent()).thenReturn(tableId); + when(ck1.getName()).thenReturn(CqlIdentifier.fromInternal("ck1")); + when(ck1.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.VARINT)); + when(ck2.getParent()).thenReturn(tableId); + when(ck2.getName()).thenReturn(CqlIdentifier.fromInternal("ck2")); + when(ck2.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.DECIMAL)); + when(c1.getParent()).thenReturn(tableId); + when(c1.getName()).thenReturn(CqlIdentifier.fromInternal("c1")); + when(c1.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.BOOLEAN)); + when(c2.getParent()).thenReturn(tableId); + when(c2.getName()).thenReturn(CqlIdentifier.fromInternal("c2")); + when(c2.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.DATE)); + when(c3.getParent()).thenReturn(tableId); + when(c3.getName()).thenReturn(CqlIdentifier.fromInternal("c3")); + when(c3.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.TIME)); + when(c4.getParent()).thenReturn(tableId); + when(c4.getName()).thenReturn(CqlIdentifier.fromInternal("c4")); + when(c4.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.ASCII)); + when(c5.getParent()).thenReturn(tableId); + when(c5.getName()).thenReturn(CqlIdentifier.fromInternal("c6")); + when(c5.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.VARCHAR)); + when(c6.getParent()).thenReturn(tableId); + when(c6.getName()).thenReturn(CqlIdentifier.fromInternal("c6")); + when(c6.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.BLOB)); + when(c7.getParent()).thenReturn(tableId); + when(c7.getName()).thenReturn(CqlIdentifier.fromInternal("c7")); + when(c7.getType()).thenReturn(new DefaultListType(new PrimitiveType(ProtocolConstants.DataType.UUID), false)); + when(c8.getParent()).thenReturn(tableId); + when(c8.getName()).thenReturn(CqlIdentifier.fromInternal("c8")); + when(c8.getType()).thenReturn(new DefaultMapType(new PrimitiveType(ProtocolConstants.DataType.TIMESTAMP), + new PrimitiveType(ProtocolConstants.DataType.INET), false)); JsonEmitter emitter = new JsonEmitter(); - new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processScheduled(cluster); + new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processScheduled(session); String actual = emitter.content(); String expected = IOUtils.readFully("/datahub/primitive_types.json"); @@ -237,7 +265,7 @@ void testPrimitiveTypes() throws IOException assertThat(metrics.finishedSuccess.metric.getValue()).isOne(); // * one execution resulted in success assertThat(metrics.finishedFailure.metric.getValue()).isZero(); // * zero executions resulted in failure assertThat(metrics.sizeAspects.metric.getCount()).isOne(); // * single number of aspects, - assertThat(metrics.sizeAspects.metric.getSnapshot().getValues()).containsExactly(13L); // equal to thirteen + assertThat(metrics.sizeAspects.metric.getSnapshot().getValues()).containsExactly(13L); // equal to thirteen assertThat(metrics.totalDuration.metric.getCount()).isOne(); // * single duration of execution, assertThat(metrics.totalDuration.metric.getSnapshot().getValues()[0]).isNotNegative(); // that is non-negative } @@ -245,65 +273,58 @@ void testPrimitiveTypes() throws IOException @Test void testUserTypes() throws IOException { - Cluster cluster = mock(Cluster.class); + CqlSession cluster = mock(CqlSession.class); Metadata metadata = mock(Metadata.class); KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class); TableMetadata table = mock(TableMetadata.class); - TableOptionsMetadata options = mock(TableOptionsMetadata.class); ColumnMetadata pk = mock(ColumnMetadata.class); ColumnMetadata ck = mock(ColumnMetadata.class); ColumnMetadata udt1 = mock(ColumnMetadata.class); ColumnMetadata udt2 = mock(ColumnMetadata.class); ColumnMetadata c1 = mock(ColumnMetadata.class); ColumnMetadata c2 = mock(ColumnMetadata.class); - UserType udt1t = mock(UserType.class); - UserType udt2t = mock(UserType.class); - UserType.Field udt1c1 = mock(UserType.Field.class); - UserType.Field udt1udt2 = mock(UserType.Field.class); - UserType.Field udt2c2 = mock(UserType.Field.class); + UserDefinedType udt2t = new UserDefinedTypeBuilder("sample_keyspace", "udt2") + .withField("c2", new PrimitiveType(ProtocolConstants.DataType.BOOLEAN)) + .build(); + UserDefinedType udt1t = new UserDefinedTypeBuilder("sample_keyspace", "udt1") + .withField("c1", new PrimitiveType(ProtocolConstants.DataType.ASCII)) + .withField("udt2", udt2t) + .build(); when(cluster.getMetadata()).thenReturn(metadata); - when(metadata.getKeyspaces()).thenReturn(Collections.singletonList(keyspace)); - when(keyspace.getName()).thenReturn("sample_keyspace"); - when(keyspace.getTables()).thenReturn(ImmutableList.of(table)); - when(table.getKeyspace()).thenReturn(keyspace); - when(table.getName()).thenReturn("sample_table"); - when(table.getOptions()).thenReturn(options); - when(table.getColumns()).thenReturn(ImmutableList.of(pk, ck, udt1)); + CqlIdentifier keyspaceId = CqlIdentifier.fromCql("sample_keyspace"); + CqlIdentifier tableId = CqlIdentifier.fromCql("sample_table"); + when(metadata.getKeyspaces()).thenReturn(Map.of(keyspaceId, keyspace)); + when(keyspace.getName()).thenReturn(keyspaceId); + when(keyspace.getTables()).thenReturn(Map.of(tableId, table)); + when(table.getKeyspace()).thenReturn(keyspaceId); + when(table.getName()).thenReturn(tableId); + Map columns = Maps.newLinkedHashMap(); + columns.put(CqlIdentifier.fromCql("pk"), pk); + columns.put(CqlIdentifier.fromCql("cd"), ck); + columns.put(CqlIdentifier.fromCql("udt1"), udt1); + when(table.getColumns()).thenReturn(columns); when(table.getPartitionKey()).thenReturn(ImmutableList.of(pk)); - when(table.getClusteringColumns()).thenReturn(ImmutableList.of(ck)); - when(table.exportAsString()).thenReturn("CREATE TABLE sample_keyspace.sample_table (...);"); - when(options.getComment()).thenReturn("table comment"); - when(pk.getParent()).thenReturn(table); - when(pk.getName()).thenReturn("pk"); - when(pk.getType()).thenReturn(DataType.cint()); - when(ck.getParent()).thenReturn(table); - when(ck.getName()).thenReturn("ck"); - when(ck.getType()).thenReturn(DataType.cfloat()); - when(udt1.getParent()).thenReturn(table); - when(udt1.getName()).thenReturn("udt1"); + when(table.getClusteringColumns()).thenReturn(Map.of(ck, ClusteringOrder.ASC)); + when(table.describeWithChildren(anyBoolean())).thenReturn("CREATE TABLE sample_keyspace.sample_table (...);"); + when(table.getOptions()).thenReturn(Map.of(CqlIdentifier.fromInternal("comment"), "table comment")); + when(pk.getParent()).thenReturn(tableId); + when(pk.getName()).thenReturn(CqlIdentifier.fromInternal("pk")); + when(pk.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.INT)); + when(ck.getParent()).thenReturn(tableId); + when(ck.getName()).thenReturn(CqlIdentifier.fromInternal("ck")); + when(ck.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.FLOAT)); + when(udt1.getParent()).thenReturn(tableId); + when(udt1.getName()).thenReturn(CqlIdentifier.fromInternal("udt1")); when(udt1.getType()).thenReturn(udt1t); - when(udt2.getParent()).thenReturn(table); - when(udt2.getName()).thenReturn("udt2"); + when(udt2.getParent()).thenReturn(tableId); + when(udt2.getName()).thenReturn(CqlIdentifier.fromInternal("udt2")); when(udt2.getType()).thenReturn(udt2t); - when(c1.getParent()).thenReturn(table); - when(c1.getName()).thenReturn("c1"); - when(c1.getType()).thenReturn(DataType.ascii()); - when(c2.getParent()).thenReturn(table); - when(c2.getName()).thenReturn("c2"); - when(c2.getType()).thenReturn(DataType.cboolean()); - when(udt1t.getName()).thenReturn(DataType.Name.UDT); - when(udt1t.getFieldNames()).thenReturn(ImmutableList.of("c1", "udt2")); - when(udt1t.getFieldType("c1")).thenReturn(DataType.ascii()); - when(udt1t.getFieldType("udt2")).thenReturn(udt2t); - when(udt2t.getName()).thenReturn(DataType.Name.UDT); - when(udt2t.getFieldNames()).thenReturn(ImmutableList.of("c2")); - when(udt2t.getFieldType("c2")).thenReturn(DataType.cboolean()); - when(udt1c1.getName()).thenReturn("c1"); - when(udt1c1.getType()).thenReturn(DataType.ascii()); - when(udt1udt2.getName()).thenReturn("udt2"); - when(udt1udt2.getType()).thenReturn(udt2t); - when(udt2c2.getName()).thenReturn("c2"); - when(udt2c2.getType()).thenReturn(DataType.cboolean()); + when(c1.getParent()).thenReturn(tableId); + when(c1.getName()).thenReturn(CqlIdentifier.fromInternal("c1")); + when(c1.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.ASCII)); + when(c2.getParent()).thenReturn(tableId); + when(c2.getName()).thenReturn(CqlIdentifier.fromInternal("c2")); + when(c2.getType()).thenReturn(new PrimitiveType(ProtocolConstants.DataType.BOOLEAN)); JsonEmitter emitter = new JsonEmitter(); new SchemaReporter(IDENTIFIERS, () -> emitter, metrics).processScheduled(cluster); @@ -318,7 +339,7 @@ void testUserTypes() throws IOException assertThat(metrics.finishedSuccess.metric.getValue()).isOne(); // * one execution resulted in success assertThat(metrics.finishedFailure.metric.getValue()).isZero(); // * zero executions resulted in failure assertThat(metrics.sizeAspects.metric.getCount()).isOne(); // * single number of aspects, - assertThat(metrics.sizeAspects.metric.getSnapshot().getValues()).containsExactly(13L); // equal to thirteen + assertThat(metrics.sizeAspects.metric.getSnapshot().getValues()).containsExactly(13L); // equal to thirteen assertThat(metrics.totalDuration.metric.getCount()).isOne(); // * single duration of execution, assertThat(metrics.totalDuration.metric.getSnapshot().getValues()[0]).isNotNegative(); // that is non-negative } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/BasicPermissionsDatabaseAccessorTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/BasicPermissionsDatabaseAccessorTest.java index 934daa632..96f9e24d0 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/BasicPermissionsDatabaseAccessorTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/BasicPermissionsDatabaseAccessorTest.java @@ -22,11 +22,11 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Statement; +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.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.Statement; import org.apache.cassandra.sidecar.acl.authorization.PermissionFactoryImpl; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.db.schema.SidecarRolePermissionsSchema; @@ -66,7 +66,7 @@ protected TestSidecarPermissionsDatabaseAccessor(SidecarRolePermissionsSchema ta } @Override - protected ResultSet execute(Statement statement) + protected ResultSet execute(Statement statement) { ResultSet mockResultSet = mock(ResultSet.class); Row mockRow = mock(Row.class); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessorTests.java b/server/src/test/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessorTests.java index 2db66cb24..8b2fe8720 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessorTests.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessorTests.java @@ -27,21 +27,19 @@ import java.util.Objects; import java.util.TreeMap; import java.util.UUID; -import java.util.concurrent.Executor; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.ResultSetFuture; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; +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.Row; import com.google.inject.Provider; import org.apache.cassandra.bridge.TokenRange; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; @@ -51,7 +49,6 @@ import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; import org.apache.cassandra.sidecar.utils.TokenSplitUtil; import org.apache.cassandra.spark.data.partitioner.Partitioner; -import org.jetbrains.annotations.NotNull; import static org.apache.cassandra.sidecar.db.CdcDatabaseAccessor.await; import static org.apache.cassandra.sidecar.utils.TokenSplitUtil.overlaps; @@ -123,7 +120,8 @@ void testDataStore(int numNodes) TokenRange range = TokenRange.openClosed(lower, upper); int[] splits = tokenSplitUtil.findOverlappingSplitIds(partitioner, range); ByteBuffer expected = buffers[i]; - Arrays.stream(splits).forEach(split -> assertByteBufferEquals(expected, datastore.selectBuffers(jobId, split).stream().findFirst().orElseThrow())); + Arrays.stream(splits).forEach(split -> assertByteBufferEquals(expected, datastore.selectBuffers(jobId, split) + .stream().findFirst().orElseThrow())); } } @@ -233,15 +231,21 @@ void testOverlaps() assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.ZERO, BigInteger.ZERO))).isFalse(); assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.TEN, BigInteger.TEN))).isFalse(); assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.ONE, BigInteger.TWO))).isTrue(); - assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(3), BigInteger.valueOf(8)))).isTrue(); - assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.valueOf(5)))).isTrue(); + assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), + TokenRange.openClosed(BigInteger.valueOf(3), BigInteger.valueOf(8)))).isTrue(); + assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), + TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.valueOf(5)))).isTrue(); assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.TEN))).isTrue(); - assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.valueOf(15)))).isTrue(); - assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(5), BigInteger.valueOf(15)))).isTrue(); + assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), + TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.valueOf(15)))).isTrue(); + assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), + TokenRange.openClosed(BigInteger.valueOf(5), BigInteger.valueOf(15)))).isTrue(); assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(5), BigInteger.TEN))).isTrue(); - assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.valueOf(-1)))).isFalse(); - assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), TokenRange.openClosed(BigInteger.valueOf(11), BigInteger.valueOf(15)))).isFalse(); + assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), + TokenRange.openClosed(BigInteger.valueOf(-5), BigInteger.valueOf(-1)))).isFalse(); + assertThat(overlaps(TokenRange.openClosed(BigInteger.ZERO, BigInteger.TEN), + TokenRange.openClosed(BigInteger.valueOf(11), BigInteger.valueOf(15)))).isFalse(); } // test utils @@ -424,9 +428,9 @@ CQLSessionProvider getMockCQLSessionProvider(MockCdcStateV2 datastore, CdcStates }); when(mockCdcStatesSchema.select()).thenReturn(selectStmt); - Session session = mock(Session.class, RETURNS_DEEP_STUBS); + CqlSession session = mock(CqlSession.class, RETURNS_DEEP_STUBS); - when(session.getCluster().getMetadata().getPartitioner()).thenReturn("org.apache.cassandra.dht.Murmur3Partitioner"); + when(session.getMetadata().getTokenMap().get().getPartitionerName()).thenReturn("Murmur3Partitioner"); // store inserts in mocked Datastore when(session.executeAsync(insertBound)).then(invocation -> { @@ -437,27 +441,27 @@ CQLSessionProvider getMockCQLSessionProvider(MockCdcStateV2 datastore, CdcStates ByteBuffer buf = insertArgs.getArgument(4); // long timestamp = invocation.getArgument(5); datastore.insert(jobId, split, lower, upper, buf); - return new TestResultSetFuture(mock(ResultSet.class)); + return CompletableFuture.completedFuture(mock(AsyncResultSet.class)); }); when(session.executeAsync(selectBound)).then(invocation -> { String jobId = selectArgs.getArgument(0); short split = selectArgs.getArgument(1); List values = datastore.select(jobId, split); - ResultSet resultSet = mock(ResultSet.class); + AsyncResultSet resultSet = mock(AsyncResultSet.class); List rows = values.stream().map(value -> { Row row = mock(Row.class); when(row.isNull(eq(0))).thenReturn(false); when(row.isNull(eq(1))).thenReturn(false); when(row.isNull(eq(2))).thenReturn(false); - when(row.getVarint(eq(0))).thenReturn(value.range.lowerEndpoint()); - when(row.getVarint(eq(1))).thenReturn(value.range.upperEndpoint()); - when(row.getBytes(eq(2))).thenReturn(value.buf()); + when(row.getBigInteger(eq(0))).thenReturn(value.range.lowerEndpoint()); + when(row.getBigInteger(eq(1))).thenReturn(value.range.upperEndpoint()); + when(row.getByteBuffer(eq(2))).thenReturn(value.buf()); return row; }).collect(Collectors.toList()); - when(resultSet.all()).thenReturn(rows); - return new TestResultSetFuture(resultSet); + when(resultSet.currentPage()).thenReturn(rows); + return CompletableFuture.completedFuture(resultSet); }); CQLSessionProvider cqlSession = mock(CQLSessionProvider.class); @@ -465,54 +469,4 @@ CQLSessionProvider getMockCQLSessionProvider(MockCdcStateV2 datastore, CdcStates when(cqlSession.getIfConnected()).thenReturn(session); return cqlSession; } - - private static class TestResultSetFuture implements ResultSetFuture - { - final ResultSet resultSet; - - public TestResultSetFuture(ResultSet resultSet) - { - this.resultSet = resultSet; - } - - public ResultSet getUninterruptibly() - { - return resultSet; - } - - public ResultSet getUninterruptibly(long timeout, TimeUnit unit) - { - return resultSet; - } - - public boolean cancel(boolean mayInterruptIfRunning) - { - return false; - } - - public boolean isCancelled() - { - return false; - } - - public boolean isDone() - { - return true; - } - - public ResultSet get() - { - return resultSet; - } - - public ResultSet get(long timeout, @NotNull TimeUnit unit) - { - return resultSet; - } - - public void addListener(Runnable listener, Executor executor) - { - - } - } } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java index b67396597..8dbca9c30 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java @@ -23,12 +23,12 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.Statement; +import com.datastax.oss.driver.api.core.CqlSession; +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.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.Statement; import org.apache.cassandra.sidecar.common.request.Service; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; import org.apache.cassandra.sidecar.db.schema.ConfigsSchema; @@ -129,7 +129,7 @@ CQLSessionProvider getMockCQLSessionProvider(Map configs, boolea when(resultSet.one()).thenAnswer(invocation -> row); } - Session session = mock(Session.class); + CqlSession session = mock(CqlSession.class); when(session.execute(any(Statement.class))).then(invocation -> resultSet); CQLSessionProvider cqlSession = mock(CQLSessionProvider.class); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorTest.java index cac131865..85b18cb19 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessorTest.java @@ -18,9 +18,9 @@ package org.apache.cassandra.sidecar.db; -import org.junit.jupiter.api.Test; +import java.time.LocalDate; -import com.datastax.driver.core.LocalDate; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -30,13 +30,13 @@ class RestoreJobDatabaseAccessorTest void testDaysInPast() { long now = System.currentTimeMillis(); - LocalDate nowLocalDate = LocalDate.fromMillisSinceEpoch(now); + LocalDate nowLocalDate = LocalDate.ofEpochDay(now / 1000 / 60 / 60 / 24); for (int i = 0; i <= 10; i++) { LocalDate pastDate = RestoreJobDatabaseAccessor.dateInPast(now, i); - assertThat(pastDate.getDaysSinceEpoch()) + assertThat(pastDate.toEpochDay()) .describedAs(i + " days in the past") - .isEqualTo(nowLocalDate.getDaysSinceEpoch() - i); + .isEqualTo(nowLocalDate.toEpochDay() - i); } } } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobTest.java index 0a418b431..f75730369 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreJobTest.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.data.ConsistencyLevel; import org.apache.cassandra.sidecar.common.data.RestoreJobSecrets; import org.apache.cassandra.sidecar.common.data.RestoreJobStatus; @@ -102,14 +102,14 @@ public static RestoreJob createUpdatedJob(UUID jobId, String jobAgent, @Test void testDefaultImportOptionsWhenNotSetInDb() { - RestoreJob job = createNewTestingJob(UUIDs.timeBased()); + RestoreJob job = createNewTestingJob(Uuids.timeBased()); assertThat(job.importOptions).isEqualTo(SSTableImportOptions.defaults()); } @Test void testExpectedNextRangeStatus() { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); for (RestoreJobStatus status : RestoreJobStatus.values()) { RestoreJob job = createTestingJob(jobId, status); @@ -142,7 +142,7 @@ else if (status == RestoreJobStatus.STAGED) @Test void testCreateLocalConsistencyLevelJobWithoutLocalDcFails() { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); for (ConsistencyLevel localCL : Arrays.asList(ConsistencyLevel.LOCAL_QUORUM, ConsistencyLevel.LOCAL_ONE)) { assertThatThrownBy(() -> createTestingJob(jobId, RestoreJobStatus.CREATED, localCL)) @@ -154,7 +154,7 @@ void testCreateLocalConsistencyLevelJobWithoutLocalDcFails() @Test void testCreateSidecarManagedJobs() { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); String dcName = "dc1"; for (ConsistencyLevel cl : ConsistencyLevel.values()) { @@ -168,7 +168,7 @@ void testHasExpired() { long timestamp = System.currentTimeMillis(); Date expireAt = new Date(timestamp + TimeUnit.HOURS.toMillis(1)); - RestoreJob job = createNewTestingJob(UUIDs.startOf(timestamp)).unbuild().expireAt(expireAt).build(); + RestoreJob job = createNewTestingJob(Uuids.startOf(timestamp)).unbuild().expireAt(expireAt).build(); assertThat(job.hasExpired(timestamp)).isFalse(); assertThat(job.hasExpired(timestamp - 1000)).isFalse(); assertThat(job.hasExpired(expireAt.getTime() - 1)).isFalse(); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreSliceTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreSliceTest.java index dd8a1fd3f..6953e3ab6 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreSliceTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/RestoreSliceTest.java @@ -23,8 +23,8 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.request.data.CreateSliceRequestPayload; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; @@ -41,7 +41,7 @@ public class RestoreSliceTest @Test void testEquals() { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); RestoreSlice slice1 = createTestingSlice(jobId, "slice-id", 0L, 10L); RestoreSlice slice2 = createTestingSlice(jobId, "slice-id", 0L, 10L); assertThat(slice1).isEqualTo(slice2); @@ -52,7 +52,7 @@ void testEquals() @Test void testNotEquals() { - RestoreSlice slice1 = createTestingSlice(UUIDs.timeBased(), "slice-id", 0L, 10L); + RestoreSlice slice1 = createTestingSlice(Uuids.timeBased(), "slice-id", 0L, 10L); RestoreSlice slice2 = slice1.unbuild().endToken(BigInteger.valueOf(20L)).build(); assertThat(slice1).isNotEqualTo(slice2); @@ -64,18 +64,18 @@ void testNotEquals() @Test void testCreateFromRow() { - RestoreJob restoreJob = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob restoreJob = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); RestoreSlice slice = createTestingSlice(restoreJob, "slice-id", 0L, 10L); Row mockRow = mock(Row.class); - when(mockRow.getUUID("job_id")).thenReturn(slice.jobId()); + when(mockRow.getUuid("job_id")).thenReturn(slice.jobId()); when(mockRow.getString("slice_id")).thenReturn(slice.sliceId()); when(mockRow.getShort("bucket_id")).thenReturn(slice.bucketId()); when(mockRow.getString("bucket")).thenReturn(slice.bucket()); when(mockRow.getString("key")).thenReturn(slice.key()); when(mockRow.getString("checksum")).thenReturn(slice.checksum()); - when(mockRow.getVarint("start_token")).thenReturn(slice.startToken()); - when(mockRow.getVarint("end_token")).thenReturn(slice.endToken()); + when(mockRow.getBigInteger("start_token")).thenReturn(slice.startToken()); + when(mockRow.getBigInteger("end_token")).thenReturn(slice.endToken()); when(mockRow.getLong("compressed_size")).thenReturn(slice.compressedSize()); when(mockRow.getLong("uncompressed_size")).thenReturn(slice.uncompressedSize()); @@ -108,7 +108,7 @@ void testCreateFromPayload() @Test void testNoSplit() { - RestoreSlice slice = createTestingSlice(UUIDs.timeBased(), "slice-id", 0L, 10L); + RestoreSlice slice = createTestingSlice(Uuids.timeBased(), "slice-id", 0L, 10L); RestoreSlice result = slice.trimMaybe(new TokenRange(-10L, 10L)); assertThat(result) .describedAs("No trim is done when fully enclosed by the local token range") @@ -118,7 +118,7 @@ void testNoSplit() @Test void testSplitNoIntersection() { - RestoreSlice slice = createTestingSlice(UUIDs.timeBased(), "slice-id", 0L, 10L); + RestoreSlice slice = createTestingSlice(Uuids.timeBased(), "slice-id", 0L, 10L); // (0, 10] does not intersect with (100, 110] assertThatThrownBy(() -> slice.trimMaybe(new TokenRange(100L, 110L))) .isExactlyInstanceOf(IllegalStateException.class) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java index 9b6800606..d2ba05972 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java @@ -18,10 +18,14 @@ package org.apache.cassandra.sidecar.db; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -32,12 +36,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.ExecutionInfo; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.ExecutionInfo; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -50,9 +54,12 @@ import io.vertx.junit5.VertxTestContext; import org.apache.cassandra.sidecar.TestModule; import org.apache.cassandra.sidecar.TestResourceReaper; +import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate; import org.apache.cassandra.sidecar.cluster.InstancesMetadata; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; +import org.apache.cassandra.sidecar.common.response.NodeSettings; import org.apache.cassandra.sidecar.common.server.CQLSessionProvider; +import org.apache.cassandra.sidecar.common.server.StorageOperations; import org.apache.cassandra.sidecar.coordination.ClusterLease; import org.apache.cassandra.sidecar.db.schema.RestoreJobsSchema; import org.apache.cassandra.sidecar.db.schema.RestoreRangesSchema; @@ -269,17 +276,16 @@ public SidecarSchemaTestModule(boolean intercept) public CQLSessionProvider cqlSessionProvider() { CQLSessionProvider cqlSession = mock(CQLSessionProvider.class); - Session session = mock(Session.class, RETURNS_DEEP_STUBS); + CqlSession session = mock(CqlSession.class, RETURNS_DEEP_STUBS); KeyspaceMetadata ks = mock(KeyspaceMetadata.class); - when(ks.getTable(anyString())).thenReturn(null); - when(session.getCluster() - .getMetadata() - .getKeyspace(anyString())).thenAnswer((Answer) invocation -> { + when(ks.getTable(anyString())).thenReturn(Optional.empty()); + when(session.getMetadata() + .getKeyspace(anyString())).thenAnswer((Answer>) invocation -> { if (DEFAULT_SIDECAR_SCHEMA_KEYSPACE_NAME.equals(invocation.getArgument(0))) { - return null; + return Optional.empty(); } - return ks; + return Optional.of(ks); }); when(session.execute(any(String.class))).then(invocation -> { if (intercept) @@ -309,9 +315,14 @@ public CQLSessionProvider cqlSessionProvider() @Provides @Singleton - public InstancesMetadata instancesMetadata() + public InstancesMetadata instancesMetadata() throws UnknownHostException { InstanceMetadata instanceMeta = mock(InstanceMetadata.class); + CassandraAdapterDelegate mockCassandraAdapterDelegate = mock(CassandraAdapterDelegate.class); + when(mockCassandraAdapterDelegate.localStorageBroadcastAddress()).thenReturn(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8888)); + when(mockCassandraAdapterDelegate.storageOperations()).thenReturn(mock(StorageOperations.class)); + when(mockCassandraAdapterDelegate.nodeSettings()).thenReturn(mock(NodeSettings.class)); + when(instanceMeta.delegate()).thenReturn(mockCassandraAdapterDelegate); when(instanceMeta.stagingDir()).thenReturn("/tmp/staging"); // not an actual file InstancesMetadata instancesMetadata = mock(InstancesMetadata.class); when(instancesMetadata.instances()).thenReturn(Collections.singletonList(instanceMeta)); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/SystemAuthSchemaTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/SystemAuthSchemaTest.java index 912a513dd..e84cec564 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/SystemAuthSchemaTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/SystemAuthSchemaTest.java @@ -18,12 +18,13 @@ package org.apache.cassandra.sidecar.db; +import java.util.Optional; + import org.junit.jupiter.api.Test; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import org.apache.cassandra.sidecar.db.schema.SystemAuthSchema; import org.apache.cassandra.sidecar.exceptions.SchemaUnavailableException; @@ -39,14 +40,12 @@ class SystemAuthSchemaTest @Test void testSchemaNotPreparedWhenTableNotFound() { - Session mockSession = mock(Session.class); - Cluster mockCluster = mock(Cluster.class); + CqlSession mockSession = mock(CqlSession.class); Metadata mockMetadata = mock(Metadata.class); KeyspaceMetadata mockKeyspaceMetadata = mock(KeyspaceMetadata.class); - when(mockMetadata.getKeyspace("system_auth")).thenReturn(mockKeyspaceMetadata); + when(mockMetadata.getKeyspace("system_auth")).thenReturn(Optional.of(mockKeyspaceMetadata)); when(mockKeyspaceMetadata.getTable("identity_to_role")).thenReturn(null); - when(mockCluster.getMetadata()).thenReturn(mockMetadata); - when(mockSession.getCluster()).thenReturn(mockCluster); + when(mockSession.getMetadata()).thenReturn(mockMetadata); SystemAuthSchema systemAuthSchema = new SystemAuthSchema(); assertThatThrownBy(systemAuthSchema::roleFromIdentity) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/ListOperationalJobsHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/ListOperationalJobsHandlerTest.java index 5a36bfde6..039865a5a 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/ListOperationalJobsHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/ListOperationalJobsHandlerTest.java @@ -32,7 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -69,8 +69,8 @@ class ListOperationalJobsHandlerTest Vertx vertx; Server server; - static UUID runningUuid = UUIDs.timeBased(); - static UUID runningUuid2 = UUIDs.timeBased(); + static UUID runningUuid = Uuids.timeBased(); + static UUID runningUuid2 = Uuids.timeBased(); static SampleOperationalJob running = new SampleOperationalJob(runningUuid); static SampleOperationalJob running2 = new SampleOperationalJob(runningUuid2); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/OperationalJobHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/OperationalJobHandlerTest.java index 23efcfc51..a53c52b8e 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/OperationalJobHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/OperationalJobHandlerTest.java @@ -29,7 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -69,9 +69,9 @@ class OperationalJobHandlerTest Vertx vertx; Server server; - static UUID runningUuid = UUIDs.timeBased(); - static UUID completedUuid = UUIDs.timeBased(); - static UUID failedUuid = UUIDs.timeBased(); + static UUID runningUuid = Uuids.timeBased(); + static UUID completedUuid = Uuids.timeBased(); + static UUID failedUuid = Uuids.timeBased(); @BeforeEach void before() throws InterruptedException @@ -105,7 +105,7 @@ void after() throws InterruptedException void testGetJobStatusNonExistentJob(VertxTestContext context) { WebClient client = WebClient.create(vertx); - String uuid = UUIDs.timeBased().toString(); + String uuid = Uuids.timeBased().toString(); String testRoute = "/api/v1/cassandra/operational-jobs/" + uuid; client.get(server.actualPort(), "127.0.0.1", testRoute) .expect(ResponsePredicate.SC_NOT_FOUND) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/RepairHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/RepairHandlerTest.java index 6acc3545c..591c7a73f 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/RepairHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/RepairHandlerTest.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -30,9 +31,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -97,8 +98,8 @@ void before() throws InterruptedException when(mockInstanceMetadata.delegate()).thenReturn(mockDelegate); when(mockDelegate.metadata()).thenReturn(mockMetadata); when(mockDelegate.storageOperations()).thenReturn(mockStorageOperations); - when(mockMetadata.getKeyspace(anyString())).thenReturn(mockKeyspaceMetadata); - when(mockKeyspaceMetadata.getTable(anyString())).thenReturn(mockTableMetadata); + when(mockMetadata.getKeyspace(anyString())).thenReturn(Optional.of(mockKeyspaceMetadata)); + when(mockKeyspaceMetadata.getTable(anyString())).thenReturn(Optional.of(mockTableMetadata)); AbstractModule repairTestModule = new AbstractModule() { diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandlerTest.java index 0ecbeb634..194f9a172 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/ReportSchemaHandlerTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -95,7 +95,7 @@ private final class ReportSchemaHandlerTestModule extends AbstractModule public InstancesMetadata instancesMetadata() { Metadata metadata = mock(Metadata.class); - when(metadata.getKeyspaces()).thenReturn(Collections.emptyList()); + when(metadata.getKeyspaces()).thenReturn(Collections.emptyMap()); StorageOperations operations = mock(StorageOperations.class); when(operations.clusterName()).thenReturn(CLUSTER); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/SchemaHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/SchemaHandlerTest.java index fbda6c963..d1515187e 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/SchemaHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/SchemaHandlerTest.java @@ -23,6 +23,8 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -34,8 +36,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -59,6 +62,7 @@ import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -117,7 +121,7 @@ void testAllKeyspacesSchema(VertxTestContext context) JsonObject jsonObject = response.bodyAsJsonObject(); assertThat(jsonObject.getString("keyspace")).isNull(); assertThat(jsonObject.getString("schema")) - .isEqualTo("FULL SCHEMA"); + .isEqualTo(testKeyspaceSchema + "\n"); // one additional new line will be present context.completeNow(); }))); } @@ -173,9 +177,9 @@ public InstancesMetadata instanceConfig() throws IOException when(instanceMetadata.delegate()).thenReturn(mockCassandraAdapterDelegate); Metadata mockMetadata = mock(Metadata.class); KeyspaceMetadata mockKeyspaceMetadata = mock(KeyspaceMetadata.class); - when(mockMetadata.exportSchemaAsString()).thenReturn("FULL SCHEMA"); - when(mockMetadata.getKeyspace("testKeyspace")).thenReturn(mockKeyspaceMetadata); - when(mockKeyspaceMetadata.exportAsString()).thenReturn(testKeyspaceSchema); + when(mockKeyspaceMetadata.describeWithChildren(anyBoolean())).thenReturn(testKeyspaceSchema); + when(mockMetadata.getKeyspace("testKeyspace")).thenReturn(Optional.of(mockKeyspaceMetadata)); + when(mockMetadata.getKeyspaces()).thenReturn(Map.of(CqlIdentifier.fromCql("testKeyspace"), mockKeyspaceMetadata)); when(mockCassandraAdapterDelegate.metadata()).thenReturn(mockMetadata); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/TableStatsHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/TableStatsHandlerTest.java index 2c43f6e4d..da93ad050 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/TableStatsHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/TableStatsHandlerTest.java @@ -19,6 +19,7 @@ package org.apache.cassandra.sidecar.handlers; import java.util.Collections; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -29,9 +30,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -186,11 +188,11 @@ public InstancesMetadata instanceConfig() KeyspaceMetadata mockKeyspaceMetadata = mock(KeyspaceMetadata.class); Metadata mockMetadata = mock(Metadata.class); - when(mockMetadata.getKeyspace(KEYSPACE)).thenReturn(mockKeyspaceMetadata); + when(mockMetadata.getKeyspace(KEYSPACE)).thenReturn(Optional.of(mockKeyspaceMetadata)); TableMetadata table = mock(TableMetadata.class); - when(table.getKeyspace()).thenReturn(mockKeyspaceMetadata); - when(table.getName()).thenReturn(TABLE); - when(mockKeyspaceMetadata.getTable(TABLE)).thenReturn(table); + when(table.getKeyspace()).thenReturn(CqlIdentifier.fromCql(KEYSPACE)); + when(table.getName()).thenReturn(CqlIdentifier.fromCql(TABLE)); + when(mockKeyspaceMetadata.getTable(TABLE)).thenReturn(Optional.of(table)); when(delegate.metadata()).thenReturn(mockMetadata); InstancesMetadata mockInstancesMetadata = mock(InstancesMetadata.class); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/livemigration/LiveMigrationDataCopyTaskHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/livemigration/LiveMigrationDataCopyTaskHandlerTest.java index c39948bb6..747888725 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/livemigration/LiveMigrationDataCopyTaskHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/livemigration/LiveMigrationDataCopyTaskHandlerTest.java @@ -350,7 +350,8 @@ void testCreateDataCopyTaskInvalidMaxConcurrency(VertxTestContext context) // Here, we are trying to trigger a data copy request with max concurrency greater than the allowed limit. // Thus, this should throw validation errors and this test case is trying to test this particular scenario. final JsonObject dataCopyTaskPayload = getDataCopyTaskPayload(); - JsonObject badRequest = dataCopyTaskPayload.copy().put("maxConcurrency", sidecarConfiguration.liveMigrationConfiguration().maxConcurrentDownloads() + 1); + JsonObject badRequest = dataCopyTaskPayload.copy().put("maxConcurrency", + sidecarConfiguration.liveMigrationConfiguration().maxConcurrentDownloads() + 1); // Data copy task request can only be submitted from a destination host (since it follows a pull model) client.post(server.actualPort(), FIRST_DESTINATION_HOST, LIVE_MIGRATION_DATA_COPY_TASKS_ROUTE) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/CreateRestoreJobHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/CreateRestoreJobHandlerTest.java index 34b6bc23a..27b1dec64 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/CreateRestoreJobHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/CreateRestoreJobHandlerTest.java @@ -24,7 +24,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.client.HttpResponse; @@ -117,7 +117,7 @@ void testExceptionThrownDuringExecution(VertxTestContext context) throws Throwab { JsonObject payload = getRequestPayload("8e5799a4-d277-11ed-8d85-6916bb9b8056"); CQLSessionProvider sessionProviderWithNonWorkingSession = mock(CQLSessionProvider.class); - Session nonWorkingSession = mock(Session.class); + CqlSession nonWorkingSession = mock(CqlSession.class); when(nonWorkingSession.execute(anyString())).thenAnswer(invocation -> { throw new RuntimeException("unexpected exception"); }); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/RestoreJobSummaryHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/RestoreJobSummaryHandlerTest.java index 950aa38f6..bdd3cce72 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/RestoreJobSummaryHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/restore/RestoreJobSummaryHandlerTest.java @@ -18,14 +18,16 @@ package org.apache.cassandra.sidecar.handlers.restore; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import com.datastax.driver.core.LocalDate; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.json.Json; import io.vertx.ext.web.client.WebClient; @@ -53,7 +55,7 @@ void testValidRequest(VertxTestContext context) throws Throwable UUID id = UUID.fromString(jobId); // keyspace name is different return RestoreJob.builder() - .createdAt(LocalDate.fromMillisSinceEpoch(UUIDs.unixTimestamp(id))) + .createdAt(LocalDate.ofInstant(Instant.ofEpochMilli(Uuids.unixTimestamp(id)), ZoneOffset.UTC)) .jobId(id).jobAgent("job agent") .keyspace("ks").table("table") .jobStatus(RestoreJobStatus.CREATED) @@ -120,7 +122,7 @@ void testReadIncompleteRecordFails(VertxTestContext context) throws Throwable mockLookupRestoreJob(x -> { UUID jobId = UUID.fromString("7cd82ff9-d276-11ed-93e5-7fce0df1306f"); return RestoreJob.builder() - .createdAt(LocalDate.fromMillisSinceEpoch(UUIDs.unixTimestamp(jobId))) + .createdAt(LocalDate.ofInstant(Instant.ofEpochMilli(Uuids.unixTimestamp(jobId)), ZoneOffset.UTC)) .jobId(jobId).jobAgent("job agent") .keyspace("ks").table("table") .jobStatus(RestoreJobStatus.CREATED) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/handlers/sstableuploads/BaseUploadsHandlerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/handlers/sstableuploads/BaseUploadsHandlerTest.java index 64b4ebc0d..5467fa32a 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/handlers/sstableuploads/BaseUploadsHandlerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/handlers/sstableuploads/BaseUploadsHandlerTest.java @@ -22,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -35,9 +36,9 @@ import org.slf4j.LoggerFactory; import com.codahale.metrics.SharedMetricRegistries; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.Metadata; -import com.datastax.driver.core.TableMetadata; +import com.datastax.oss.driver.api.core.metadata.Metadata; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -147,8 +148,8 @@ void setup() throws InterruptedException, IOException Metadata mockMetadata = mock(Metadata.class); KeyspaceMetadata mockKeyspaceMetadata = mock(KeyspaceMetadata.class); TableMetadata mockTableMetadata = mock(TableMetadata.class); - when(mockMetadata.getKeyspace("ks")).thenReturn(mockKeyspaceMetadata); - when(mockMetadata.getKeyspace("ks").getTable("tbl")).thenReturn(mockTableMetadata); + when(mockMetadata.getKeyspace("ks")).thenReturn(Optional.of(mockKeyspaceMetadata)); + when(mockMetadata.getKeyspace("ks").get().getTable("tbl")).thenReturn(Optional.of(mockTableMetadata)); testDelegate.setMetadata(mockMetadata); mockCFOperations = mock(CassandraTableOperations.class); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/job/InMemoryOperationalJobTrackerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/job/InMemoryOperationalJobTrackerTest.java index cf5e5f590..86d8dfe1b 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/job/InMemoryOperationalJobTrackerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/job/InMemoryOperationalJobTrackerTest.java @@ -30,7 +30,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import static org.apache.cassandra.sidecar.common.data.OperationalJobStatus.CREATED; import static org.apache.cassandra.sidecar.common.data.OperationalJobStatus.RUNNING; @@ -53,7 +53,7 @@ class InMemoryOperationalJobTrackerTest OperationalJob job4 = createOperationalJob(SUCCEEDED); long twoDaysAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2); - OperationalJob jobWithStaleCreationTime = createOperationalJob(UUIDs.startOf(twoDaysAgo), SUCCEEDED); + OperationalJob jobWithStaleCreationTime = createOperationalJob(Uuids.startOf(twoDaysAgo), SUCCEEDED); @BeforeEach void setUp() @@ -134,7 +134,7 @@ void testConcurrentAccess() throws Exception ExecutorService executorService = Executors.newFixedThreadPool(trackerSize); List sortedJobs = IntStream.range(0, trackerSize + 10) .boxed() - .map(i -> createOperationalJob(UUIDs.startOf(pastTimestamp + i), SUCCEEDED)) + .map(i -> createOperationalJob(Uuids.startOf(pastTimestamp + i), SUCCEEDED)) .collect(Collectors.toList()); sortedJobs.forEach(tracker::put); executorService.shutdown(); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/job/NodeDrainJobTest.java b/server/src/test/java/org/apache/cassandra/sidecar/job/NodeDrainJobTest.java index 4fb0ca9d1..f5551fd4c 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/job/NodeDrainJobTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/job/NodeDrainJobTest.java @@ -26,7 +26,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.data.OperationalJobStatus; import org.apache.cassandra.sidecar.common.server.StorageOperations; import org.apache.cassandra.sidecar.common.server.exceptions.OperationalJobException; @@ -57,7 +57,7 @@ class NodeDrainJobTest void setup() { mockStorageOperations = mock(StorageOperations.class); - jobId = UUIDs.timeBased(); + jobId = Uuids.timeBased(); nodeDrainJob = new NodeDrainJob(jobId, mockStorageOperations); } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/job/NodeMoveJobTest.java b/server/src/test/java/org/apache/cassandra/sidecar/job/NodeMoveJobTest.java index 871ec7b07..27aa4bc78 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/job/NodeMoveJobTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/job/NodeMoveJobTest.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Promise; import org.apache.cassandra.sidecar.common.data.OperationalJobStatus; import org.apache.cassandra.sidecar.common.server.StorageOperations; @@ -54,7 +54,7 @@ class NodeMoveJobTest void setUp() { mockStorageOperations = mock(StorageOperations.class); - jobId = UUIDs.timeBased(); + jobId = Uuids.timeBased(); newToken = "123456789"; } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobManagerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobManagerTest.java index 4007b6612..0cc5273a7 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobManagerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobManagerTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Future; import io.vertx.core.Vertx; import org.apache.cassandra.sidecar.TestResourceReaper; @@ -110,7 +110,7 @@ void testWithRunningDownstreamJob() throws InterruptedException @Test void testWithLongRunningJob() throws InterruptedException { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); OperationalJobTracker tracker = new InMemoryOperationalJobTracker(4); OperationalJobManager manager = new OperationalJobManager(tracker, executorPool); CountDownLatch latch = new CountDownLatch(1); @@ -134,7 +134,7 @@ void testWithLongRunningJob() throws InterruptedException @Test void testWithFailingJob() throws InterruptedException { - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); OperationalJobTracker tracker = new InMemoryOperationalJobTracker(4); OperationalJobManager manager = new OperationalJobManager(tracker, executorPool); CountDownLatch latch = new CountDownLatch(1); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobTest.java b/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobTest.java index f3f495b7c..34404b895 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/job/OperationalJobTest.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.Vertx; @@ -53,12 +53,12 @@ class OperationalJobTest public static OperationalJob createOperationalJob(OperationalJobStatus jobStatus) { - return createOperationalJob(UUIDs.timeBased(), jobStatus); + return createOperationalJob(Uuids.timeBased(), jobStatus); } public static OperationalJob createOperationalJob(String name, OperationalJobStatus jobStatus) { - return new OperationalJob(UUIDs.timeBased()) + return new OperationalJob(Uuids.timeBased()) { @Override protected Future executeInternal() throws OperationalJobException @@ -176,7 +176,7 @@ void testJobCompletion() void testJobFailed() { String msg = "Test Job failed"; - OperationalJob failingJob = new OperationalJob(UUIDs.timeBased()) + OperationalJob failingJob = new OperationalJob(Uuids.timeBased()) { @Override public boolean hasConflict(List jobs) @@ -209,7 +209,7 @@ protected Future executeInternal() throws OperationalJobException @Test void testGetAsyncResultInWaitTime() { - OperationalJob longRunning = createOperationalJob(UUIDs.timeBased(), MillisecondBoundConfiguration.parse("500ms")); + OperationalJob longRunning = createOperationalJob(Uuids.timeBased(), MillisecondBoundConfiguration.parse("500ms")); executorPool.executeBlocking(longRunning::execute); DurationSpec waitTime = SecondBoundConfiguration.parse("2s"); Future result = longRunning.asyncResult(executorPool, waitTime); @@ -221,7 +221,7 @@ void testGetAsyncResultInWaitTime() void testGetFailedAsyncResultInWaitTime() { OperationalJobException jobFailure = new OperationalJobException("Job fails"); - OperationalJob longButFailedJob = createOperationalJob(UUIDs.timeBased(), MillisecondBoundConfiguration.parse("500ms"), jobFailure); + OperationalJob longButFailedJob = createOperationalJob(Uuids.timeBased(), MillisecondBoundConfiguration.parse("500ms"), jobFailure); executorPool.executeBlocking(longButFailedJob::execute); DurationSpec waitTime = SecondBoundConfiguration.parse("2s"); Future result = longButFailedJob.asyncResult(executorPool, waitTime); @@ -235,7 +235,7 @@ void testGetFailedAsyncResultInWaitTime() @Test void testGetAsyncResultExceedsWaitTime() { - OperationalJob longRunning = createOperationalJob(UUIDs.timeBased(), SecondBoundConfiguration.parse("5s")); + OperationalJob longRunning = createOperationalJob(Uuids.timeBased(), SecondBoundConfiguration.parse("5s")); executorPool.executeBlocking(longRunning::execute); DurationSpec waitTime = MillisecondBoundConfiguration.parse("200ms"); Future result = longRunning.asyncResult(executorPool, waitTime); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/job/RepairJobTest.java b/server/src/test/java/org/apache/cassandra/sidecar/job/RepairJobTest.java index 1eb46601a..36c525ae0 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/job/RepairJobTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/job/RepairJobTest.java @@ -29,7 +29,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.apache.cassandra.sidecar.TestResourceReaper; @@ -99,8 +99,9 @@ void testRepairJob() throws Exception .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name("testkeyspace"), payload); - RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); // Use a shorter poll interval for testing - RepairJob testJob = new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + // Use a shorter poll interval for testing + RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); + RepairJob testJob = new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); Promise promise = Promise.promise(); testJob.execute(promise); @@ -128,8 +129,9 @@ void testRunningRepairJob() .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name("testkeyspace"), payload); - RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); // Shorter poll interval for testing - RepairJob testJob = new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + // Shorter poll interval for testing + RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); + RepairJob testJob = new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); Promise promise = Promise.promise(); testJob.execute(promise); @@ -159,8 +161,9 @@ void testLongRunningRepairJobTimeout() throws Exception .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name("testkeyspace"), payload); - RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); // Shorter poll interval for testing - RepairJob testJob = new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + // Shorter poll interval for testing + RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); + RepairJob testJob = new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); Promise promise = Promise.promise(); testJob.execute(promise); @@ -178,14 +181,15 @@ void testTimersOnCompletion() throws Exception .thenReturn(List.of(RepairJob.ParentRepairStatus.COMPLETED.name(), "Repair completed successfully")); when(storageOperations.repairAsync(any(), any())).thenReturn(1); - RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); // Short poll interval for quick test + // Short poll interval for quick test + RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); RepairPayload payload = RepairPayload.builder() .isPrimaryRange(true) .tables(List.of("testtable")) .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name("testkeyspace"), payload); - RepairJob testJob = new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + RepairJob testJob = new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); Promise promise = Promise.promise(); testJob.execute(promise); @@ -206,13 +210,14 @@ void testTimersOnFailure() throws Exception .thenReturn(List.of(RepairJob.ParentRepairStatus.FAILED.name(), "Repair failed with error")); when(storageOperations.repairAsync(any(), any())).thenReturn(1); - RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); // Short poll interval for quick test + // Short poll interval for quick test + RepairJobsConfiguration config = new RepairJobsConfigurationImpl(MAX_ATTEMPTS, MillisecondBoundConfiguration.parse("100ms")); RepairPayload payload = RepairPayload.builder() .isPrimaryRange(true) .tables(List.of("testtable")) .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name("testkeyspace"), payload); - RepairJob testJob = new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + RepairJob testJob = new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); Promise promise = Promise.promise(); testJob.execute(promise); @@ -319,7 +324,7 @@ void testEmptyRepairStatusHandling() throws Exception .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name("testkeyspace"), payload); - RepairJob testJob = new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + RepairJob testJob = new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); Promise promise = Promise.promise(); testJob.execute(promise); @@ -344,6 +349,6 @@ private RepairJob createRepairJob(RepairJobsConfiguration config, StorageOperati .tables(List.of(table)) .build(); RepairRequestParam repairParams = RepairRequestParam.from(new Name(keyspace), payload); - return new RepairJob(periodicTaskExecutor, config, UUIDs.timeBased(), storageOperations, repairParams); + return new RepairJob(periodicTaskExecutor, config, Uuids.timeBased(), storageOperations, repairParams); } } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManagerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManagerTest.java index 52bafd6e8..159af461b 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManagerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/livemigration/DataCopyTaskManagerTest.java @@ -474,7 +474,8 @@ protected void configure() when(mockSourceInstanceMeta.delegate()).thenReturn(mock(CassandraAdapterDelegate.class)); // Configure LiveMigrationTaskFactory to return fake tasks - when(mockLiveMigrationTaskFactory.create(anyString(), any(LiveMigrationDataCopyRequest.class), anyString(), anyInt(), any(InstanceMetadata.class))).thenAnswer(invocation -> { + when(mockLiveMigrationTaskFactory.create(anyString(), any(LiveMigrationDataCopyRequest.class), anyString(), + anyInt(), any(InstanceMetadata.class))).thenAnswer(invocation -> { String id = invocation.getArgument(0); LiveMigrationDataCopyRequest request = invocation.getArgument(1); String source = invocation.getArgument(2); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/livemigration/LiveMigrationFileDownloaderTest.java b/server/src/test/java/org/apache/cassandra/sidecar/livemigration/LiveMigrationFileDownloaderTest.java index 7606d2088..d967011bc 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/livemigration/LiveMigrationFileDownloaderTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/livemigration/LiveMigrationFileDownloaderTest.java @@ -701,7 +701,8 @@ void testDeleteUnnecessary(@TempDir Path tempDir) throws IOException TestFile emptyKeyspace = new TestFile(DATA_FILE_DIR, 0, "emptykeyspace", -1, timeStamp); long timeStamp2 = System.currentTimeMillis(); - List localFiles = List.of(droppedKeyspaceFile, partiallyDownloadedFile, fullyDownloadedFile, wrongTimestampFile, dirDoesNotExistInRemote, emptyKeyspace); + List localFiles = List.of(droppedKeyspaceFile, partiallyDownloadedFile, fullyDownloadedFile, wrongTimestampFile, + dirDoesNotExistInRemote, emptyKeyspace); prepareDataHomeDir(storageDir, localFiles); Consumer mockStatusUpdater = mock(Consumer.class); @@ -860,7 +861,7 @@ void testGetDownloadTask(@TempDir Path tmpDir) throws IOException = getInstanceFileInfo(new String[]{ fileExists, fileDoesNotExist }, fileSize, lastModifiedTime) .get(0); Path localFilePath = localPath(fileInfos.fileUrl, downloaderSpy.instanceMetadata()); - createFile(localFilePath.toFile(), fileSize, lastModifiedTime); // Creating file explicitly as sidecarClient is mocked and doesn't do anything + createFile(localFilePath.toFile(), fileSize, lastModifiedTime); // Creating file explicitly as sidecarClient is mocked and doesn't do anything SidecarClient sidecarClient = injector.getInstance(SidecarClient.class); when(sidecarClient.liveMigrationStreamFileAsync(any(), anyString(), anyString())) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/metrics/SchemaMetricsTest.java b/server/src/test/java/org/apache/cassandra/sidecar/metrics/SchemaMetricsTest.java index 424ef247f..fc1d07449 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/metrics/SchemaMetricsTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/metrics/SchemaMetricsTest.java @@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory; import com.codahale.metrics.SharedMetricRegistries; -import com.datastax.driver.core.Session; +import com.datastax.oss.driver.api.core.CqlSession; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -115,11 +115,11 @@ public static class SchemaFailureSimulateModule extends AbstractModule @Singleton public CQLSessionProvider cqlSessionProvider() { - CQLSessionProvider cqlSession = mock(CQLSessionProvider.class); - Session session = mock(Session.class); - when(cqlSession.get()).thenReturn(session); - when(cqlSession.getIfConnected()).thenReturn(session); - return cqlSession; + CQLSessionProvider cqlSessionProvider = mock(CQLSessionProvider.class); + CqlSession session = mock(CqlSession.class); + when(cqlSessionProvider.get()).thenReturn(session); + when(cqlSessionProvider.getIfConnected()).thenReturn(session); + return cqlSessionProvider; } @Provides diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/BaseRestoreJobProgressCollectorTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/BaseRestoreJobProgressCollectorTest.java index d10191e34..456e8ddf1 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/BaseRestoreJobProgressCollectorTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/BaseRestoreJobProgressCollectorTest.java @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.common.data.ConsistencyVerificationResult; import org.apache.cassandra.sidecar.common.response.data.RestoreJobProgressResponsePayload; import org.apache.cassandra.sidecar.common.response.data.RestoreJobSummaryResponsePayload; @@ -33,7 +33,7 @@ abstract class BaseRestoreJobProgressCollectorTest { - private final RestoreJob restoreJob = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + private final RestoreJob restoreJob = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); protected final RestoreJobProgressCollector collector = createCollector(restoreJob); protected abstract RestoreJobProgressCollector createCollector(RestoreJob restoreJob); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscovererTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscovererTest.java index 9eec31fc3..72d5ca999 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscovererTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobDiscovererTest.java @@ -18,6 +18,7 @@ package org.apache.cassandra.sidecar.restore; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -28,12 +29,12 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import com.google.common.primitives.Ints; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.datastax.driver.core.LocalDate; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Promise; import org.apache.cassandra.sidecar.TestModule; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; @@ -131,7 +132,7 @@ void testGetDelay() // when there is no active restore job. The delay is idle loop delay assertThat(loop.delay()).isEqualTo(idleLoopDelay); // when there is active restore job (status: CREATED) - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); when(mockJobAccessor.findAllRecent(anyLong(), anyInt())) .thenReturn(Collections.singletonList(RestoreJob.builder() .createdAt(RestoreJob.toLocalDate(jobId)) @@ -171,9 +172,9 @@ void testExecute() when(sidecarSchema.isInitialized()).thenReturn(true); // setup, cassandra should return 3 jobs, a new job, a failed and a succeeded List mockResult = new ArrayList<>(3); - UUID newJobId = UUIDs.timeBased(); - UUID failedJobId = UUIDs.timeBased(); - UUID succeededJobId = UUIDs.timeBased(); + UUID newJobId = Uuids.timeBased(); + UUID failedJobId = Uuids.timeBased(); + UUID succeededJobId = Uuids.timeBased(); mockResult.add(createNewTestingJob(newJobId)); mockResult.add(createUpdatedJob(failedJobId, "agent", RestoreJobStatus.ABORTED, null, new Date(System.currentTimeMillis() + 10000L))); @@ -220,7 +221,7 @@ void testExecute() assertThat(loop.scheduleDecision()).isEqualTo(ScheduleDecision.EXECUTE); // Execution 4 - UUID newJobId2 = UUIDs.timeBased(); + UUID newJobId2 = Uuids.timeBased(); when(mockJobAccessor.findAllRecent(anyLong(), anyInt())) .thenReturn(Collections.singletonList(createNewTestingJob(newJobId2))); @@ -260,7 +261,7 @@ void testExecuteWithExpiredJobs() when(sidecarSchema.isInitialized()).thenReturn(true); List mockResult = IntStream.range(0, 3) .boxed() - .map(x -> createUpdatedJob(UUIDs.timeBased(), "agent", + .map(x -> createUpdatedJob(Uuids.timeBased(), "agent", RestoreJobStatus.CREATED, null, new Date(System.currentTimeMillis() - 1000L))) .collect(Collectors.toList()); @@ -295,7 +296,7 @@ void testDisciverAlreadyFailedSidecarManagedJob() throws Exception private UUID discoverSidecarManagedJob(boolean isJobFailed) throws Exception { when(sidecarSchema.isInitialized()).thenReturn(true); - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); RestoreJob sidecarManagedJob = createTestingJob(jobId, RestoreJobStatus.STAGE_READY, ConsistencyLevel.QUORUM); assertThat(sidecarManagedJob.isManagedBySidecar()).isTrue(); @@ -326,7 +327,7 @@ private UUID discoverSidecarManagedJob(boolean isJobFailed) throws Exception void testWhenJobShouldBeLogged() { RestoreJobDiscoverer.JobIdsByDay jobIdsByDay = new RestoreJobDiscoverer.JobIdsByDay(); - RestoreJob job = createNewTestingJob(UUIDs.timeBased()); + RestoreJob job = createNewTestingJob(Uuids.timeBased()); assertThat(jobIdsByDay.shouldLogJob(job)) .describedAs("should return true for the new job") .isTrue(); @@ -346,17 +347,17 @@ void testWhenJobShouldBeLogged() void testCleanupJobIdsByDay() { RestoreJobDiscoverer.JobIdsByDay jobIdsByDay = new RestoreJobDiscoverer.JobIdsByDay(); - RestoreJob job = createNewTestingJob(UUIDs.timeBased()); + RestoreJob job = createNewTestingJob(Uuids.timeBased()); jobIdsByDay.shouldLogJob(job); // insert the job jobIdsByDay.cleanupMaybe(); // issue a cleanup. but it should not remove anything assertThat(jobIdsByDay.jobsByDay()).hasSize(1) - .containsKey(job.createdAt.getDaysSinceEpoch()); - RestoreJob jobOfNextDay = job.unbuild().createdAt(LocalDate.fromDaysSinceEpoch(job.createdAt.getDaysSinceEpoch() + 1)).build(); + .containsKey(Ints.checkedCast(job.createdAt.toEpochDay())); + RestoreJob jobOfNextDay = job.unbuild().createdAt(LocalDate.ofEpochDay(job.createdAt.toEpochDay() + 1)).build(); jobIdsByDay.shouldLogJob(jobOfNextDay); jobIdsByDay.cleanupMaybe(); // issue a new cleanup. it should remove the job that is not reported in the new round assertThat(jobIdsByDay.jobsByDay()).hasSize(1) - .containsKey(jobOfNextDay.createdAt.getDaysSinceEpoch()) - .doesNotContainKey(job.createdAt.getDaysSinceEpoch()); + .containsKey(Ints.checkedCast(jobOfNextDay.createdAt.toEpochDay())) + .doesNotContainKey(Ints.checkedCast(job.createdAt.toEpochDay())); } @Test @@ -374,7 +375,7 @@ void testAdjustRecencyDays() // set up an old job that is created 10 days ago long now = System.currentTimeMillis(); long tenDaysAgo = now - TimeUnit.DAYS.toMillis(10); - UUID newJobId = UUIDs.startOf(tenDaysAgo); + UUID newJobId = Uuids.startOf(tenDaysAgo); when(mockJobAccessor.findAllRecent(anyLong(), anyInt())) .thenReturn(Collections.singletonList(createNewTestingJob(newJobId))); @@ -389,7 +390,7 @@ void testAdjustRecencyDays() void testSkipNotOwnedRestoreToLocalDatacenterOnlyJob() { // Create a restore job that restores to dc2 only. Meanwhile, discoverer runs in dc1. - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); when(mockJobAccessor.findAllRecent(anyLong(), anyInt())) .thenReturn(Collections.singletonList(RestoreJob.builder() .createdAt(RestoreJob.toLocalDate(jobId)) @@ -411,7 +412,7 @@ void testRestoreToLocalDatacenterOnlyJobIsOnHoldWhenLocalDatacenterIsUndetermine // local datacenter is undetermined and the restore job is configured to restore to local datacenter only. // the job is on hold until local datacenter is resolved in discoverer. when(instanceMetadataFetcher.callOnFirstAvailableInstance(any())).thenThrow(new CassandraUnavailableException(JMX, "NodeSettings unavailable")); - UUID jobId = UUIDs.timeBased(); + UUID jobId = Uuids.timeBased(); when(mockJobAccessor.findAllRecent(anyLong(), anyInt())) .thenReturn(Collections.singletonList(RestoreJob.builder() .createdAt(RestoreJob.toLocalDate(jobId)) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobManagerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobManagerTest.java index 16083d373..d50fcff99 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobManagerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobManagerTest.java @@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.util.Modules; @@ -192,17 +192,17 @@ void testUpdateRestoreJobForSubmittedRange() throws RestoreJobFatalException @Test void testCheckDirectoryIsObsolete() throws IOException { - Path jobDir = newDir(RestoreJobUtil.prefixedJobId(UUIDs.startOf(System.currentTimeMillis()))); + Path jobDir = newDir(RestoreJobUtil.prefixedJobId(Uuids.startOf(System.currentTimeMillis()))); // not old enough assertThat(manager.isObsoleteRestoreJobDir(jobDir)).isFalse(); // still not old enough (not 1 day yet) - jobDir = newDir(RestoreJobUtil.prefixedJobId(UUIDs.startOf(System.currentTimeMillis() + jobDir = newDir(RestoreJobUtil.prefixedJobId(Uuids.startOf(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(jobRecencyDays) + 9000))); assertThat(manager.isObsoleteRestoreJobDir(jobDir)).isFalse(); // invalid format: missing 'restore-' prefix - jobDir = newDir(UUIDs.startOf(System.currentTimeMillis() + jobDir = newDir(Uuids.startOf(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(jobRecencyDays + 1)).toString()); assertThat(manager.isObsoleteRestoreJobDir(jobDir)).isFalse(); // invalid format @@ -221,7 +221,7 @@ void testCheckDirectoryIsObsolete() throws IOException // format is good; directory is older than jobRecencyDays - jobDir = newDir(RestoreJobUtil.prefixedJobId(UUIDs.startOf(System.currentTimeMillis() + jobDir = newDir(RestoreJobUtil.prefixedJobId(Uuids.startOf(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(jobRecencyDays) - 1))); assertThat(manager.isObsoleteRestoreJobDir(jobDir)).isTrue(); @@ -231,17 +231,17 @@ void testCheckDirectoryIsObsolete() throws IOException void testDeleteObsoleteData() throws IOException { long nowMillis = System.currentTimeMillis(); - Path oldJobDir = newDir(RestoreJobUtil.prefixedJobId(UUIDs.startOf(nowMillis + Path oldJobDir = newDir(RestoreJobUtil.prefixedJobId(Uuids.startOf(nowMillis - TimeUnit.DAYS.toMillis(jobRecencyDays) - 1))); createFileInDirectory(oldJobDir, 5); Path olderJobDir - = newDir(RestoreJobUtil.prefixedJobId(UUIDs.startOf(nowMillis + = newDir(RestoreJobUtil.prefixedJobId(Uuids.startOf(nowMillis - TimeUnit.DAYS.toMillis(jobRecencyDays + 1)))); createFileInDirectory(olderJobDir, 5); - Path newJobDir = newDir(RestoreJobUtil.prefixedJobId(UUIDs.startOf(nowMillis))); + Path newJobDir = newDir(RestoreJobUtil.prefixedJobId(Uuids.startOf(nowMillis))); createFileInDirectory(newJobDir, 5); manager.deleteObsoleteDataAsync(); @@ -303,7 +303,7 @@ void testDiscardOverlappingRanges() throws Exception private RestoreRange getTestRange() { - return getTestRange(RestoreJobTest.createNewTestingJob(UUIDs.timeBased())); + return getTestRange(RestoreJobTest.createNewTestingJob(Uuids.timeBased())); } private RestoreRange getTestRange(RestoreJob job) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java index 66035b082..cb0f22bc8 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.apache.cassandra.sidecar.exceptions.RestoreJobFatalException; import org.apache.cassandra.sidecar.utils.XXHash32Provider; @@ -78,7 +78,7 @@ void testUnzipMalformed() throws Exception @Test void testExtractTimestampFromRestoreJobDirName() { - assertThat(RestoreJobUtil.timestampFromRestoreJobDir(RestoreJobUtil.prefixedJobId(UUIDs.timeBased()))) + assertThat(RestoreJobUtil.timestampFromRestoreJobDir(RestoreJobUtil.prefixedJobId(Uuids.timeBased()))) .isPositive(); // all below are -1 diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTaskTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTaskTest.java index ed799477b..140433dca 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTaskTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTaskTest.java @@ -43,7 +43,7 @@ import org.junit.jupiter.api.io.TempDir; import com.codahale.metrics.SharedMetricRegistries; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.Vertx; @@ -149,7 +149,7 @@ void clear() @Test void testRestoreSucceeds() { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED); HeadObjectResponse headObjectResponse = mock(HeadObjectResponse.class); when(headObjectResponse.contentLength()).thenReturn(1L); when(mockStorageClient.objectExists(mockRange)).thenReturn(CompletableFuture.completedFuture(headObjectResponse)); @@ -184,7 +184,7 @@ void testRestoreSucceeds() @Test void testCaptureReplicationTimeOnlyOnce() { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED); // the existence of the slice is already confirmed by the s3 client when(mockRange.existsOnS3()).thenReturn(true); when(mockStorageClient.downloadObjectIfAbsent(eq(mockRange), any(TaskExecutorPool.class))) @@ -206,7 +206,7 @@ void testCaptureReplicationTimeOnlyOnce() @Test void testStopProcessingCancelledSlice() { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED); when(mockRange.isCancelled()).thenReturn(true); RestoreRangeTask task = createTask(mockRange, job); @@ -223,7 +223,7 @@ void testStopProcessingCancelledSlice() @Test void testThrowRetryableExceptionOnS3ObjectNotFound() { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED); CompletableFuture failedFuture = new CompletableFuture<>(); failedFuture.completeExceptionally(mock(NoSuchKeyException.class)); when(mockStorageClient.objectExists(mockRange)).thenReturn(failedFuture); @@ -242,7 +242,7 @@ void testThrowRetryableExceptionOnS3ObjectNotFound() void testStaging() { // test specific setup - RestoreJob job = spy(RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.STAGE_READY)); + RestoreJob job = spy(RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.STAGE_READY)); doReturn(true).when(job).isManagedBySidecar(); doReturn(job).when(mockRange).job(); doReturn(Paths.get("nonexist")).when(mockRange).stagedObjectPath(); @@ -268,7 +268,7 @@ void testStaging() void testStagingWithExistingObject(@TempDir Path testFolder) throws IOException { // test specific setup - RestoreJob job = spy(RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.STAGE_READY)); + RestoreJob job = spy(RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.STAGE_READY)); doReturn(true).when(job).isManagedBySidecar(); doReturn(job).when(mockRange).job(); Path stagedPath = testFolder.resolve("slice.zip"); @@ -295,7 +295,7 @@ void testStagingWithExistingObject(@TempDir Path testFolder) throws IOException void testImportPhase() { // test specific setup - RestoreJob job = spy(RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.IMPORT_READY)); + RestoreJob job = spy(RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.IMPORT_READY)); doReturn(true).when(job).isManagedBySidecar(); doReturn(job).when(mockRange).job(); doReturn(true).when(mockRange).hasStaged(); @@ -315,7 +315,7 @@ void testImportPhase() void testSliceNotStagedInImportPhase() { // test specific setup - RestoreJob job = spy(RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.IMPORT_READY)); + RestoreJob job = spy(RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.IMPORT_READY)); doReturn(true).when(job).isManagedBySidecar(); doReturn(job).when(mockRange).job(); doReturn(false).when(mockRange).hasStaged(); @@ -345,7 +345,7 @@ void testImportSSTables(@TempDir Path testFolder) { // import is successful when(mockSSTableImporter.scheduleImport(any())).thenReturn(Future.succeededFuture()); - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.IMPORT_READY, ConsistencyLevel.QUORUM); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.IMPORT_READY, ConsistencyLevel.QUORUM); RestoreRangeTask task = createTask(mockRange, job); Future success = task.commit(testFolder.toFile()); assertThat(success.failed()).isFalse(); @@ -361,7 +361,7 @@ void testImportSSTables(@TempDir Path testFolder) @Test void testHandlingUnexpectedExceptionInObjectExistsCheck(@TempDir Path testFolder) { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.STAGE_READY, ConsistencyLevel.QUORUM); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.STAGE_READY, ConsistencyLevel.QUORUM); when(mockStorageClient.objectExists(mockRange)).thenThrow(new RuntimeException("Random exception")); Path stagedPath = testFolder.resolve("slice.zip"); when(mockRange.stagedObjectPath()).thenReturn(stagedPath); @@ -380,7 +380,7 @@ void testHandlingUnexpectedExceptionInObjectExistsCheck(@TempDir Path testFolder @Test void testHandlingUnexpectedExceptionDuringDownloadSliceCheck(@TempDir Path testFolder) { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.STAGE_READY, ConsistencyLevel.QUORUM); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.STAGE_READY, ConsistencyLevel.QUORUM); Path stagedPath = testFolder.resolve("slice.zip"); when(mockRange.stagedObjectPath()).thenReturn(stagedPath); when(mockRange.isCancelled()).thenReturn(false); @@ -404,7 +404,7 @@ void testHandlingUnexpectedExceptionDuringDownloadSliceCheck(@TempDir Path testF @Test void testHandlingUnexpectedExceptionDuringUnzip(@TempDir Path testFolder) throws IOException { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.IMPORT_READY, ConsistencyLevel.QUORUM); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.IMPORT_READY, ConsistencyLevel.QUORUM); Path stagedPath = testFolder.resolve("slice.zip"); Files.createFile(stagedPath); when(mockRange.hasStaged()).thenReturn(true); @@ -422,7 +422,7 @@ void testHandlingUnexpectedExceptionDuringUnzip(@TempDir Path testFolder) throws @Test void testHandlingUnexpectedExceptionDuringDownloadAndImport(@TempDir Path testFolder) { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED, null); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED, null); Path stagedPath = testFolder.resolve("slice.zip"); when(mockRange.stagedObjectPath()).thenReturn(stagedPath); when(mockRange.isCancelled()).thenReturn(false); @@ -446,7 +446,7 @@ void testHandlingUnexpectedExceptionDuringDownloadAndImport(@TempDir Path testFo @Test void testSliceDuration() { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.STAGED, ConsistencyLevel.QUORUM); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.STAGED, ConsistencyLevel.QUORUM); AtomicLong currentNanos = new AtomicLong(0); RestoreRangeTask task = createTask(mockRange, job, currentNanos::get); Promise promise = Promise.promise(); @@ -459,7 +459,7 @@ void testSliceDuration() void testRemoveOutOfRangeSSTables(@TempDir Path tempDir) throws RestoreJobException, IOException { // TODO: update test to use replica ranges implementation - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.STAGED, ConsistencyLevel.QUORUM); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.STAGED, ConsistencyLevel.QUORUM); RestoreRangeTask task = createTask(mockRange, job); // the mocked localTokenRangesProvider returns null, so retry later @@ -509,7 +509,7 @@ void testRemoveOutOfRangeSSTables(@TempDir Path tempDir) throws RestoreJobExcept @Test void testCompareChecksum(@TempDir Path tempDir) throws RestoreJobFatalException, IOException { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED); RestoreRangeTask task = createTask(mockRange, job); byte[] bytes = "Hello".getBytes(StandardCharsets.UTF_8); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTest.java index 5440e3bcf..e8978a152 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/RestoreRangeTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Future; import io.vertx.core.Promise; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; @@ -62,7 +62,7 @@ void testEquals() assertThat(range1).isEqualTo(range2); RestoreRange range3 = range1.unbuild() - .jobId(UUIDs.timeBased()) + .jobId(Uuids.timeBased()) .bucketId((short) 2) .startToken(BigInteger.valueOf(2)).endToken(BigInteger.TEN) .build(); @@ -105,7 +105,7 @@ void testCreateTaskFailsWhenMissingTacker() throws Exception void testCreateTaskFailsWhenJobExpires() throws Exception { long anchor = 1730334656231L; - RestoreJob expiredJob = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()).unbuild().expireAt(new Date(anchor - 10000L)).build(); + RestoreJob expiredJob = RestoreJobTest.createNewTestingJob(Uuids.timeBased()).unbuild().expireAt(new Date(anchor - 10000L)).build(); RestoreRange range = createTestRange(expiredJob, Paths.get("."), false); RestoreRangeHandler handler = createRestoreRangeHandler(range); assertFailedHandler(range, handler, @@ -202,7 +202,7 @@ public static RestoreRange createTestRange() public static RestoreRange createTestRange(long start, long end) { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED, null); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED, null); return createTestRange(job, Paths.get("."), false, start, end); } @@ -213,7 +213,7 @@ public static RestoreRange createTestRange(boolean jobManagedBySidecar) public static RestoreRange createTestRange(Path rootDir, boolean jobManagedBySidecar) { - RestoreJob job = RestoreJobTest.createTestingJob(UUIDs.timeBased(), RestoreJobStatus.CREATED, null); + RestoreJob job = RestoreJobTest.createTestingJob(Uuids.timeBased(), RestoreJobStatus.CREATED, null); return createTestRange(job, rootDir, jobManagedBySidecar); } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/restore/RingTopologyRefresherTest.java b/server/src/test/java/org/apache/cassandra/sidecar/restore/RingTopologyRefresherTest.java index 982a065d5..5a122b622 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/restore/RingTopologyRefresherTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/restore/RingTopologyRefresherTest.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test; -import com.datastax.driver.core.utils.UUIDs; +import com.datastax.oss.driver.api.core.uuid.Uuids; import io.vertx.core.Future; import org.apache.cassandra.sidecar.common.data.RestoreJobStatus; import org.apache.cassandra.sidecar.common.response.TokenRangeReplicasResponse; @@ -50,8 +50,8 @@ void testRegisterJobs() assertThat(replicaByTokenRangePerKeyspace.isEmpty()).isTrue(); // job1 and job2 belongs to the same keyspace - RestoreJob job1 = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); - RestoreJob job2 = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob job1 = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); + RestoreJob job2 = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); replicaByTokenRangePerKeyspace.register(job1); assertThat(replicaByTokenRangePerKeyspace.isEmpty()).isFalse(); assertThat(replicaByTokenRangePerKeyspace.allJobsUnsafe()).containsExactlyInAnyOrder(job1.jobId); @@ -68,7 +68,7 @@ void testRegisterJobs() assertThat(replicaByTokenRangePerKeyspace.mappingUnsafe()).isEmpty(); // job3 belongs to a different keyspace - RestoreJob job3 = RestoreJobTest.createTestingJob(UUIDs.timeBased(), "job3ks", RestoreJobStatus.CREATED, null); + RestoreJob job3 = RestoreJobTest.createTestingJob(Uuids.timeBased(), "job3ks", RestoreJobStatus.CREATED, null); replicaByTokenRangePerKeyspace.register(job3); assertThat(replicaByTokenRangePerKeyspace.isEmpty()).isFalse(); assertThat(replicaByTokenRangePerKeyspace.allJobsUnsafe()).containsExactlyInAnyOrder(job1.jobId, job2.jobId, job3.jobId); @@ -85,8 +85,8 @@ void testUnregisterJobs() assertThat(replicaByTokenRangePerKeyspace.isEmpty()).isTrue(); // register 2 jobs of the same keyspace and set up the promise and mapping - RestoreJob job1 = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); - RestoreJob job2 = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob job1 = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); + RestoreJob job2 = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); TokenRangeReplicasResponse mockTopology = mock(TokenRangeReplicasResponse.class); Future future1 = replicaByTokenRangePerKeyspace.futureOf(job1); Future future2 = replicaByTokenRangePerKeyspace.futureOf(job2); @@ -126,7 +126,7 @@ void testUnregisterJobs() @Test void testUnregisterPendingRefreshShouldFailPromise() { - RestoreJob job = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob job = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); Future future = replicaByTokenRangePerKeyspace.futureOf(job); assertThat(future.isComplete()).isFalse(); replicaByTokenRangePerKeyspace.unregister(job); @@ -138,7 +138,7 @@ void testUnregisterPendingRefreshShouldFailPromise() @Test void testIgnoreFailedLoad() { - replicaByTokenRangePerKeyspace.register(RestoreJobTest.createNewTestingJob(UUIDs.timeBased())); + replicaByTokenRangePerKeyspace.register(RestoreJobTest.createNewTestingJob(Uuids.timeBased())); assertThat(replicaByTokenRangePerKeyspace.mappingUnsafe()).isEmpty(); replicaByTokenRangePerKeyspace.load(ks -> { throw new RuntimeException("Load topology failed"); @@ -150,7 +150,7 @@ void testIgnoreFailedLoad() @Test void testLoadAndGetMapping() { - RestoreJob job = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob job = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); Future future = replicaByTokenRangePerKeyspace.futureOf(job); assertThat(future.isComplete()).isFalse(); assertThat(replicaByTokenRangePerKeyspace.forRestoreJob(job)).isNull(); @@ -168,7 +168,7 @@ void testLoadAndGetMapping() void testTopologyChanged() { assertThat(listenerValueCaptor).isEmpty(); - RestoreJob job = RestoreJobTest.createNewTestingJob(UUIDs.timeBased()); + RestoreJob job = RestoreJobTest.createNewTestingJob(Uuids.timeBased()); replicaByTokenRangePerKeyspace.futureOf(job); TokenRangeReplicasResponse mockTopologyEpoch1 = mock(TokenRangeReplicasResponse.class); when(mockTopologyEpoch1.writeReplicas()) diff --git a/server/src/test/java/org/apache/cassandra/sidecar/tasks/CassandraClusterSchemaMonitorTest.java b/server/src/test/java/org/apache/cassandra/sidecar/tasks/CassandraClusterSchemaMonitorTest.java index 498a9e623..b03bcf60e 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/tasks/CassandraClusterSchemaMonitorTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/tasks/CassandraClusterSchemaMonitorTest.java @@ -211,7 +211,10 @@ void testRefreshDetectsSchemaChangeAndUpdatesCdcTables() cdcUtil.when(() -> CdcUtil.extractCdcTables(UPDATED_SCHEMA)).thenReturn(mockCreateStmts2); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema( + anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), + any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class) + ); // First call returns initial schema, second call returns updated schema when(mockDatabaseAccessor.fullSchema()) @@ -249,7 +252,9 @@ void testRefreshSkipsProcessingWhenSchemaUnchanged() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), + any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); // First refresh clusterSchema.refresh(); @@ -279,7 +284,9 @@ void testRefreshNotifiesSchemaChangeListeners() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), + any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); AtomicBoolean listener1Called = new AtomicBoolean(false); AtomicBoolean listener2Called = new AtomicBoolean(false); @@ -361,7 +368,9 @@ void testExecuteCompletesPromiseSuccessfully() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), + any(Boolean.class))).thenReturn(mock(CqlTable.class)); @SuppressWarnings("unchecked") Promise promise = mock(Promise.class); @@ -410,7 +419,9 @@ void testBuildCdcTablesWithDatabaseAccessor() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), + any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); ConcurrentHashMap tableIdCache = new ConcurrentHashMap<>(); UUID testTableId = UUID.randomUUID(); @@ -445,7 +456,9 @@ void testAddSchemaChangeListenerStoresListener() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), + any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); AtomicBoolean listenerCalled = new AtomicBoolean(false); Runnable listener = () -> listenerCalled.set(true); @@ -472,7 +485,9 @@ void testMultipleSchemaChangeListenersAllNotified() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), + any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); AtomicBoolean listener1Called = new AtomicBoolean(false); AtomicBoolean listener2Called = new AtomicBoolean(false); @@ -505,7 +520,9 @@ void testSchemaChangeListenersNotCalledWhenNoSchemaChange() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), + any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); AtomicBoolean listenerCalled = new AtomicBoolean(false); clusterSchema.addSchemaChangeListener(() -> listenerCalled.set(true)); @@ -564,7 +581,9 @@ void testRefreshUpdatesTableIdCache() cdcUtil.when(() -> CdcUtil.extractCdcTables(anyString())).thenReturn(mockCreateStmts); cqlUtils.when(() -> CqlUtils.extractUdts(anyString(), anyString())).thenReturn(Collections.emptySet()); cqlUtils.when(() -> CqlUtils.extractReplicationFactor(anyString(), anyString())).thenReturn(ReplicationFactor.simpleStrategy(1)); - when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), any(Boolean.class))).thenReturn(mock(CqlTable.class)); + when(mockCassandraBridge.buildSchema(anyString(), anyString(), any(ReplicationFactor.class), + any(Partitioner.class), any(Set.class), any(UUID.class), any(Integer.class), + any(Boolean.class))).thenReturn(mock(CqlTable.class)); TableIdentifier expectedTableId = TableIdentifier.of("test", "cdc_table"); UUID expectedUuid = UUID.randomUUID(); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/tasks/CdcRawDirectorySpaceCleanerTest.java b/server/src/test/java/org/apache/cassandra/sidecar/tasks/CdcRawDirectorySpaceCleanerTest.java index 86670fb77..ae229388f 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/tasks/CdcRawDirectorySpaceCleanerTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/tasks/CdcRawDirectorySpaceCleanerTest.java @@ -262,7 +262,8 @@ private void checkExists(Path tempDir, String logFileName) private void checkExists(Path tempDir, String logFileName, boolean orphaned, boolean intact) { assertThat(Files.exists(Paths.get(tempDir.toString(), CdcRawDirectorySpaceCleaner.CDC_DIR_NAME, logFileName))).isEqualTo(!orphaned); - assertThat(Files.exists(Paths.get(tempDir.toString(), CdcRawDirectorySpaceCleaner.CDC_DIR_NAME, CdcUtil.getIdxFileName(logFileName)))).isEqualTo(!intact); + assertThat(Files.exists(Paths.get(tempDir.toString(), CdcRawDirectorySpaceCleaner.CDC_DIR_NAME, + CdcUtil.getIdxFileName(logFileName)))).isEqualTo(!intact); } private void checkNotExists(Path tempDir, String logFileName) diff --git a/server/src/test/resources/datahub/integration_test.json b/server/src/test/resources/datahub/integration_test.json index d56ba1c56..a19e1855e 100644 --- a/server/src/test/resources/datahub/integration_test.json +++ b/server/src/test/resources/datahub/integration_test.json @@ -76,7 +76,7 @@ "changeType" : "UPSERT", "aspect" : { "contentType" : "application/json", - "value" : "{\"platformSchema\":{\"com.linkedin.schema.OtherSchema\":{\"rawSchema\":\"CREATE TABLE testkeyspace.testtable (\\n b boolean,\\n c frozen,\\n n testkeyspace.numbers,\\n o testkeyspace.other,\\n s testkeyspace.strings,\\n t frozen,\\n PRIMARY KEY (b)\\n) WITH read_repair = 'BLOCKING'\\n AND gc_grace_seconds = 864000\\n AND additional_write_policy = '99p'\\n AND bloom_filter_fp_chance = 0.01\\n AND caching = { 'keys' : 'ALL', 'rows_per_partition' : 'NONE' }\\n AND comment = ''\\n AND compaction = { 'class' : 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'enabled' : 'false', 'max_threshold' : 32, 'min_threshold' : 4 }\\n AND compression = { 'chunk_length_in_kb' : 16, 'class' : 'org.apache.cassandra.io.compress.LZ4Compressor' }\\n AND default_time_to_live = 0\\n AND speculative_retry = '99p'\\n AND min_index_interval = 128\\n AND max_index_interval = 2048\\n AND crc_check_chance = 1.0\\n AND cdc = false\\n AND memtable_flush_period_in_ms = 0;\"}},\"schemaName\":\"testtable\",\"fields\":[{\"nullable\":false,\"fieldPath\":\"b\",\"isPartOfKey\":true,\"isPartitioningKey\":true,\"type\":{\"type\":{\"com.linkedin.schema.BooleanType\":{}}},\"nativeDataType\":\"boolean\"},{\"nullable\":true,\"fieldPath\":\"c.t\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"tuple\"},{\"nullable\":true,\"fieldPath\":\"c.s\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"set\"},{\"nullable\":true,\"fieldPath\":\"c.l\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"list\"},{\"nullable\":true,\"fieldPath\":\"c.m\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.MapType\":{}}},\"nativeDataType\":\"map\"},{\"nullable\":true,\"fieldPath\":\"n.ti\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"tinyint\"},{\"nullable\":true,\"fieldPath\":\"n.si\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"smallint\"},{\"nullable\":true,\"fieldPath\":\"n.bi\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"bigint\"},{\"nullable\":true,\"fieldPath\":\"n.vi\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"varint\"},{\"nullable\":true,\"fieldPath\":\"n.sf\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"float\"},{\"nullable\":true,\"fieldPath\":\"n.df\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"double\"},{\"nullable\":true,\"fieldPath\":\"n.de\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"decimal\"},{\"nullable\":true,\"fieldPath\":\"o.t.b\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.BytesType\":{}}},\"nativeDataType\":\"blob\"},{\"nullable\":true,\"fieldPath\":\"s.tu\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"timeuuid\"},{\"nullable\":true,\"fieldPath\":\"s.ru\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"uuid\"},{\"nullable\":true,\"fieldPath\":\"s.ip\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"inet\"},{\"nullable\":true,\"fieldPath\":\"s.as\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"ascii\"},{\"nullable\":true,\"fieldPath\":\"s.us\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"text\"},{\"nullable\":true,\"fieldPath\":\"s.vc\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"text\"},{\"nullable\":true,\"fieldPath\":\"t.dd\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.DateType\":{}}},\"nativeDataType\":\"date\"},{\"nullable\":true,\"fieldPath\":\"t.ts\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.DateType\":{}}},\"nativeDataType\":\"timestamp\"},{\"nullable\":true,\"fieldPath\":\"t.tt\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.TimeType\":{}}},\"nativeDataType\":\"time\"}],\"version\":1,\"platform\":\"urn:li:dataPlatform:urn:li:dataPlatform:cassandra\",\"hash\":\"a11c283d6b0007010a567a732fece86edb37d394\"}" + "value" : "{\"platformSchema\":{\"com.linkedin.schema.OtherSchema\":{\"rawSchema\":\"CREATE TABLE testkeyspace.testtable (\\n b boolean,\\n c frozen,\\n n testkeyspace.numbers,\\n o testkeyspace.other,\\n s testkeyspace.strings,\\n t frozen,\\n PRIMARY KEY (b)\\n) WITH additional_write_policy = '99p'\\n AND bloom_filter_fp_chance = 0.01\\n AND caching = {'keys':'ALL','rows_per_partition':'NONE'}\\n AND comment = ''\\n AND compaction = {'class':'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy','enabled':'false','max_threshold':'32','min_threshold':'4'}\\n AND compression = {'chunk_length_in_kb':'16','class':'org.apache.cassandra.io.compress.LZ4Compressor'}\\n AND crc_check_chance = 1.0\\n AND default_time_to_live = 0\\n AND extensions = {}\\n AND gc_grace_seconds = 864000\\n AND max_index_interval = 2048\\n AND memtable_flush_period_in_ms = 0\\n AND min_index_interval = 128\\n AND read_repair = 'BLOCKING'\\n AND speculative_retry = '99p';\"}},\"schemaName\":\"testtable\",\"fields\":[{\"nullable\":false,\"fieldPath\":\"b\",\"isPartOfKey\":true,\"isPartitioningKey\":true,\"type\":{\"type\":{\"com.linkedin.schema.BooleanType\":{}}},\"nativeDataType\":\"boolean\"},{\"nullable\":true,\"fieldPath\":\"c.t\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"frozen>\"},{\"nullable\":true,\"fieldPath\":\"c.s\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"set\"},{\"nullable\":true,\"fieldPath\":\"c.l\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"frozen>\"},{\"nullable\":true,\"fieldPath\":\"c.m\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.MapType\":{}}},\"nativeDataType\":\"map>>\"},{\"nullable\":true,\"fieldPath\":\"n.ti\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"tinyint\"},{\"nullable\":true,\"fieldPath\":\"n.si\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"smallint\"},{\"nullable\":true,\"fieldPath\":\"n.bi\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"bigint\"},{\"nullable\":true,\"fieldPath\":\"n.vi\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"varint\"},{\"nullable\":true,\"fieldPath\":\"n.sf\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"float\"},{\"nullable\":true,\"fieldPath\":\"n.df\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"double\"},{\"nullable\":true,\"fieldPath\":\"n.de\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"decimal\"},{\"nullable\":true,\"fieldPath\":\"o.t.b\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.BytesType\":{}}},\"nativeDataType\":\"blob\"},{\"nullable\":true,\"fieldPath\":\"s.tu\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"timeuuid\"},{\"nullable\":true,\"fieldPath\":\"s.ru\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"uuid\"},{\"nullable\":true,\"fieldPath\":\"s.ip\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"inet\"},{\"nullable\":true,\"fieldPath\":\"s.as\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"ascii\"},{\"nullable\":true,\"fieldPath\":\"s.us\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"text\"},{\"nullable\":true,\"fieldPath\":\"s.vc\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"text\"},{\"nullable\":true,\"fieldPath\":\"t.dd\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.DateType\":{}}},\"nativeDataType\":\"date\"},{\"nullable\":true,\"fieldPath\":\"t.ts\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.DateType\":{}}},\"nativeDataType\":\"timestamp\"},{\"nullable\":true,\"fieldPath\":\"t.tt\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.TimeType\":{}}},\"nativeDataType\":\"time\"}],\"version\":1,\"platform\":\"urn:li:dataPlatform:urn:li:dataPlatform:cassandra\",\"hash\":\"3c8dcd597a429f63acd2a443c44768dbd9e132be\"}" } }, { diff --git a/server/src/test/resources/datahub/primitive_types.json b/server/src/test/resources/datahub/primitive_types.json index 4c6ca7e6f..250146417 100644 --- a/server/src/test/resources/datahub/primitive_types.json +++ b/server/src/test/resources/datahub/primitive_types.json @@ -76,7 +76,7 @@ "changeType" : "UPSERT", "aspect" : { "contentType" : "application/json", - "value" : "{\"platformSchema\":{\"com.linkedin.schema.OtherSchema\":{\"rawSchema\":\"CREATE TABLE sample_keyspace.sample_table (...);\"}},\"schemaName\":\"sample_table\",\"fields\":[{\"nullable\":false,\"fieldPath\":\"pk1\",\"isPartOfKey\":true,\"isPartitioningKey\":true,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"int\"},{\"nullable\":false,\"fieldPath\":\"pk2\",\"isPartOfKey\":true,\"isPartitioningKey\":true,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"float\"},{\"nullable\":true,\"fieldPath\":\"ck1\",\"isPartOfKey\":true,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"varint\"},{\"nullable\":true,\"fieldPath\":\"ck2\",\"isPartOfKey\":true,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"decimal\"},{\"nullable\":true,\"fieldPath\":\"c1\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.BooleanType\":{}}},\"nativeDataType\":\"boolean\"},{\"nullable\":true,\"fieldPath\":\"c2\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.DateType\":{}}},\"nativeDataType\":\"date\"},{\"nullable\":true,\"fieldPath\":\"c3\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.TimeType\":{}}},\"nativeDataType\":\"time\"},{\"nullable\":true,\"fieldPath\":\"c4\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"ascii\"},{\"nullable\":true,\"fieldPath\":\"c6\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"varchar\"},{\"nullable\":true,\"fieldPath\":\"c6\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.BytesType\":{}}},\"nativeDataType\":\"blob\"},{\"nullable\":true,\"fieldPath\":\"c7\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"list\"},{\"nullable\":true,\"fieldPath\":\"c8\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.MapType\":{}}},\"nativeDataType\":\"map\"}],\"version\":1,\"platform\":\"urn:li:dataPlatform:urn:li:dataPlatform:cassandra\",\"hash\":\"d1ec8b1da5cc2efddfb3d5b484d091ae32fdd6c4\"}" + "value" : "{\"platformSchema\":{\"com.linkedin.schema.OtherSchema\":{\"rawSchema\":\"CREATE TABLE sample_keyspace.sample_table (...);\"}},\"schemaName\":\"sample_table\",\"fields\":[{\"nullable\":false,\"fieldPath\":\"pk1\",\"isPartOfKey\":true,\"isPartitioningKey\":true,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"int\"},{\"nullable\":false,\"fieldPath\":\"pk2\",\"isPartOfKey\":true,\"isPartitioningKey\":true,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"float\"},{\"nullable\":true,\"fieldPath\":\"ck1\",\"isPartOfKey\":true,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"varint\"},{\"nullable\":true,\"fieldPath\":\"ck2\",\"isPartOfKey\":true,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.NumberType\":{}}},\"nativeDataType\":\"decimal\"},{\"nullable\":true,\"fieldPath\":\"c1\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.BooleanType\":{}}},\"nativeDataType\":\"boolean\"},{\"nullable\":true,\"fieldPath\":\"c2\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.DateType\":{}}},\"nativeDataType\":\"date\"},{\"nullable\":true,\"fieldPath\":\"c3\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.TimeType\":{}}},\"nativeDataType\":\"time\"},{\"nullable\":true,\"fieldPath\":\"c4\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"ascii\"},{\"nullable\":true,\"fieldPath\":\"c6\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.StringType\":{}}},\"nativeDataType\":\"text\"},{\"nullable\":true,\"fieldPath\":\"c6\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.BytesType\":{}}},\"nativeDataType\":\"blob\"},{\"nullable\":true,\"fieldPath\":\"c7\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.ArrayType\":{}}},\"nativeDataType\":\"list\"},{\"nullable\":true,\"fieldPath\":\"c8\",\"isPartOfKey\":false,\"isPartitioningKey\":false,\"type\":{\"type\":{\"com.linkedin.schema.MapType\":{}}},\"nativeDataType\":\"map\"}],\"version\":1,\"platform\":\"urn:li:dataPlatform:urn:li:dataPlatform:cassandra\",\"hash\":\"d1ec8b1da5cc2efddfb3d5b484d091ae32fdd6c4\"}" } }, { diff --git a/server/src/test/resources/logback-in-jvm-dtest.xml b/server/src/test/resources/logback-in-jvm-dtest.xml index 9770bd2af..2c871a750 100644 --- a/server/src/test/resources/logback-in-jvm-dtest.xml +++ b/server/src/test/resources/logback-in-jvm-dtest.xml @@ -37,6 +37,5 @@ - - + diff --git a/test-common/build.gradle b/test-common/build.gradle index 03285e0ba..aa1fbe827 100644 --- a/test-common/build.gradle +++ b/test-common/build.gradle @@ -34,7 +34,7 @@ dependencies { testFixturesCompileOnly(group: 'io.vertx', name: 'vertx-core', version: "${project.vertxVersion}") testFixturesCompileOnly(group: 'com.google.guava', name: 'guava', version: "${project.guavaVersion}") - testFixturesCompileOnly('com.datastax.cassandra:cassandra-driver-core:3.11.3') + testFixturesCompileOnly('org.apache.cassandra:java-driver-core:4.19.1') testFixturesCompileOnly(group: 'com.intellij', name: 'annotations', version: '12.0') testFixturesApi("org.assertj:assertj-core:${assertjCoreVersion}") diff --git a/test-common/src/testFixtures/java/org/apache/cassandra/sidecar/testing/SharedExecutorNettyOptions.java b/test-common/src/testFixtures/java/org/apache/cassandra/sidecar/testing/SharedExecutorNettyOptions.java deleted file mode 100644 index fdf1a97c1..000000000 --- a/test-common/src/testFixtures/java/org/apache/cassandra/sidecar/testing/SharedExecutorNettyOptions.java +++ /dev/null @@ -1,72 +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. - */ - -package org.apache.cassandra.sidecar.testing; - -import java.util.concurrent.ThreadFactory; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -import com.datastax.driver.core.NettyOptions; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; - -/** - * This class is used to encapsulate several heavy-weight objects that can be shared across all executions - * of tests within a test run. It intentionally does not close these resources when the Cassandra Driver's - * cluster is closed, so they can be reused for the next test. - */ -public class SharedExecutorNettyOptions extends NettyOptions -{ - private SharedExecutorNettyOptions() - { - } - - public static final SharedExecutorNettyOptions INSTANCE = new SharedExecutorNettyOptions(); - - private final ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setDaemon(true) - .setNameFormat("IntegrationTest-%d") - .build(); - private final HashedWheelTimer sharedHWT = new HashedWheelTimer(threadFactory); - private final EventLoopGroup sharedEventLoopGroup = new NioEventLoopGroup(0, threadFactory); - - @Override - public EventLoopGroup eventLoopGroup(ThreadFactory threadFactory) - { - return sharedEventLoopGroup; - } - - @Override - public void onClusterClose(EventLoopGroup eventLoopGroup) - { - } - - @Override - public Timer timer(ThreadFactory threadFactory) - { - return sharedHWT; - } - - @Override - public void onClusterClose(Timer timer) - { - } -} diff --git a/vertx-client/src/test/resources/log4j2.xml b/vertx-client/src/test/resources/log4j2.xml index 3adc05314..ae794d48c 100644 --- a/vertx-client/src/test/resources/log4j2.xml +++ b/vertx-client/src/test/resources/log4j2.xml @@ -33,8 +33,6 @@ - - - + From f212aecabc3282a89817109944dd9ef7429a9a99 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 13 Apr 2026 15:31:12 +0200 Subject: [PATCH 2/4] CASSSIDECAR-421: Upgrade Java driver to 4.x --- .../adapters/base/CassandraAdapter.java | 2 +- .../ConnectedClientStatsDatabaseAccessor.java | 4 +- .../db/schema/ConnectedClientsSchema.java | 7 ++ .../SharedClusterIntegrationTestBase.java | 4 +- .../cassandra/testing/TlsTestUtils.java | 3 +- .../com/datastax/driver/core/DriverUtils.java | 85 ------------------- .../common/server/CQLSessionProvider.java | 7 ++ .../common/server/utils/DriverUtils.java | 19 +---- .../sidecar/db/schema/AbstractSchema.java | 7 +- .../db/schema/CassandraSystemTableSchema.java | 7 ++ .../cluster/CQLSessionProviderImpl.java | 5 +- .../driver/SidecarLoadBalancingPolicy.java | 11 +-- .../coordination/ClusterLeaseClaimTask.java | 4 +- .../TableToSchemaMetadataConverter.java | 2 +- .../sidecar/db/CdcDatabaseAccessor.java | 7 +- .../sidecar/db/ConfigAccessorImpl.java | 12 ++- .../db/RestoreJobDatabaseAccessor.java | 34 ++++---- .../db/RestoreRangeDatabaseAccessor.java | 10 ++- .../db/RestoreSliceDatabaseAccessor.java | 6 +- .../db/SidecarLeaseDatabaseAccessor.java | 6 +- .../SidecarPermissionsDatabaseAccessor.java | 2 +- .../db/SystemAuthDatabaseAccessor.java | 12 ++- .../db/TableHistoryDatabaseAccessor.java | 4 +- .../db/schema/SidecarInternalKeyspace.java | 7 ++ .../SidecarLoadBalancingPolicyTest.java | 3 +- .../sidecar/db/ConfigAccessorImplTest.java | 8 +- 26 files changed, 118 insertions(+), 160 deletions(-) delete mode 100644 server-common/src/main/java/com/datastax/driver/core/DriverUtils.java diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java index 09219ba47..2365f9a8e 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/CassandraAdapter.java @@ -139,7 +139,7 @@ public InetSocketAddress localNativeTransportAddress() public InetSocketAddress localStorageBroadcastAddress() { Metadata metadata = metadata(); - return getHost(metadata).getBroadcastAddress().get(); // Maybe return null? + return getHost(metadata).getBroadcastAddress().get(); } /** diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java index d30549b2a..09073dfb6 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/ConnectedClientStatsDatabaseAccessor.java @@ -46,7 +46,7 @@ public ConnectedClientStatsDatabaseAccessor(TableSchemaFetcher tableSchemaFetche public ConnectedClientStatsSummary summary() { Preconditions.checkState(tableSchema.isInitialized(), () -> tableSchema.getClass().getSimpleName() + " is not initialized yet"); - BoundStatement statement = tableSchema.connectionsByUser().bind(); + BoundStatement statement = tableSchema.connectionsByUser().bind().setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); return ConnectedClientStatsSummary.from(resultSet); } @@ -58,7 +58,7 @@ public ConnectedClientStatsSummary summary() public Stream stats() { Preconditions.checkState(tableSchema.isInitialized(), () -> tableSchema.getClass().getSimpleName() + " is not initialized yet"); - BoundStatement statement = tableSchema.stats().bind(); + BoundStatement statement = tableSchema.stats().bind().setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); return StreamSupport.stream(resultSet.spliterator(), false) .map(ConnectedClientStats::from); diff --git a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java index 54aff9019..5ad82a3df 100644 --- a/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java +++ b/adapters/adapters-base/src/main/java/org/apache/cassandra/sidecar/adapters/base/db/schema/ConnectedClientsSchema.java @@ -18,6 +18,7 @@ package org.apache.cassandra.sidecar.adapters.base.db.schema; +import com.datastax.oss.driver.api.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import org.apache.cassandra.sidecar.db.schema.CassandraSystemTableSchema; @@ -48,6 +49,12 @@ public void prepareStatements(@NotNull CqlSession session) connectionsByUserStatement = prepare(connectionsByUserStatement, session, selectConnectionsByUserStatement()); } + @Override + public ConsistencyLevel getConsistencyLevel() + { + return ConsistencyLevel.LOCAL_QUORUM; + } + @Override protected String tableName() { diff --git a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java index 38e64940a..43a3f3f75 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java +++ b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java @@ -580,8 +580,8 @@ protected ResultSet queryAllDataWithDriver(QualifiedName table) protected ResultSet queryAllDataWithDriver(QualifiedName table, ConsistencyLevel consistency) { CqlSession session = createDriverSession(cluster.delegate()); - SimpleStatement statement = SimpleStatement.newInstance(String.format("SELECT * FROM %s;", table)); - statement = statement.setConsistencyLevel(DefaultConsistencyLevel.valueOf(consistency.name())); + SimpleStatement statement = SimpleStatement.newInstance(String.format("SELECT * FROM %s;", table)) + .setConsistencyLevel(DefaultConsistencyLevel.valueOf(consistency.name())); return session.execute(statement); } diff --git a/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java b/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java index 61c7dd6fc..601e24438 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java +++ b/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java @@ -130,8 +130,7 @@ public static SSLContext buildSSLContext(String keystorePath, String keystorePas SSLContext sslContext; try { - // TODO(lantoniak): Multiple protocols are not supported. - sslContext = SSLContext.getInstance("TLSv1.3"); + sslContext = SSLContext.getInstance("TLS"); KeyManagerFactory kmf = null; if (keystorePath != null && keystorePassword != null) diff --git a/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java b/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java deleted file mode 100644 index c1b05a1a0..000000000 --- a/server-common/src/main/java/com/datastax/driver/core/DriverUtils.java +++ /dev/null @@ -1,85 +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. - */ - -package com.datastax.driver.core; - -import java.net.InetSocketAddress; - -import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.core.metadata.Node; -import org.jetbrains.annotations.VisibleForTesting; - -/** - * A collection of methods that require access to package-private members in the datastax driver. - */ -public class DriverUtils -{ - /** - * Check if a host has active connections. - * - *

    Note: This method should not be used directly, but should be proxied by - * an implementation of {@link org.apache.cassandra.sidecar.common.server.utils.DriverUtils}. - * - * @param host the host to check - * @return true if the host has active connections, false otherwise - */ - @VisibleForTesting - public static boolean hasActiveConnections(Node host) - { - return host.getOpenConnections() > 0; - } - -// /** -// * Start attempting to reconnect to the given host, as hosts with `IGNORED` distance aren't attempted -// * and the SidecarLoadBalancingPolicy marks non-selected nodes as IGNORED until they need to rotate in. -// * -// *

    Note: This method should not be used directly, but should be proxied by -// * an implementation of {@link org.apache.cassandra.sidecar.common.server.utils.DriverUtils}. -// * -// * @param cluster The cluster object -// * @param host the host to which reconnect attempts will be made -// */ -// public static void startPeriodicReconnectionAttempt(Cluster cluster, Node host) -// { -// cluster.manager.startPeriodicReconnectionAttempt(host, false); -// } - - /** - * Gets a Host instance from metadata based on the native transport address - * - *

    Note: This method should not be used directly, but should be proxied by - * an implementation of {@link org.apache.cassandra.sidecar.common.server.utils.DriverUtils}. - * - * @param metadata the {@link Metadata} instance to search for the host - * @param localNativeTransportAddress the native transport ip address and port for the host to find - * @return the {@link Node} instance if found, else null - */ - public static Node getHost(Metadata metadata, InetSocketAddress localNativeTransportAddress) - { -// // Because the driver can sometimes mess up the broadcast address, we need to search by endpoint -// // which is what it actually uses to connect to the cluster. Therefore, create a TranslatedAddressEndpoint -// // to use for searching. It has to be one of these because that's what the driver is using internally, -// // and the `.equals` method used when searching checks the type explicitly. -// TranslatedAddressEndPoint endPoint = new TranslatedAddressEndPoint(localNativeTransportAddress); -// return metadata.getHost(endPoint); - // TODO(lantoniak): Use TranslatedAddressEndPoint? - return metadata.getNodes().values().stream() - .filter(n -> n.getEndPoint().resolve().equals(localNativeTransportAddress)) - .findFirst().orElse(null); - } -} diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java index c63f23021..1f2f4dd87 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/CQLSessionProvider.java @@ -57,6 +57,13 @@ public interface CQLSessionProvider */ void close(); + /** + * Register new node state listener. + */ void registerNodeStateListener(NodeStateListener nodeStateListener); + + /** + * Unregister node state listener. + */ void unregisterNodeStateListener(NodeStateListener nodeStateListener); } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java index 834a7b823..a190a51e7 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/DriverUtils.java @@ -27,24 +27,11 @@ import com.datastax.oss.driver.api.core.metadata.Node; /** - * A shim layer that provides information from the Cassandra driver. Instead of accessing the - * {@link com.datastax.driver.core.DriverUtils} directly, this acts as a proxy that can be swapped out + * A shim layer that provides information from the Cassandra driver. This acts as a proxy that can be swapped out * based on the specific Sidecar implementation. This can be useful if a different driver version is used */ public class DriverUtils { -// /** -// * Start attempting to reconnect to the given host, as hosts with `IGNORED` distance aren't attempted -// * and the SidecarLoadBalancingPolicy marks non-selected nodes as IGNORED until they need to rotate in. -// * -// * @param cluster The cluster object -// * @param host the host to which reconnect attempts will be made -// */ -// public void startPeriodicReconnectionAttempt(Cluster cluster, Node host) -// { -// com.datastax.driver.core.DriverUtils.startPeriodicReconnectionAttempt(cluster, host); -// } - /** * Gets a Host instance from metadata based on the native transport address * @@ -54,7 +41,9 @@ public class DriverUtils */ public Node getHost(Metadata metadata, InetSocketAddress localNativeTransportAddress) { - return com.datastax.driver.core.DriverUtils.getHost(metadata, localNativeTransportAddress); + return metadata.getNodes().values().stream() + .filter(n -> n.getEndPoint().resolve().equals(localNativeTransportAddress)) + .findFirst().orElse(null); } /** diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java index 85061254b..f7ac79975 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/AbstractSchema.java @@ -23,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.datastax.oss.driver.api.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.ResultSet; @@ -54,7 +55,6 @@ public boolean isInitialized() protected PreparedStatement prepare(PreparedStatement cached, CqlSession session, String cqlLiteral) { - // TODO(lantoniak): .setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM) return cached == null ? session.prepare(cqlLiteral) : cached; } @@ -114,4 +114,9 @@ protected boolean initializeInternal(@NotNull CqlSession session, * @return the statement to create the schema */ protected abstract String createSchemaStatement(); + + public ConsistencyLevel getConsistencyLevel() + { + return ConsistencyLevel.LOCAL_QUORUM; + } } diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java index 8d21ceab7..136e98388 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/db/schema/CassandraSystemTableSchema.java @@ -20,6 +20,7 @@ import java.util.function.Predicate; +import com.datastax.oss.driver.api.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Metadata; import org.jetbrains.annotations.NotNull; @@ -52,4 +53,10 @@ protected String createSchemaStatement() { return null; } + + @Override + public ConsistencyLevel getConsistencyLevel() + { + return ConsistencyLevel.ONE; + } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java index abe1a0846..94d307aca 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CQLSessionProviderImpl.java @@ -286,8 +286,9 @@ private SSLContext createSslContext(SslConfiguration sslConfiguration) try { - // TODO(lantoniak): Multiple protocols are not supported. - SSLContext sslContext = SSLContext.getInstance(sslConfiguration.secureTransportProtocols().get(0)); + // TODO: If we wish to explicitly limit allowed SSL protocols, + // we need to implement custom DefaultSslEngineFactory and use SSLEngine.setEnabledProtocols(). + SSLContext sslContext = SSLContext.getInstance("TLS"); KeyManagerFactory kmf = null; if (sslConfiguration.isKeystoreConfigured()) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java index bcb9695f3..04e606812 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java @@ -83,7 +83,7 @@ public SidecarLoadBalancingPolicy(DriverContext context, String profileName) public void init(Map nodes, @NotNull DistanceReporter distanceReporter) { this.allHosts.addAll(nodes.values()); - recalculateSelectedHosts(true); + recalculateSelectedHosts(); super.init(nodes, distanceReporter); } @@ -111,7 +111,7 @@ public synchronized void onUp(@NotNull Node node) this.allHosts.add(node); // replace existing reference if there is one if (selectedHosts.size() < totalRequestedConnections) { - recalculateSelectedHosts(false); + recalculateSelectedHosts(); } super.onUp(node); } @@ -125,7 +125,8 @@ public synchronized void onDown(@NotNull Node node) LOGGER.debug("Local Node {} has been marked down.", node); return; } - recalculateSelectedHosts(false); + selectedHosts.remove(node); + recalculateSelectedHosts(); super.onDown(node); } @@ -137,7 +138,7 @@ public void onRemove(@NotNull Node node) super.onRemove(node); } - private synchronized void recalculateSelectedHosts(boolean initiation) + private synchronized void recalculateSelectedHosts() { Map> partitionedHosts = allHosts.stream() .collect(Collectors.partitioningBy(this::isLocalHost)); @@ -170,7 +171,7 @@ private synchronized void recalculateSelectedHosts(boolean initiation) nonLocalHosts = nonLocalHosts.stream() .filter(h -> !selectedHosts.contains(h) && (NodeState.UP.equals(h.getState()) - || (initiation && NodeState.UNKNOWN.equals(h.getState())))) + || NodeState.UNKNOWN.equals(h.getState()))) .collect(Collectors.toList()); if (nonLocalHosts.size() < requiredNonLocalHosts) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java index 949ac760a..8ac511a49 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java @@ -26,7 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.oss.driver.api.core.NoNodeAvailableException; +import com.datastax.oss.driver.api.core.AllNodesFailedException; import com.datastax.oss.driver.api.core.servererrors.QueryConsistencyException; import io.vertx.core.Promise; import io.vertx.core.Vertx; @@ -217,7 +217,7 @@ protected String executeLeaseAction(String actionName, LOGGER.debug("Attempting to {} lease for sidecarHostId={}", actionName, sidecarHostId); return actionFn.apply(sidecarHostId).currentOwner; } - catch (QueryConsistencyException | NoNodeAvailableException | IllegalArgumentException e) + catch (QueryConsistencyException | AllNodesFailedException | IllegalArgumentException e) { LOGGER.debug("Unable to {} lease for sidecarHostId={}", actionName, sidecarHostId, e); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java index 02e12565f..d229b93b2 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java @@ -115,7 +115,7 @@ public MetadataChangeProposalWrapper convert(@NotNull KeyspaceMe // Use {@code CREATE TABLE} CQL statement with all associated indexes and views but without // UDTs as the native schema; using {@code asCQLQuery()} does not allow formatting produced CQL - String cql = table.describeWithChildren(true); // TODO(lantoniak): Test true or false. + String cql = table.describeWithChildren(true); SchemaMetadata.PlatformSchema schema = new SchemaMetadata.PlatformSchema(); schema.setOtherSchema(new OtherSchema().setRawSchema(cql)); String hash = DigestUtils.sha1Hex(cql); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java index 0ae8565c2..293ed726f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/CdcDatabaseAccessor.java @@ -129,7 +129,7 @@ public List> storeStateAsync(String jobId, range.upperEndpoint(), buf, timestamp - )).toCompletableFuture()) + ).setConsistencyLevel(tableSchema.getConsistencyLevel())).toCompletableFuture()) .collect(Collectors.toList()); } @@ -167,7 +167,6 @@ public static Stream await(Stream> future return futures.flatMap(f -> { try { - // TODO(lantoniak): Fid a better implementation of loading Stream? List rows = new ArrayList<>(); do { @@ -198,6 +197,8 @@ public static Stream await(Stream> future CompletableFuture selectCdcRange(String jobId, int split) { - return session().executeAsync(tableSchema.select().bind(jobId, (short) split)).toCompletableFuture(); + return session().executeAsync(tableSchema.select().bind(jobId, (short) split) + .setConsistencyLevel(tableSchema.getConsistencyLevel())) + .toCompletableFuture(); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java b/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java index 676a41b32..ffd2fb919 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/ConfigAccessorImpl.java @@ -55,7 +55,8 @@ public ServiceConfig getConfig() { sidecarSchema.ensureInitialized(); BoundStatement statement = tableSchema.selectConfig() - .bind(serviceName); + .bind(serviceName) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); Row row = execute(statement).one(); if (row == null || row.isNull(0)) { @@ -70,7 +71,8 @@ public ServiceConfig storeConfig(Map config) { sidecarSchema.ensureInitialized(); BoundStatement statement = tableSchema.insertConfig() - .bind(serviceName, config); + .bind(serviceName, config) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(statement); return new ServiceConfig(config); } @@ -80,7 +82,8 @@ public Optional storeConfigIfNotExists(Map config { sidecarSchema.ensureInitialized(); BoundStatement statement = tableSchema.insertConfigIfNotExists() - .bind(serviceName, config); + .bind(serviceName, config) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); if (resultSet.wasApplied()) { @@ -94,7 +97,8 @@ public void deleteConfig() { sidecarSchema.ensureInitialized(); BoundStatement deleteStatement = tableSchema.deleteConfig() - .bind(serviceName); + .bind(serviceName) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(deleteStatement); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java index 2990d8ae3..84b786026 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreJobDatabaseAccessor.java @@ -102,7 +102,8 @@ public RestoreJob create(CreateRestoreJobRequestPayload payload, QualifiedTableN job.consistencyLevelText(), job.localDatacenter, job.shouldRestoreToLocalDatacenterOnly, - job.expireAt.toInstant()); + job.expireAt.toInstant()) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(statement); return job; @@ -141,7 +142,8 @@ public RestoreJob update(UpdateRestoreJobRequestPayload payload, UUID jobId) byte[] secretBytes = MAPPER.writeValueAsBytes(secrets); wrappedSecrets = ByteBuffer.wrap(secretBytes); batchStatement = batchStatement.add(tableSchema.updateBlobSecrets() - .bind(createdAt, jobId, wrappedSecrets)); + .bind(createdAt, jobId, wrappedSecrets) + .setConsistencyLevel(tableSchema.getConsistencyLevel())); } catch (JsonProcessingException e) { @@ -151,22 +153,26 @@ public RestoreJob update(UpdateRestoreJobRequestPayload payload, UUID jobId) } if (status != null) { - batchStatement = batchStatement.add(tableSchema.updateStatus().bind(createdAt, jobId, status.name())); + batchStatement = batchStatement.add(tableSchema.updateStatus().bind(createdAt, jobId, status.name()) + .setConsistencyLevel(tableSchema.getConsistencyLevel())); updateBuilder.jobStatus(status); } if (jobAgent != null) { - batchStatement = batchStatement.add(tableSchema.updateJobAgent().bind(createdAt, jobId, jobAgent)); + batchStatement = batchStatement.add(tableSchema.updateJobAgent().bind(createdAt, jobId, jobAgent) + .setConsistencyLevel(tableSchema.getConsistencyLevel())); updateBuilder.jobAgent(jobAgent); } if (expireAt != null) { - batchStatement = batchStatement.add(tableSchema.updateExpireAt().bind(createdAt, jobId, expireAt.toInstant())); + batchStatement = batchStatement.add(tableSchema.updateExpireAt().bind(createdAt, jobId, expireAt.toInstant()) + .setConsistencyLevel(tableSchema.getConsistencyLevel())); updateBuilder.expireAt(expireAt); } if (sliceCount != null) { - batchStatement = batchStatement.add(tableSchema.updateSliceCount().bind(createdAt, jobId, sliceCount)); + batchStatement = batchStatement.add(tableSchema.updateSliceCount().bind(createdAt, jobId, sliceCount) + .setConsistencyLevel(tableSchema.getConsistencyLevel())); updateBuilder.sliceCount(sliceCount); } @@ -185,7 +191,8 @@ public void abort(UUID jobId, @Nullable String reason) status = status + ": " + reason; } BoundStatement statement = tableSchema.updateStatus() - .bind(createdAt, jobId, status); + .bind(createdAt, jobId, status) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(statement); } @@ -193,7 +200,8 @@ public RestoreJob find(UUID jobId) { sidecarSchema.ensureInitialized(); - BoundStatement statement = tableSchema.selectJob().bind(RestoreJob.toLocalDate(jobId), jobId); + BoundStatement statement = tableSchema.selectJob().bind(RestoreJob.toLocalDate(jobId), jobId) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); Row row = resultSet.one(); if (row == null) @@ -218,18 +226,12 @@ public List findAllByCreationDate(LocalDate date) { sidecarSchema.ensureInitialized(); - BoundStatement statement = tableSchema.findAllByCreatedAt().bind(date); + BoundStatement statement = tableSchema.findAllByCreatedAt().bind(date) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); List result = new ArrayList<>(); for (Row row : resultSet) { - // TODO(lantoniak): Feature not supported in new driver. -// if (resultSet.getAvailableWithoutFetching() == 100 && !resultSet.isFullyFetched()) -// { -// // trigger an async fetch sooner when there are more to fetch, -// // and it still has around 100 available to consume from the resultSet -// resultSet.fetchMoreResults(); -// } result.add(RestoreJob.from(row)); } return result; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java index 643fa35b3..b85beddfb 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreRangeDatabaseAccessor.java @@ -65,7 +65,8 @@ public RestoreRange create(RestoreRange range) range.jobId(), range.bucketId(), range.startToken(), - range.endToken()); + range.endToken()) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(statement); LOGGER.debug("Created range={}", range); return range; @@ -80,21 +81,22 @@ public RestoreRange updateStatus(RestoreRange range) range.jobId(), range.bucketId(), range.startToken(), - range.endToken()); + range.endToken()) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(statement); LOGGER.debug("Updated range={}", range); return range; } // todo: change to stream api and paginate - // TODO(lantoniak): Maybe implement above? public List findAll(UUID jobId, short bucketId) { sidecarSchema.ensureInitialized(); BoundStatement statement = tableSchema.findAll() .bind(jobId, - bucketId); + bucketId) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet result = execute(statement); List ranges = new ArrayList<>(); for (Row row : result) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java index e258f06c0..4dc9ae57e 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/RestoreSliceDatabaseAccessor.java @@ -62,7 +62,8 @@ public RestoreSlice create(RestoreSlice slice) slice.startToken(), slice.endToken(), slice.compressedSize(), - slice.uncompressedSize()); + slice.uncompressedSize()) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); execute(statement); return slice; } @@ -81,7 +82,8 @@ public List selectByJobByBucketByTokenRange(RestoreJob restoreJob, .bind(restoreJob.jobId, bucketId, range.start().toBigInteger(), - range.end().toBigInteger()); + range.end().toBigInteger()) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet result = execute(statement); List slices = new ArrayList<>(); for (Row row : result) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java index 476ad876d..51f39d4d4 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java @@ -54,7 +54,8 @@ public SidecarLeaseDatabaseAccessor(SidecarLeaseSchema leaseSchema, CQLSessionPr */ public LeaseClaimResult claimLease(String leaseClaimer) { - BoundStatement statement = tableSchema.claimLeaseStatement().bind(leaseClaimer); + BoundStatement statement = tableSchema.claimLeaseStatement().bind(leaseClaimer) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); return LeaseClaimResult.from(resultSet, leaseClaimer); } @@ -68,7 +69,8 @@ public LeaseClaimResult claimLease(String leaseClaimer) */ public LeaseClaimResult extendLease(String currentOwner) { - BoundStatement statement = tableSchema.extendLeaseStatement().bind(currentOwner, currentOwner); + BoundStatement statement = tableSchema.extendLeaseStatement().bind(currentOwner, currentOwner) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); return LeaseClaimResult.from(resultSet, currentOwner); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java index e933c9d45..8db286098 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarPermissionsDatabaseAccessor.java @@ -69,7 +69,7 @@ protected SidecarPermissionsDatabaseAccessor(SidecarRolePermissionsSchema tableS */ public Map> rolesToAuthorizations() { - BoundStatement statement = tableSchema.allRolesPermissions().bind(); + BoundStatement statement = tableSchema.allRolesPermissions().bind().setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet result = execute(statement); Map> roleAuthorizations = new HashMap<>(); for (Row row : result) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java index c11e3d246..fc8e6c342 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/SystemAuthDatabaseAccessor.java @@ -72,7 +72,8 @@ public SystemAuthDatabaseAccessor(SystemAuthSchema systemAuthSchema, */ public String findRoleFromIdentity(String identity) { - BoundStatement statement = tableSchema.roleFromIdentity().bind(identity); + BoundStatement statement = tableSchema.roleFromIdentity().bind(identity) + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet result = execute(statement); Row row = result.one(); return row != null ? row.getString("role") : null; @@ -85,7 +86,8 @@ public String findRoleFromIdentity(String identity) */ public Map findAllIdentityToRoles() { - BoundStatement statement = tableSchema.allRolesAndIdentities().bind(); + BoundStatement statement = tableSchema.allRolesAndIdentities().bind() + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet resultSet = execute(statement); Map results = new HashMap<>(); for (Row row : resultSet) @@ -103,7 +105,8 @@ public Map findAllIdentityToRoles() */ public Map> findAllRolesAndPermissions() { - BoundStatement statement = tableSchema.allRolesAndPermissions().bind(); + BoundStatement statement = tableSchema.allRolesAndPermissions().bind() + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet result = execute(statement); Map> roleAuthorizations = new HashMap<>(); for (Row row : result) @@ -156,7 +159,8 @@ public boolean isSuperUser(String role) */ public Map findAllRolesToSuperuserStatus() { - BoundStatement statement = tableSchema.allRoles().bind(); + BoundStatement statement = tableSchema.allRoles().bind() + .setConsistencyLevel(tableSchema.getConsistencyLevel()); ResultSet result = execute(statement); List rows = result.all(); Map roleToSuperUser = rows.stream() diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java b/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java index 40c752a2a..1f453210b 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/TableHistoryDatabaseAccessor.java @@ -44,12 +44,12 @@ public TableHistoryDatabaseAccessor(SidecarSchema sidecarSchema, super(sidecarSchema.tableSchema(TableHistorySchema.class), sessionProvider); } - // TODO(lantoniak): Callers do not wait for future to complete. public CompletableFuture insertTableSchemaHistory(String keyspace, String tableName, String schema) { UUID schemaUuid = UUID.nameUUIDFromBytes(schema.getBytes(StandardCharsets.UTF_8)); return session().executeAsync(tableSchema .insertTableSchema() - .bind(keyspace, tableName, schemaUuid, schema)).toCompletableFuture(); + .bind(keyspace, tableName, schemaUuid, schema) + .setConsistencyLevel(tableSchema.getConsistencyLevel())).toCompletableFuture(); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java index ef7919eda..13d962e81 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/db/schema/SidecarInternalKeyspace.java @@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; +import com.datastax.oss.driver.api.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.metadata.Metadata; import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration; @@ -102,4 +103,10 @@ protected String createSchemaStatement() return String.format("CREATE KEYSPACE IF NOT EXISTS %s WITH REPLICATION = %s", keyspaceName(), keyspaceConfig.createReplicationStrategyString()); } + + @Override + public ConsistencyLevel getConsistencyLevel() + { + return ConsistencyLevel.ONE; + } } diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java index 756fb58d9..58cbf6d9a 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java @@ -30,7 +30,6 @@ import com.google.common.util.concurrent.Uninterruptibles; import org.junit.jupiter.api.Assertions; -import com.datastax.driver.core.DriverUtils; import com.datastax.oss.driver.api.core.metadata.Node; import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; @@ -51,7 +50,7 @@ public class SidecarLoadBalancingPolicyTest extends IntegrationTestBase private static List getConnectedHosts(Collection hosts) { return hosts.stream() - .filter(DriverUtils::hasActiveConnections) + .filter(n -> n.getOpenConnections() > 0) .collect(Collectors.toList()); } diff --git a/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java b/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java index 8dbca9c30..4b2d6bfff 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/db/ConfigAccessorImplTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import com.datastax.oss.driver.api.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; @@ -107,11 +108,14 @@ private ConfigsSchema getMockConfigsSchema() { ConfigsSchema mockConfigsSchema = mock(ConfigsSchema.class); PreparedStatement preparedStatement = mock(PreparedStatement.class); - when(preparedStatement.bind()).thenReturn(mock(BoundStatement.class)); - when(preparedStatement.bind(any())).thenReturn(mock(BoundStatement.class)); + BoundStatement boundStatement = mock(BoundStatement.class); + when(boundStatement.setConsistencyLevel(any())).thenReturn(boundStatement); + when(preparedStatement.bind()).thenReturn(boundStatement); + when(preparedStatement.bind(any())).thenReturn(boundStatement); when(mockConfigsSchema.selectConfig()).thenReturn(preparedStatement); when(mockConfigsSchema.insertConfig()).thenReturn(preparedStatement); when(mockConfigsSchema.deleteConfig()).thenReturn(preparedStatement); + when(mockConfigsSchema.getConsistencyLevel()).thenReturn(ConsistencyLevel.LOCAL_QUORUM); return mockConfigsSchema; } From e28adac1ab5a9b624e4338eac710acfcde24d995 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Wed, 15 Apr 2026 15:52:57 +0200 Subject: [PATCH 3/4] Refactor MetadataUtils --- .../common/server/dns/DnsResolvers.java | 2 +- .../cdc/SidecarClusterConfigProvider.java | 8 +++++--- .../driver/SidecarLoadBalancingPolicy.java | 14 +++++++++++--- .../locator/CachedLocalTokenRanges.java | 8 +++++--- .../CassandraClientTokenRingProvider.java | 18 +++++++++++++----- .../coordination/TokenRingProvider.java | 13 ++++++++----- .../cassandra/sidecar/modules/CdcModule.java | 11 +++++++---- .../sidecar/modules/RestoreJobModule.java | 5 +++-- .../cassandra/sidecar/utils/MetadataUtils.java | 14 -------------- .../driver/SidecarLoadBalancingPolicyTest.java | 4 ++-- .../CassandraClientTokenRingProviderTest.java | 8 ++++++-- 11 files changed, 61 insertions(+), 44 deletions(-) diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/dns/DnsResolvers.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/dns/DnsResolvers.java index 5277780bc..f5a97dd5f 100644 --- a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/dns/DnsResolvers.java +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/dns/DnsResolvers.java @@ -74,6 +74,6 @@ public String reverseResolve(String address) throws UnknownHostException @Override public String resolve(String hostname) throws UnknownHostException { - return InetAddress.getByName(hostname).getHostAddress(); + return InetAddress.getByName(hostname).getHostAddress(); } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java index a8b3c4baa..b899e9991 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java @@ -28,9 +28,9 @@ import com.datastax.oss.driver.api.core.metadata.TokenMap; import org.apache.cassandra.cdc.sidecar.ClusterConfigProvider; import org.apache.cassandra.sidecar.common.response.NodeSettings; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.coordination.CassandraClientTokenRingProvider; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; -import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.apache.cassandra.spark.data.partitioner.CassandraInstance; import org.apache.cassandra.spark.data.partitioner.Partitioner; @@ -47,10 +47,12 @@ public class SidecarClusterConfigProvider implements ClusterConfigProvider { private final InstanceMetadataFetcher instanceMetadataFetcher; + private final DriverUtils driverUtils; - public SidecarClusterConfigProvider(InstanceMetadataFetcher instanceMetadataFetcher) + public SidecarClusterConfigProvider(InstanceMetadataFetcher instanceMetadataFetcher, DriverUtils driverUtils) { this.instanceMetadataFetcher = instanceMetadataFetcher; + this.driverUtils = driverUtils; } public String dc() @@ -69,7 +71,7 @@ public Set getCluster() .flatMap(host -> tokenMap.getTokens(host).stream() .map(token -> new CassandraInstance( CassandraClientTokenRingProvider.tokenToString(token), - MetadataUtils.resolveEndpoint(host).getHostName(), + driverUtils.getSocketAddress(host).getHostName(), host.getDatacenter() )) ).collect(Collectors.toSet()); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java index 04e606812..1df3232da 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java @@ -19,6 +19,7 @@ package org.apache.cassandra.sidecar.cluster.driver; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -29,6 +30,7 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.google.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +41,6 @@ import com.datastax.oss.driver.api.core.session.Request; import com.datastax.oss.driver.api.core.session.Session; import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy; -import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.jetbrains.annotations.NotNull; /** @@ -120,7 +121,7 @@ public synchronized void onUp(@NotNull Node node) public synchronized void onDown(@NotNull Node node) { // Don't remove local addresses from the selected host list - if (localHostAddresses.contains(MetadataUtils.resolveEndpoint(node))) + if (localHostAddresses.contains(resolveEndpoint(node))) { LOGGER.debug("Local Node {} has been marked down.", node); return; @@ -198,6 +199,13 @@ private synchronized void recalculateSelectedHosts() private boolean isLocalHost(Node host) { - return localHostAddresses.contains(MetadataUtils.resolveEndpoint(host)); + return localHostAddresses.contains(resolveEndpoint(host)); + } + + private static InetSocketAddress resolveEndpoint(Node node) + { + SocketAddress socketAddress = node.getEndPoint().resolve(); + Preconditions.checkState(socketAddress instanceof InetSocketAddress, "Unsupported endpoint type: " + node.getEndPoint()); + return (InetSocketAddress) socketAddress; } } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java index 09e7c7964..8de90afe2 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/locator/CachedLocalTokenRanges.java @@ -46,8 +46,8 @@ import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException; -import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.jetbrains.annotations.NotNull; /** @@ -59,6 +59,7 @@ public class CachedLocalTokenRanges implements LocalTokenRangesProvider private static final Logger LOGGER = LoggerFactory.getLogger(CachedLocalTokenRanges.class); private final InstancesMetadata instancesMetadata; private final DnsResolver dnsResolver; + private final DriverUtils driverUtils; @GuardedBy("this") private Set localInstanceIdsCache; @@ -69,10 +70,11 @@ public class CachedLocalTokenRanges implements LocalTokenRangesProvider @GuardedBy("this") private ImmutableMap>> localTokenRangesCache; - public CachedLocalTokenRanges(InstancesMetadata instancesMetadata, DnsResolver dnsResolver) + public CachedLocalTokenRanges(InstancesMetadata instancesMetadata, DnsResolver dnsResolver, DriverUtils driverUtils) { this.instancesMetadata = instancesMetadata; this.dnsResolver = dnsResolver; + this.driverUtils = driverUtils; this.localTokenRangesCache = null; this.localInstanceIdsCache = null; this.allInstancesCache = null; @@ -190,7 +192,7 @@ private synchronized Map> getCacheOrReload(Metadata met }; for (Node host : allInstancesCache) { - putNullSafe.accept(MetadataUtils.resolveEndpoint(host), host); + putNullSafe.accept(driverUtils.getSocketAddress(host), host); putNullSafe.accept(host.getListenAddress().orElse(null), host); putNullSafe.accept(host.getBroadcastAddress().orElse(null), host); } diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java index 97f8fc9b0..9b0f28374 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java @@ -57,6 +57,7 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.Partitioners; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; @@ -68,6 +69,7 @@ public class CassandraClientTokenRingProvider extends TokenRingProvider implements LocalTokenRangesProvider { private static final Logger LOGGER = LoggerFactory.getLogger(CassandraClientTokenRingProvider.class); + private final DriverUtils driverUtils; @GuardedBy("this") private volatile Map>> assignedRangesOfAllInstancesByDcCache = null; @GuardedBy("this") @@ -76,9 +78,13 @@ public class CassandraClientTokenRingProvider extends TokenRingProvider implemen private volatile Set allInstancesCache = null; @Inject - public CassandraClientTokenRingProvider(InstancesMetadata instancesMetadata, InstanceMetadataFetcher instanceMetadataFetcher, DnsResolver dnsResolver) + public CassandraClientTokenRingProvider(InstancesMetadata instancesMetadata, + InstanceMetadataFetcher instanceMetadataFetcher, + DnsResolver dnsResolver, + DriverUtils driverUtils) { - super(instancesMetadata, instanceMetadataFetcher, dnsResolver); + super(instancesMetadata, instanceMetadataFetcher, dnsResolver, driverUtils); + this.driverUtils = driverUtils; } @Override @@ -183,11 +189,13 @@ private boolean matchesSidecar(String hostIp, SidecarInstance sidecarInstance) public Map>> assignedRangesOfAllInstancesByDc(Metadata metadata) { - return assignedRangesOfAllInstancesByDc(dnsResolver, metadata); + return assignedRangesOfAllInstancesByDc(dnsResolver, driverUtils, metadata); } @VisibleForTesting - public static Map>> assignedRangesOfAllInstancesByDc(DnsResolver dnsResolver, Metadata metadata) + public static Map>> assignedRangesOfAllInstancesByDc(DnsResolver dnsResolver, + DriverUtils driverUtils, + Metadata metadata) { Partitioner partitioner = extractPartitioner(metadata); Map> perDcHosts = new HashMap<>(4); @@ -196,7 +204,7 @@ public static Map>> assignedRangesOfAllInst Token minToken = metadata.getTokenMap().get().getTokens(host).stream().min(Comparable::compareTo) .orElseThrow(() -> new RuntimeException("No token found for host: " + host)); perDcHosts.computeIfAbsent(host.getDatacenter(), (dc) -> new ArrayList<>()) - .add(new CassandraInstance(tokenToString(minToken), getIpFromHost(dnsResolver, host))); + .add(new CassandraInstance(tokenToString(minToken), getIpFromHost(dnsResolver, driverUtils, host))); } perDcHosts.forEach((dc, hosts) -> hosts.sort(Comparator.comparing(o -> new BigInteger(o.token)))); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java index bd6747aea..1ac911e3e 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/TokenRingProvider.java @@ -39,8 +39,8 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.Partitioners; import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; -import org.apache.cassandra.sidecar.utils.MetadataUtils; import org.jetbrains.annotations.Nullable; /** @@ -52,12 +52,15 @@ public abstract class TokenRingProvider protected final InstancesMetadata instancesMetadata; protected final InstanceMetadataFetcher fetcher; protected final DnsResolver dnsResolver; + protected final DriverUtils driverUtils; - public TokenRingProvider(InstancesMetadata instancesMetadata, InstanceMetadataFetcher fetcher, DnsResolver dnsResolver) + public TokenRingProvider(InstancesMetadata instancesMetadata, InstanceMetadataFetcher fetcher, + DnsResolver dnsResolver, DriverUtils driverUtils) { this.instancesMetadata = instancesMetadata; this.fetcher = fetcher; this.dnsResolver = dnsResolver; + this.driverUtils = driverUtils; } /** @@ -131,16 +134,16 @@ public Partitioner partitioner() protected String getIpFromHost(Node host) { - return getIpFromHost(dnsResolver, host); + return getIpFromHost(dnsResolver, driverUtils, host); } - protected static String getIpFromHost(DnsResolver dnsResolver, Node host) + protected static String getIpFromHost(DnsResolver dnsResolver, DriverUtils driverUtils, Node host) { // if the IP address is already resolved for the host (it generally should be), use it. // this also avoids the case where the driver connects to the local node with an IPv6 or IPv4 address and is // able to resolve its host name, we want to avoid attempting to resolve by host name here in the event // that the configured DNS resolver resolves the wrong IP class for the configured node. - @SuppressWarnings("deprecation") InetAddress address = MetadataUtils.resolveEndpoint(host).getAddress(); + @SuppressWarnings("deprecation") InetAddress address = driverUtils.getSocketAddress(host).getAddress(); String hostAddress = address.getHostAddress(); if (hostAddress != null) { diff --git a/server/src/main/java/org/apache/cassandra/sidecar/modules/CdcModule.java b/server/src/main/java/org/apache/cassandra/sidecar/modules/CdcModule.java index ddf094f9c..0ff5d67ee 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/modules/CdcModule.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/modules/CdcModule.java @@ -54,6 +54,7 @@ import org.apache.cassandra.sidecar.common.request.data.AllServicesConfigPayload; import org.apache.cassandra.sidecar.common.response.ListCdcSegmentsResponse; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.concurrent.ExecutorPools; import org.apache.cassandra.sidecar.config.ServiceConfiguration; import org.apache.cassandra.sidecar.config.SidecarClientConfiguration; @@ -346,9 +347,10 @@ public SchemaSupplier schemaSupplier(InstanceMetadataFetcher instanceMetadataFet @Provides @Singleton - public ClusterConfigProvider clusterConfigProvider(InstanceMetadataFetcher instanceMetadataFetcher) + public ClusterConfigProvider clusterConfigProvider(InstanceMetadataFetcher instanceMetadataFetcher, + DriverUtils driverUtils) { - return new SidecarClusterConfigProvider(instanceMetadataFetcher); + return new SidecarClusterConfigProvider(instanceMetadataFetcher, driverUtils); } @Provides @@ -362,9 +364,10 @@ public ICdcStats cdcStats() @Provides @Singleton - public TokenRingProvider tokenRingProvider(InstancesMetadata instancesMetadata, InstanceMetadataFetcher instanceMetadataFetcher, DnsResolver dnsResolver) + public TokenRingProvider tokenRingProvider(InstancesMetadata instancesMetadata, InstanceMetadataFetcher instanceMetadataFetcher, + DnsResolver dnsResolver, DriverUtils driverUtils) { - return new CassandraClientTokenRingProvider(instancesMetadata, instanceMetadataFetcher, dnsResolver); + return new CassandraClientTokenRingProvider(instancesMetadata, instanceMetadataFetcher, dnsResolver, driverUtils); } @Provides diff --git a/server/src/main/java/org/apache/cassandra/sidecar/modules/RestoreJobModule.java b/server/src/main/java/org/apache/cassandra/sidecar/modules/RestoreJobModule.java index 88377d17c..3fa2d6e6b 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/modules/RestoreJobModule.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/modules/RestoreJobModule.java @@ -35,6 +35,7 @@ import org.apache.cassandra.sidecar.common.response.data.RestoreJobProgressResponsePayload; import org.apache.cassandra.sidecar.common.response.data.RestoreJobSummaryResponsePayload; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.config.SidecarConfiguration; import org.apache.cassandra.sidecar.db.schema.RestoreJobsSchema; import org.apache.cassandra.sidecar.db.schema.RestoreRangesSchema; @@ -85,9 +86,9 @@ protected void configure() @Provides @Singleton - LocalTokenRangesProvider localTokenRangesProvider(InstancesMetadata instancesMetadata, DnsResolver dnsResolver) + LocalTokenRangesProvider localTokenRangesProvider(InstancesMetadata instancesMetadata, DnsResolver dnsResolver, DriverUtils driverUtils) { - return new CachedLocalTokenRanges(instancesMetadata, dnsResolver); + return new CachedLocalTokenRanges(instancesMetadata, dnsResolver, driverUtils); } @ProvidesIntoMap diff --git a/server/src/main/java/org/apache/cassandra/sidecar/utils/MetadataUtils.java b/server/src/main/java/org/apache/cassandra/sidecar/utils/MetadataUtils.java index 2f146823c..c6270e16e 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/utils/MetadataUtils.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/utils/MetadataUtils.java @@ -17,13 +17,7 @@ */ package org.apache.cassandra.sidecar.utils; -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -import com.google.common.base.Preconditions; - import com.datastax.oss.driver.api.core.metadata.Metadata; -import com.datastax.oss.driver.api.core.metadata.Node; 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.internal.core.util.Strings; @@ -73,12 +67,4 @@ public static String describe(Metadata metadata) }); return builder.toString(); } - - // TODO(lantoniak): Move to driver utils? - public static InetSocketAddress resolveEndpoint(Node node) - { - SocketAddress socketAddress = node.getEndPoint().resolve(); - Preconditions.checkState(socketAddress instanceof InetSocketAddress, "Unsupported endpoint type: " + node.getEndPoint()); - return (InetSocketAddress) socketAddress; - } } diff --git a/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java b/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java index 58cbf6d9a..747c1963c 100644 --- a/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java +++ b/server/src/test/integration/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicyTest.java @@ -83,8 +83,8 @@ private void assertConnectionsWithRetry(InetSocketAddress downInstanceAddress, i { List connectedHosts = Collections.emptyList(); int attempts = 0; - // Retry for up to 2 minutes, but passes much more quickly most of the time, so this should be safe. - while (attempts <= 24) + // Retry for up to 3 minutes, but passes much more quickly most of the time, so this should be safe. + while (attempts <= 36) { Collection hosts = sidecarTestContext.session().getMetadata().getNodes().values(); connectedHosts = getConnectedHosts(hosts); diff --git a/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java b/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java index 784afe26c..aba9fc021 100644 --- a/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java +++ b/server/src/test/java/org/apache/cassandra/sidecar/cluster/CassandraClientTokenRingProviderTest.java @@ -51,6 +51,7 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; +import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; import org.apache.cassandra.sidecar.coordination.CassandraClientTokenRingProvider; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; import org.apache.cassandra.sidecar.utils.SimpleCassandraVersion; @@ -72,11 +73,13 @@ public class CassandraClientTokenRingProviderTest { private final CassandraClientTokenRingProvider tokenRingProvider = new CassandraClientTokenRingProvider(mockInstancesMetadata(), mockInstanceMetadataFetcher(), - mockDnsResolver()); + mockDnsResolver(), + new DriverUtils()); @Test public void testPrimaryRangesOfAllInstancesByDc() { + DriverUtils driverUtils = new DriverUtils(); Metadata metadata = mock(Metadata.class); TokenMap tokenMap = mock(TokenMap.class); when(tokenMap.getPartitionerName()).thenReturn(Partitioners.MURMUR3.name()); @@ -235,7 +238,8 @@ public String reverseResolve(String s) return nodeTokens.get(n); }); - Map>> tokens = CassandraClientTokenRingProvider.assignedRangesOfAllInstancesByDc(dnsResolver, metadata); + Map>> tokens = CassandraClientTokenRingProvider + .assignedRangesOfAllInstancesByDc(dnsResolver, driverUtils, metadata); assertFalse(tokens.isEmpty()); assertTrue(tokens.containsKey("DC1")); assertTrue(tokens.containsKey("DC2")); From c8d1ecd1ebae811ce6a0cbb41e8c9f0abe93cb11 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Thu, 16 Apr 2026 11:38:47 +0200 Subject: [PATCH 4/4] Tests --- .../SharedClusterIntegrationTestBase.java | 3 +- .../cassandra/testing/TlsTestUtils.java | 2 +- .../common/server/utils/TokenUtils.java | 47 +++++++++++++++++++ .../cdc/SidecarClusterConfigProvider.java | 4 +- .../cluster/CassandraAdapterDelegate.java | 11 +++-- .../cluster/driver/CustomDriverOption.java | 9 +++- .../driver/MultiplexingNodeStateListener.java | 2 +- .../driver/SidecarLoadBalancingPolicy.java | 4 +- .../CassandraClientTokenRingProvider.java | 20 +------- .../InnerDcTokenAdjacentPeerProvider.java | 21 +-------- .../TableToSchemaMetadataConverter.java | 4 +- 11 files changed, 76 insertions(+), 51 deletions(-) create mode 100644 server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/TokenUtils.java diff --git a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java index 43a3f3f75..f7427f9e4 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java +++ b/integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java @@ -733,7 +733,8 @@ public IntegrationTestModule(Iterable instances, public CQLSessionProvider cqlSessionProvider() { List contactPoints = buildContactPoints(instances); - return new TemporaryCqlSessionProvider(contactPoints, "datacenter1", null); + IInstance instance = instances.iterator().next(); + return new TemporaryCqlSessionProvider(contactPoints, instance.config().localDatacenter(), null); } @Provides diff --git a/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java b/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java index 601e24438..2b10bce33 100644 --- a/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java +++ b/integration-framework/src/main/java/org/apache/cassandra/testing/TlsTestUtils.java @@ -79,7 +79,7 @@ public static void withAuthenticatedSession(IInstance instance, CqlSessionBuilder builder = CqlSession.builder() .withSslContext(sslOptions) .withAuthCredentials(username, password) - .withLocalDatacenter("datacenter1") + .withLocalDatacenter(instance.config().localDatacenter()) .addContactPoint(nativeInetSocketAddress); if (builderCustomizer != null) diff --git a/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/TokenUtils.java b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/TokenUtils.java new file mode 100644 index 000000000..6c6344d33 --- /dev/null +++ b/server-common/src/main/java/org/apache/cassandra/sidecar/common/server/utils/TokenUtils.java @@ -0,0 +1,47 @@ +/* + * 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 org.apache.cassandra.sidecar.common.server.utils; + +import java.math.BigInteger; + +import com.datastax.oss.driver.api.core.metadata.token.Token; +import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; +import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; + +/** + * Token utility functions. + */ +public class TokenUtils +{ + public static BigInteger tokenToBigInteger(Token token) + { + if (token instanceof RandomToken) // BigInteger - RandomPartitioner + { + RandomToken t = (RandomToken) token; + return t.getValue(); + } + else if (token instanceof Murmur3Token) // Long - Murmur3Partitioner + { + Murmur3Token t = (Murmur3Token) token; + return BigInteger.valueOf(t.getValue()); + } + throw new IllegalArgumentException("Unsupported token type: " + token.getClass().getName() + + ". Only tokens of Murmur3Partitioner and RandomPartitioner are supported."); + } +} diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java index b899e9991..6d4fa6387 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/SidecarClusterConfigProvider.java @@ -29,7 +29,7 @@ import org.apache.cassandra.cdc.sidecar.ClusterConfigProvider; import org.apache.cassandra.sidecar.common.response.NodeSettings; import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; -import org.apache.cassandra.sidecar.coordination.CassandraClientTokenRingProvider; +import org.apache.cassandra.sidecar.common.server.utils.TokenUtils; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; import org.apache.cassandra.spark.data.partitioner.CassandraInstance; import org.apache.cassandra.spark.data.partitioner.Partitioner; @@ -70,7 +70,7 @@ public Set getCluster() .filter(host -> host.getListenAddress().isPresent()) .flatMap(host -> tokenMap.getTokens(host).stream() .map(token -> new CassandraInstance( - CassandraClientTokenRingProvider.tokenToString(token), + TokenUtils.tokenToBigInteger(token).toString(), driverUtils.getSocketAddress(host).getHostName(), host.getDatacenter() )) diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java index 776a71437..f0a9407e3 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/CassandraAdapterDelegate.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Function; @@ -92,6 +94,7 @@ public class CassandraAdapterDelegate implements ICassandraAdapter, NodeStateListener, Consumer { private static final Logger LOGGER = LoggerFactory.getLogger(CassandraAdapterDelegate.class); + private static final ExecutorService eventExecutor = Executors.newFixedThreadPool(1); private final Vertx vertx; private final int cassandraInstanceId; @@ -491,28 +494,28 @@ public void accept(ChannelEvent channelEvent) public void onAdd(@NotNull Node host) { LOGGER.debug("Host added. host={}", host); - CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck)); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck), eventExecutor); } @Override public void onUp(@NotNull Node host) { LOGGER.debug("Host up. host={}", host); - CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck)); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck), eventExecutor); } @Override public void onDown(@NotNull Node host) { LOGGER.debug("Host down. host={}", host); - CompletableFuture.runAsync(() -> runIfThisHost(host, this::markNativeDownAndMaybeNotifyDisconnection)); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::markNativeDownAndMaybeNotifyDisconnection), eventExecutor); } @Override public void onRemove(@NotNull Node host) { LOGGER.debug("Host removed. host={}", host); - CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck)); + CompletableFuture.runAsync(() -> runIfThisHost(host, this::healthCheck), eventExecutor); } /** diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java index cd656d277..780b92479 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/CustomDriverOption.java @@ -22,11 +22,18 @@ import org.jspecify.annotations.NonNull; /** - * Custom driver options required by {@code SidecarLoadBalancingPolicy}. + * Custom driver options required by {@link SidecarLoadBalancingPolicy}. */ public enum CustomDriverOption implements DriverOption { + /** + * Number of non-localhost Cassandra connections to be maintained by the Sidecar. + */ NUM_CONNECTIONS("basic.load-balancing-policy.num-connections"), + + /** + * Comma-separated list of local Cassandra instances in the format of {@code host:port}. + */ LOCAL_INSTANCES("basic.load-balancing-policy.local-instances"); private final String path; diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java index b2c751e8b..e02cd4317 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/MultiplexingNodeStateListener.java @@ -35,7 +35,7 @@ /** * Combines multiple node state listeners into a single one. - * Implementation note: Copied from Java driver, but with unregistering functionality. + * Implementation note: copied from Java driver, but added functionality to unregister the listener. * *

    Any exception thrown by a child listener is caught and logged. */ diff --git a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java index 1df3232da..2ebf0a0f6 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/cluster/driver/SidecarLoadBalancingPolicy.java @@ -20,12 +20,12 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.security.SecureRandom; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -52,7 +52,7 @@ public class SidecarLoadBalancingPolicy extends DefaultLoadBalancingPolicy { public static final int MIN_NON_LOCAL_CONNECTIONS = 2; private static final Logger LOGGER = LoggerFactory.getLogger(SidecarLoadBalancingPolicy.class); - private final Random random = new Random(); + private final SecureRandom random = new SecureRandom(); private final Set localHostAddresses; private final HashSet allHosts = new HashSet<>(); diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java index 9b0f28374..74d6fa5d8 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/CassandraClientTokenRingProvider.java @@ -45,8 +45,6 @@ import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; import com.datastax.oss.driver.api.core.metadata.token.Token; -import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; -import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.client.SidecarInstance; @@ -58,6 +56,7 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; +import org.apache.cassandra.sidecar.common.server.utils.TokenUtils; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; @@ -204,7 +203,7 @@ public static Map>> assignedRangesOfAllInst Token minToken = metadata.getTokenMap().get().getTokens(host).stream().min(Comparable::compareTo) .orElseThrow(() -> new RuntimeException("No token found for host: " + host)); perDcHosts.computeIfAbsent(host.getDatacenter(), (dc) -> new ArrayList<>()) - .add(new CassandraInstance(tokenToString(minToken), getIpFromHost(dnsResolver, driverUtils, host))); + .add(new CassandraInstance(TokenUtils.tokenToBigInteger(minToken).toString(), getIpFromHost(dnsResolver, driverUtils, host))); } perDcHosts.forEach((dc, hosts) -> hosts.sort(Comparator.comparing(o -> new BigInteger(o.token)))); @@ -212,21 +211,6 @@ public static Map>> assignedRangesOfAllInst .collect(Collectors.toMap(Map.Entry::getKey, e -> calculateTokenRanges(partitioner, e.getValue()))); } - public static String tokenToString(Token token) - { - if (token instanceof Murmur3Token) - { - Murmur3Token t = (Murmur3Token) token; - return Long.toString(t.getValue()); - } - else if (token instanceof RandomToken) - { - RandomToken t = (RandomToken) token; - return t.getValue().toString(); - } - throw new UnsupportedOperationException("Unsupported token type: " + token.getClass().getName()); - } - protected static Map> calculateTokenRanges(Partitioner partitioner, List sortedPerDcHosts) { // RingTopologyRefresher.calculate... diff --git a/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java b/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java index 22dfc37a8..6aa48062f 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/coordination/InnerDcTokenAdjacentPeerProvider.java @@ -41,8 +41,6 @@ import com.datastax.oss.driver.api.core.metadata.Node; import com.datastax.oss.driver.api.core.metadata.TokenMap; import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; -import com.datastax.oss.driver.internal.core.metadata.token.Murmur3Token; -import com.datastax.oss.driver.internal.core.metadata.token.RandomToken; import com.google.inject.Inject; import com.google.inject.Singleton; import org.apache.cassandra.sidecar.client.SidecarInstance; @@ -51,6 +49,7 @@ import org.apache.cassandra.sidecar.common.server.cluster.locator.TokenRange; import org.apache.cassandra.sidecar.common.server.dns.DnsResolver; import org.apache.cassandra.sidecar.common.server.utils.DriverUtils; +import org.apache.cassandra.sidecar.common.server.utils.TokenUtils; import org.apache.cassandra.sidecar.common.utils.Preconditions; import org.apache.cassandra.sidecar.config.ServiceConfiguration; import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; @@ -174,27 +173,11 @@ public static BigInteger minToken(TokenMap tokenMap, Node host) { return tokenMap.getTokens(host) .stream() - .map(InnerDcTokenAdjacentPeerProvider::tokenToBigInteger) + .map(TokenUtils::tokenToBigInteger) .min(BigInteger::compareTo) .orElseThrow(() -> new RuntimeException("No min token found on host: " + host.getHostId())); } - public static BigInteger tokenToBigInteger(com.datastax.oss.driver.api.core.metadata.token.Token token) - { - if (token instanceof RandomToken) // BigInteger - RandomPartitioner - { - RandomToken t = (RandomToken) token; - return t.getValue(); - } - else if (token instanceof Murmur3Token) // Long - Murmur3Partitioner - { - Murmur3Token t = (Murmur3Token) token; - return BigInteger.valueOf(t.getValue()); - } - throw new IllegalArgumentException("Unsupported token type: " + token.getClass().getName() + - ". Only tokens of Murmur3Partitioner and RandomPartitioner are supported."); - } - protected static BigInteger minToken(Stream tokenRanges) { return tokenRanges diff --git a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java index d229b93b2..93f60a96b 100644 --- a/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java +++ b/server/src/main/java/org/apache/cassandra/sidecar/datahub/TableToSchemaMetadataConverter.java @@ -180,7 +180,7 @@ protected Stream convertType(@NotNull String name, { SchemaFieldDataType datahubType = convertType(type); String description = datahubType.getType().isNullType() - ? "Unknown Cassandra data type " + type.asCql(true, true) + ? "Unknown Cassandra data type " + type.asCql(true, true).toLowerCase() : null; // Column-level comments are not supported by Cassandra return Stream.of(new SchemaField() @@ -188,7 +188,7 @@ protected Stream convertType(@NotNull String name, .setNullable(!partition) // Everything is potentially nullable in Cassandra except for the partition key .setDescription(description, SetMode.REMOVE_IF_NULL) .setType(datahubType) - .setNativeDataType(type.asCql(true, true)) + .setNativeDataType(type.asCql(true, true).toLowerCase()) .setIsPartitioningKey(partition) .setIsPartOfKey(key)); }