This is an automated email from the ASF dual-hosted git repository.

jyothsnakonisa pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git


The following commit(s) were added to refs/heads/trunk by this push:
     new f8fee7b91 CASSSIDECAR-492: CDC log_only mode should not require Kafka 
producer … (#389)
f8fee7b91 is described below

commit f8fee7b91c3e64725d467124b13de88fbb3afe9f
Author: Shruti Sekaran <[email protected]>
AuthorDate: Fri Oct 9 18:30:43 2026 -0700

    CASSSIDECAR-492: CDC log_only mode should not require Kafka producer … 
(#389)
    
    Patch by Shruti Sekaran; reviewed by Jyothsna Konisa, Bernardo Botella, 
Yifan Cai for CASSSIDECAR-492
---
 CHANGES.txt                                        |  1 +
 README.md                                          |  3 ++
 .../cassandra/sidecar/cdc/CdcConfigImpl.java       |  4 +--
 .../apache/cassandra/sidecar/cdc/CdcPublisher.java |  8 ++++++
 .../cassandra/sidecar/cdc/CdcConfigImplTest.java   | 32 ++++++++++++++++++++++
 .../cassandra/sidecar/cdc/CdcPublisherTests.java   | 29 +++++++++++++++++++-
 6 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index d1df53b35..28fb6f030 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 0.5.0
 -----
+ * CDC log_only mode should not require Kafka producer configuration 
(CASSSIDECAR-492)
  * Report unknown node status as "Unknown" instead of "?" in ring and token 
range replica responses (CASSSIDECAR-506)
  * Remove unused Instance Metadata Fetcher from CdcDatabaseAccessor 
(CASSSIDECAR-497)
  * Fix IPV6 regex to recognize bracketed addresses in gossip info host headers 
(CASSSIDECAR-503)
diff --git a/README.md b/README.md
index 3f4a7931d..728fc8c45 100644
--- a/README.md
+++ b/README.md
@@ -209,6 +209,9 @@ curl --request PUT \
   - `TABLE`: Format as `{topic}-{table}`
   - `MAP`: Use custom topic mapping (advanced)
 - `topic`: Base Kafka topic name for CDC events.
+- `log_only`: When `true`, CDC mutations are logged instead of published to 
Kafka, and no Kafka
+  producer configuration is required. Mutations processed in this mode are not 
published to Kafka
+  later, even after `log_only` is turned off.
 
 #### 5. Configure Kafka Producer
 
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcConfigImpl.java 
b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcConfigImpl.java
index 3e493aaa0..9f37a4dd6 100644
--- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcConfigImpl.java
+++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcConfigImpl.java
@@ -94,10 +94,8 @@ public class CdcConfigImpl implements CdcConfig
     @Override
     public boolean isConfigReady()
     {
-        kafkaConfigs();
-        cdcConfigs();
         return cdcConfigAccessor.isAvailable()
-                && !kafkaConfigMappings.isEmpty()
+                && (logOnly() || !kafkaConfigMappings.isEmpty())
                 && !cdcConfigMappings.isEmpty();
     }
 
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcPublisher.java 
b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcPublisher.java
index 5a1105405..f52cdf1fa 100644
--- a/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcPublisher.java
+++ b/server/src/main/java/org/apache/cassandra/sidecar/cdc/CdcPublisher.java
@@ -141,6 +141,14 @@ public class CdcPublisher implements 
Handler<Message<Object>>, PeriodicTask
             instanceMetadataFetcher.callOnFirstAvailableInstance(instance ->
                 instance.delegate().nodeSettings()).releaseVersion()
         ).getVersion();
+
+        if (conf.logOnly())
+        {
+            LOGGER.info("CDC log_only is set; mutations will be logged and not 
published to Kafka");
+            CdcLogMode.init(key -> 
TypeCache.get(version).getType(key.keyspace, key.type));
+            return event -> CdcLogMode.FULL.info(LOGGER, "CDC log_only", 
event, null);
+        }
+
         this.kafkaPublisher = KafkaPublisher.create(version,
                                                     buildTopicSupplier(conf),
                                                     conf.kafkaConfigs(),
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcConfigImplTest.java 
b/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcConfigImplTest.java
index c53cd08b5..379030842 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcConfigImplTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcConfigImplTest.java
@@ -141,6 +141,38 @@ class CdcConfigImplTest
         assertThat(cdcConfig.persistDelay()).isEqualTo(new 
MillisecondBoundConfiguration(5, TimeUnit.SECONDS));
     }
 
+    /**
+     * With {@code log_only} set there is no Kafka producer configuration to 
load, so readiness must
+     * not require it. Note that {@link CdcConfigImpl#isConfigReady()} has no 
production caller — it
+     * is not an enforced gate, and this pins the policy rather than any 
behaviour.
+     */
+    @Test
+    void testIsConfigReadyWithoutKafkaConfigsWhenLogOnly() throws 
InterruptedException
+    {
+        // Dedicated Vertx instance so the codec registration does not depend 
on test ordering
+        Vertx testVertx = Vertx.vertx();
+        try
+        {
+            CdcConfigAccessor cdcConfigAccessor = mockCdcConfigAccessor();
+            CdcConfigRefresherNotifierTask.ConfigMappings configMappings = new 
CdcConfigRefresherNotifierTask.ConfigMappings();
+            // Kafka mappings deliberately left empty, mirroring a broker-less 
deployment
+            configMappings.setCdcConfigMappings(Map.of("log_only", "true",
+                                                       "datacenter", "DC1"));
+
+            CdcConfigImpl cdcConfig = new CdcConfigImpl(testVertx, 
cdcConfigAccessor);
+            
testVertx.eventBus().registerDefaultCodec(CdcConfigRefresherNotifierTask.ConfigMappings.class,
 CdcConfigMappingsCodec.INSTANCE);
+            
testVertx.eventBus().publish(ON_CDC_CONFIG_MAPPINGS_CHANGED.address(), 
configMappings);
+
+            loopAssert(5, () -> assertThat(cdcConfig.logOnly()).isTrue());
+            assertThat(cdcConfig.kafkaConfigs()).isEmpty();
+            assertThat(cdcConfig.isConfigReady()).isTrue();
+        }
+        finally
+        {
+            testVertx.close();
+        }
+    }
+
     @Test
     void testConfigChanged() throws InterruptedException
     {
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcPublisherTests.java 
b/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcPublisherTests.java
index 8bf52619e..bc252960c 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcPublisherTests.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/cdc/CdcPublisherTests.java
@@ -70,6 +70,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 /**
@@ -159,6 +160,22 @@ public class CdcPublisherTests
         assertThat(result).isInstanceOf(CdcEventConsumer.class);
     }
 
+    /**
+     * Log-only must not require Kafka producer configuration, so the producer 
factory must never be
+     * reached. Asserting only the returned type would still pass if a 
producer were built and then
+     * discarded.
+     */
+    @Test
+    void testEventConsumerBuildsNoKafkaProducerWhenLogOnly()
+    {
+        setupVersionMocks();
+        when(cdcConfig.logOnly()).thenReturn(true);
+
+        cdcPublisher.eventConsumer(cdcConfig);
+
+        verifyNoInteractions(kafkaProducerFactory);
+    }
+
     /**
      * Verifies that construction captures the Cdc enabled/disabled lifecycle 
stat depending on
      * {@link CdcConfig#cdcEnabled()} at the time the {@link CdcPublisher} is 
built, mirroring the
@@ -245,6 +262,17 @@ public class CdcPublisherTests
         when(cdcConfig.failOnRecordTooLargeError()).thenReturn(false);
         when(cdcConfig.failOnKafkaError()).thenReturn(true);
 
+        setupVersionMocks();
+        
when(kafkaProducerFactory.create(any())).thenReturn(mock(KafkaProducer.class));
+    }
+
+    /**
+     * Stubs only the chain {@link CdcPublisher#eventConsumer} walks to 
resolve the Cassandra
+     * version. Kept separate from {@link #setupMocks} so that the log-only 
case can assert the
+     * Kafka producer factory was never touched, without a stubbing on it to 
explain away.
+     */
+    private void setupVersionMocks()
+    {
         InstanceMetadata mockInstance = mock(InstanceMetadata.class, 
RETURNS_DEEP_STUBS);
         
when(mockInstance.delegate().nodeSettings().releaseVersion()).thenReturn("4.1.0");
         doAnswer(invocation -> {
@@ -255,7 +283,6 @@ public class CdcPublisherTests
         CassandraBridge mockBridge = mock(CassandraBridge.class);
         when(mockBridge.getVersion()).thenReturn(CassandraVersion.FOURONE);
         when(cassandraBridgeFactory.get(anyString())).thenReturn(mockBridge);
-        
when(kafkaProducerFactory.create(any())).thenReturn(mock(KafkaProducer.class));
     }
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to