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

bbejeck pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 9ffc78db8a8 KAFKA-20760: Fix ClassCastException in 
KeyValueToTimestampedKeyValueByteStoreAdapter (#22742)
9ffc78db8a8 is described below

commit 9ffc78db8a802b90f3392723d3170767b092aba7
Author: Nick Telford <[email protected]>
AuthorDate: Fri Jul 3 01:47:51 2026 +0100

    KAFKA-20760: Fix ClassCastException in 
KeyValueToTimestampedKeyValueByteStoreAdapter (#22742)
    
    IQv2 range queries throw a `ClassCastException` when the underlying
    state store is not RocksDB (e.g. an in-memory store), because
    `KeyValueToTimestampedKeyValueByteStoreAdapter` unconditionally cast the
    query iterator result to `RocksDbIterator` before wrapping it. With a
    transactional store the result is a `StagedMergeIterator`, so the cast
    fails.
    
    The adapter exists only to convert plain key/value bytes into the
    timestamped format for any key-value store, so coupling its inner
    iterator to a specific store implementation is unnecessary. Widening the
    field and constructor parameter to `ManagedKeyValueIterator<Bytes,
    byte[]>` — the interface every store iterator already implements —
    removes the erroneous cast and makes the adapter work regardless of the
    underlying store type.
    
    Part of a series of fixes for interactive-query position consistency
    with transactional state stores.
    
    Reviewers: Bill Bejeck <[email protected]>
    
    Co-authored-by: Bill Bejeck <[email protected]>
---
 ...eyValueToTimestampedKeyValueByteStoreAdapter.java | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git 
a/streams/src/main/java/org/apache/kafka/streams/state/internals/KeyValueToTimestampedKeyValueByteStoreAdapter.java
 
b/streams/src/main/java/org/apache/kafka/streams/state/internals/KeyValueToTimestampedKeyValueByteStoreAdapter.java
index 5c5ededb8b4..406823a026a 100644
--- 
a/streams/src/main/java/org/apache/kafka/streams/state/internals/KeyValueToTimestampedKeyValueByteStoreAdapter.java
+++ 
b/streams/src/main/java/org/apache/kafka/streams/state/internals/KeyValueToTimestampedKeyValueByteStoreAdapter.java
@@ -156,8 +156,8 @@ public class KeyValueToTimestampedKeyValueByteStoreAdapter 
implements KeyValueSt
                 final byte[] valueWithTimestamp = 
convertToTimestampedFormat(plainValue);
                 result = (QueryResult<R>) 
InternalQueryResultUtil.copyAndSubstituteDeserializedResult(result, 
valueWithTimestamp);
             } else if (query instanceof RangeQuery || query instanceof 
TimestampedRangeQuery) {
-                final KeyValueToTimestampedKeyValueAdapterIterator 
wrappedRocksDBRangeIterator = new 
KeyValueToTimestampedKeyValueAdapterIterator((RocksDbIterator) 
result.getResult());
-                result = (QueryResult<R>) 
InternalQueryResultUtil.copyAndSubstituteDeserializedResult(result, 
wrappedRocksDBRangeIterator);
+                final KeyValueToTimestampedKeyValueAdapterIterator 
wrappedIterator = new 
KeyValueToTimestampedKeyValueAdapterIterator((ManagedKeyValueIterator<Bytes, 
byte[]>) result.getResult());
+                result = (QueryResult<R>) 
InternalQueryResultUtil.copyAndSubstituteDeserializedResult(result, 
wrappedIterator);
             } else {
                 throw new IllegalArgumentException("Unsupported query type: " 
+ query.getClass());
             }
@@ -218,35 +218,35 @@ public class 
KeyValueToTimestampedKeyValueByteStoreAdapter implements KeyValueSt
 
     private static class KeyValueToTimestampedKeyValueAdapterIterator 
implements ManagedKeyValueIterator<Bytes, byte[]> {
 
-        private final RocksDbIterator rocksDbIterator;
+        private final ManagedKeyValueIterator<Bytes, byte[]> iterator;
 
-        public KeyValueToTimestampedKeyValueAdapterIterator(final 
RocksDbIterator rocksDbIterator) {
-            this.rocksDbIterator = rocksDbIterator;
+        public KeyValueToTimestampedKeyValueAdapterIterator(final 
ManagedKeyValueIterator<Bytes, byte[]> iterator) {
+            this.iterator = iterator;
         }
 
         @Override
         public void close() {
-            rocksDbIterator.close();
+            iterator.close();
         }
 
         @Override
         public Bytes peekNextKey() {
-            return rocksDbIterator.peekNextKey();
+            return iterator.peekNextKey();
         }
 
         @Override
         public void onClose(final Runnable closeCallback) {
-            rocksDbIterator.onClose(closeCallback);
+            iterator.onClose(closeCallback);
         }
 
         @Override
         public boolean hasNext() {
-            return rocksDbIterator.hasNext();
+            return iterator.hasNext();
         }
 
         @Override
         public KeyValue<Bytes, byte[]> next() {
-            final KeyValue<Bytes, byte[]> next = rocksDbIterator.next();
+            final KeyValue<Bytes, byte[]> next = iterator.next();
             if (next == null) {
                 return null;
             }

Reply via email to