aliehsaeedii commented on code in PR #22666:
URL: https://github.com/apache/kafka/pull/22666#discussion_r3510830502


##########
streams/src/main/java/org/apache/kafka/streams/state/internals/MeteredTimestampedKeyValueStoreWithHeaders.java:
##########
@@ -381,6 +385,67 @@ private <R> QueryResult<R> runTimestampedKeyQuery(
         return result;
     }
 
+    @SuppressWarnings("unchecked")
+    private <R> QueryResult<R> runTimestampedKeyWithHeadersQuery(
+        final Query<R> query,
+        final PositionBound positionBound,
+        final QueryConfig config
+    ) {
+        final QueryResult<R> result;
+        final TimestampedKeyWithHeadersQuery<K, V> typedKeyQuery = 
(TimestampedKeyWithHeadersQuery<K, V>) query;
+
+        // Forward a raw byte-level KeyQuery to the wrapped store, propagating 
skipCache so the caching
+        // layer can honor it; the result bytes are the serialized 
ValueTimestampHeaders, which we
+        // deserialize below to recover value, timestamp, and headers.
+        KeyQuery<Bytes, byte[]> rawKeyQuery = 
KeyQuery.withKey(serializeKey(typedKeyQuery.key(), internalContext.headers()));
+        if (typedKeyQuery.isSkipCache()) {
+            rawKeyQuery = rawKeyQuery.skipCache();
+        }
+        final QueryResult<byte[]> rawResult = wrapped().query(rawKeyQuery, 
positionBound, config);
+        if (rawResult.isSuccess()) {
+            final Function<byte[], ValueTimestampHeaders<V>> deserializer = 
StoreQueryUtils.deserializeValue(serdes, wrapped());
+            final ValueTimestampHeaders<V> valueTimestampHeaders = 
deserializer.apply(rawResult.getResult());
+            if (valueTimestampHeaders != null && 
valueTimestampHeaders.timestamp() < 0) {
+                // The result is modeled as a Record, whose constructor 
rejects negative timestamps. A
+                // negative stored timestamp cannot arise from the normal 
record-driven flow (the PAPI
+                // Record a processor stores already forbids it), so it 
indicates corrupted/unexpected
+                // store state; surface it as a failed result rather than 
letting `new Record<>` throw
+                // out of query().
+                final QueryResult<ReadOnlyRecord<K, V>> failure = 
QueryResult.forFailure(
+                    FailureReason.STORE_EXCEPTION,
+                    "Stored record for the queried key has a negative 
timestamp ("
+                        + valueTimestampHeaders.timestamp() + "); cannot 
construct a ReadOnlyRecord.");
+                failure.setPosition(rawResult.getPosition());

Review Comment:
   Minor/observability: the negative-timestamp failure builds a fresh 
`QueryResult.forFailure(...)` and copies only the position. Every other exit of 
this handler preserves the wrapped store's execution info — the success path 
via `copyAndSubstituteDeserializedResult` (which copies 
`rawResult.getExecutionInfo()`), and the `else` branch that returns `rawResult` 
directly. So when `collectExecutionInfo` is enabled, this one failure path 
silently drops the `"Handled in ..."` execution info that all sibling paths 
keep. Consider copying `rawResult.getExecutionInfo()` onto `failure` (and/or 
adding a note) for parity. Also worth noting: 
`shouldCollectExecutionInfoWhenRequested` exercises a raw `KeyQuery` on the 
wrapped store, not the typed `TimestampedKeyWithHeadersQuery` through the 
metered handler, so neither the success nor this failure exec-info behavior of 
the new query type is covered by a test.



##########
streams/src/main/java/org/apache/kafka/streams/state/internals/RocksDBTimestampedStoreWithHeaders.java:
##########
@@ -194,25 +190,4 @@ private void openFromTimestampedStore(final DBOptions 
dbOptions,
         }
     }
 
-    @SuppressWarnings("SynchronizeOnNonFinalField")
-    @Override
-    public <R> QueryResult<R> query(final Query<R> query,
-                                    final PositionBound positionBound,
-                                    final QueryConfig config) {
-        final long start = config.isCollectExecutionInfo() ? System.nanoTime() 
: -1L;
-        final QueryResult<R> result;
-
-        synchronized (position) {
-            result = QueryResult.forUnknownQueryType(query, this);
-
-            if (config.isCollectExecutionInfo()) {
-                result.addExecutionInfo(
-                    "Handled in " + this.getClass() + " in " + 
(System.nanoTime() - start) + "ns"
-                );
-            }
-            result.setPosition(position.copy());
-        }
-        return result;
-    }
-
-}
\ No newline at end of file
+}

Review Comment:
   Have you checked which queries’ behavior changes when this method is 
removed? The range query is affected (first thing comes to my mind- please 
check other q types as well), which doesn’t seem correct, since this PR is only 
adding key queries.



##########
streams/src/test/java/org/apache/kafka/streams/state/internals/TimestampedKeyValueStoreBuilderWithHeadersTest.java:
##########
@@ -586,247 +431,108 @@ public void 
shouldReturnUnknownQueryTypeForKeyQueryOnHeadersStore(final boolean
 
     @ParameterizedTest
     @ValueSource(booleans = {true, false})
-    public void shouldReturnUnknownQueryTypeForRangeQueryOnHeadersStore(final 
boolean cachingEnabled) {

Review Comment:
   Why did you delete this test? Nothing should be changed about `RangeQuery` 
in this PR as it is only introducing key query.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to