-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-20705: IQv2 TimestampedWindowKeyWithHeadersQuery for headers-aware window stores (KIP-1356) #22799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
frankvicky
merged 7 commits into
apache:trunk
from
Jess668:kip-1356-timestamped-window-key-with-headers-query
Jul 16, 2026
Merged
KAFKA-20705: IQv2 TimestampedWindowKeyWithHeadersQuery for headers-aware window stores (KIP-1356) #22799
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
22d2801
Add TimestampedWindowKeyWithHeadersQuery IQv2 query type (KIP-1356)
Jess668 499b4d6
Add tests for TimestampedWindowKeyWithHeadersQuery (KIP-1356)
Jess668 6afbdf0
Reuse inherited windowSizeMs and document window key query edge cases
Jess668 a0a0df2
Add unit tests for TimestampedWindowKeyWithHeadersQuery store handling
Jess668 92e3aae
Strengthen TimestampedWindowKeyWithHeadersQuery builder tests
Jess668 580e26c
Strengthen IQv2HeadersStoreIntegrationTest for TimestampedWindowKeyWi…
Jess668 4d4118a
add shouldReturnEmptyHeadersForTimestampedWindowKeyWithHeadersQueryOn…
Jess668 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
290 changes: 287 additions & 3 deletions
290
...s/src/test/java/org/apache/kafka/streams/integration/IQv2HeadersStoreIntegrationTest.java
Large diffs are not rendered by default.
Oops, something went wrong.
130 changes: 130 additions & 0 deletions
130
...ms/src/main/java/org/apache/kafka/streams/query/TimestampedWindowKeyWithHeadersQuery.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| /* | ||
| * 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.kafka.streams.query; | ||
|
|
||
| import org.apache.kafka.common.annotation.InterfaceAudience; | ||
| import org.apache.kafka.common.annotation.InterfaceStability.Evolving; | ||
| import org.apache.kafka.streams.kstream.Windowed; | ||
| import org.apache.kafka.streams.processor.api.ReadOnlyRecord; | ||
| import org.apache.kafka.streams.state.ReadOnlyRecordIterator; | ||
| import org.apache.kafka.streams.state.TimestampedWindowStoreWithHeaders; | ||
|
|
||
| import java.time.Instant; | ||
| import java.util.Objects; | ||
| import java.util.Optional; | ||
|
|
||
| /** | ||
| * Interactive query for retrieving records of a single key across a window-start range, including | ||
| * their record headers, from a {@link TimestampedWindowStoreWithHeaders}. | ||
| * | ||
| * <p>This is the headers-aware parallel of {@link WindowKeyQuery}: it returns a | ||
| * {@link ReadOnlyRecordIterator} of {@link ReadOnlyRecord} elements, each carrying the windowed key, | ||
| * value, timestamp, and headers, whereas {@link WindowKeyQuery} returns a | ||
| * {@link org.apache.kafka.streams.state.WindowStoreIterator} of values keyed by window-start | ||
| * timestamp (value only, no headers). Each element's key is a {@link Windowed} whose window | ||
| * describes the record's window; the record's stored event-time is exposed via | ||
| * {@link ReadOnlyRecord#timestamp()}. | ||
| * | ||
| * <p>As with {@link WindowKeyQuery}, a closed window-start range must be supplied (both | ||
| * {@code timeFrom} and {@code timeTo}); open-ended ranges are not supported. | ||
| * | ||
| * <p>Headers are persisted and returned only when the store is backed by a native headers store, | ||
| * i.e. built with a KIP-1271 {@code WithHeaders} byte-store supplier (e.g. | ||
| * {@code Stores.persistentTimestampedWindowStoreWithHeaders}). A {@code WithHeaders} store built | ||
| * over a legacy (non-headers) supplier cannot persist headers, so the store-served reads come back | ||
| * with empty {@code headers()}. | ||
| * | ||
| * <p>Against a plain store not built with the {@code WithHeaders} builder at all, this query type is | ||
| * unsupported and fails with {@link FailureReason#UNKNOWN_QUERY_TYPE}. | ||
| * | ||
| * <p>Each element is a {@link ReadOnlyRecord}, whose timestamp is non-negative. If the backing store | ||
| * does not persist timestamps -- for example a {@code WithHeaders} store built over a plain | ||
| * window-store supplier that surfaces entries with {@code NO_TIMESTAMP} ({@code -1}) -- that entry | ||
| * cannot be represented, so advancing the returned {@link ReadOnlyRecordIterator} throws | ||
| * {@link org.apache.kafka.streams.errors.StreamsException} at that entry. Back the store with | ||
| * {@code Stores.persistentTimestampedWindowStoreWithHeaders(...)} to persist timestamps and headers, | ||
| * or use {@link WindowKeyQuery} if headers are not needed. | ||
| * | ||
| * <p>Because iteration can throw mid-stream, always close the returned {@link ReadOnlyRecordIterator} | ||
| * (for example with try-with-resources), even when a call to {@code next()} throws; otherwise the | ||
| * underlying store iterator leaks and the {@code num-open-iterators} metric stays incremented. | ||
| * | ||
| * @param <K> Type of keys | ||
| * @param <V> Type of values | ||
| */ | ||
| @Evolving | ||
| @InterfaceAudience.Public | ||
| public final class TimestampedWindowKeyWithHeadersQuery<K, V> implements Query<ReadOnlyRecordIterator<Windowed<K>, V>> { | ||
|
|
||
| private final K key; | ||
| private final Optional<Instant> timeFrom; | ||
| private final Optional<Instant> timeTo; | ||
|
|
||
| private TimestampedWindowKeyWithHeadersQuery(final K key, | ||
| final Optional<Instant> timeFrom, | ||
| final Optional<Instant> timeTo) { | ||
| this.key = key; | ||
| this.timeFrom = timeFrom; | ||
| this.timeTo = timeTo; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a query that will retrieve the records (value, timestamp, and headers) identified by | ||
| * {@code key} whose window start falls within the closed range {@code [timeFrom, timeTo]}. | ||
| * @param key The key to retrieve | ||
| * @param timeFrom The inclusive lower bound of the window-start range | ||
| * @param timeTo The inclusive upper bound of the window-start range | ||
| * @param <K> The type of the key | ||
| * @param <V> The type of the value that will be retrieved | ||
| */ | ||
| public static <K, V> TimestampedWindowKeyWithHeadersQuery<K, V> withKeyAndWindowStartRange(final K key, | ||
| final Instant timeFrom, | ||
| final Instant timeTo) { | ||
| Objects.requireNonNull(key, "the key should not be null"); | ||
| return new TimestampedWindowKeyWithHeadersQuery<>(key, Optional.of(timeFrom), Optional.of(timeTo)); | ||
| } | ||
|
|
||
| /** | ||
| * The key that was specified for this query. | ||
| */ | ||
| public K key() { | ||
| return key; | ||
| } | ||
|
|
||
| /** | ||
| * The inclusive lower bound of the window-start range, if specified. | ||
| */ | ||
| public Optional<Instant> timeFrom() { | ||
| return timeFrom; | ||
| } | ||
|
|
||
| /** | ||
| * The inclusive upper bound of the window-start range, if specified. | ||
| */ | ||
| public Optional<Instant> timeTo() { | ||
| return timeTo; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "TimestampedWindowKeyWithHeadersQuery{" + | ||
| "key=" + key + | ||
| ", timeFrom=" + timeFrom + | ||
| ", timeTo=" + timeTo + | ||
| '}'; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.