Skip to content

KAFKA-20173: Ensure Metered session-stores pass headers correctly#21957

Merged
mjsax merged 2 commits intoapache:trunkfrom
mjsax:kafka-20173-headers-metered-session-stores
Apr 7, 2026
Merged

KAFKA-20173: Ensure Metered session-stores pass headers correctly#21957
mjsax merged 2 commits intoapache:trunkfrom
mjsax:kafka-20173-headers-metered-session-stores

Conversation

@mjsax
Copy link
Copy Markdown
Member

@mjsax mjsax commented Apr 4, 2026

Ensures that all Metered Session-stores (plain and headers) pass headers
into de/serializers.

Reviewers: Uladzislau Blok blokv75@gmail.com, TengYao Chi
frankvicky@apache.org

Ensures that all Metered Session-stores (plain and headers) pass headers
into de/serializers.
@mjsax mjsax added streams kip Requires or implements a KIP labels Apr 4, 2026
return readHeaders(buffer);
}

/**
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need these any longer -- we have the corresponding method inside the stores, and I don't think it make sense to extract them into this Utils class (also given, that we need to pass in StateSerdes...)

}

protected K deserializeKey(final byte[] rawKey) {
private K deserializeKey(final byte[] rawKey) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side cleanup -- sub-classes don't use this anyway, so we can make it private and get rid of the overload that only throws.

final class MeteredWindowedKeyValueWithHeadersIterator<K, VInner, VOuter> extends MeteredWindowedKeyValueIterator<K, VOuter> {
private final Function<byte[], VInner> deserializeValue;
private final BiFunction<byte[], Headers, K> deserializeKey;
private final Function<VInner, Headers> headersExtractor;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make this iterator generic (ie, work with ValueTimestampHeaders and AggregationWithHeaders we need this helper function.


@Override
protected K deserializeKey(final byte[] rawKey) {
throw new UnsupportedOperationException("MeteredTimestampedWindowStoreWithHeaders required to pass in Headers when deserializing a key.");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make the super class method private so we don't need this override any longer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for this clean up
Actually I opened a pull request for the same change while review MeteredSessionStoreWithHeaders : #21966
Happy that we come up with the same idea :)
There is few more changes in my PR. Can you may incorporate them to current PR? Check MeteredTimestampedKeyValueStoreWithHeaders, we can make few methods private as well

);
}

private final class MeteredWindowedKeyValueWithHeadersIterator<ValueType> extends MeteredWindowedKeyValueIterator<K, ValueType> {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted into standalone class, so we can also use it in MeteredSessionStoreWithHeaders class.

final QueryResult<MeteredWindowStoreIterator<ValueAndTimestamp<V>>> typedQueryResult =
InternalQueryResultUtil.copyAndSubstituteDeserializedResult(rawResult, typedResult);
queryResult = (QueryResult<R>) typedQueryResult;
queryResult = (QueryResult<R>) InternalQueryResultUtil.copyAndSubstituteDeserializedResult(rawResult, typedResult);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some cleanup -- there is no value to have typedQueryResult.


if (query instanceof WindowRangeQuery) {
final WindowRangeQuery<K, AGG> windowRangeQuery = (WindowRangeQuery<K, AGG>) query;
if (windowRangeQuery.getKey().isPresent()) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this check inside runRangeQuery to align with how we setup the code in other classes

wrapped().query(rawKeyQuery, positionBound, config);
if (rawResult.isSuccess()) {
final MeteredWindowedKeyValueIterator<K, AGG> typedResult =
new MeteredWindowedKeyValueWithHeadersIterator<>(
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching to a different (already existing) iterator class, to be able to handle headers correctly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Copy Markdown
Contributor

@UladzislauBlok UladzislauBlok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but there are failed tests

Comment on lines +532 to +534
private Bytes serializeKey(final K key) {
return Bytes.wrap(serdes.rawKey(key, internalContext.headers()));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for making those methods private until they needed in sub-classes

There is a functional difference between those two method. New version doesn't check for null. Are we sure null value won't make trouble?
UPD: We should be fine

    public static Bytes wrap(byte[] bytes) {
        if (bytes == null)
            return null;
        return new Bytes(bytes);
    }

return super.prepareValueSerdeForStore(valueSerde, getter);
}

private Bytes serializeKey(final K key, final Headers headers) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrapped().query(rawKeyQuery, positionBound, config);
if (rawResult.isSuccess()) {
final MeteredWindowedKeyValueIterator<K, AGG> typedResult =
new MeteredWindowedKeyValueWithHeadersIterator<>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


@Override
protected K deserializeKey(final byte[] rawKey) {
throw new UnsupportedOperationException("MeteredTimestampedWindowStoreWithHeaders required to pass in Headers when deserializing a key.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for this clean up
Actually I opened a pull request for the same change while review MeteredSessionStoreWithHeaders : #21966
Happy that we come up with the same idea :)
There is few more changes in my PR. Can you may incorporate them to current PR? Check MeteredTimestampedKeyValueStoreWithHeaders, we can make few methods private as well

@UladzislauBlok
Copy link
Copy Markdown
Contributor

LTGM now + tests are passed

Copy link
Copy Markdown
Contributor

@frankvicky frankvicky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mjsax mjsax merged commit 5a2dcf8 into apache:trunk Apr 7, 2026
23 checks passed
@mjsax mjsax deleted the kafka-20173-headers-metered-session-stores branch April 7, 2026 23:58
mjsax added a commit that referenced this pull request Apr 8, 2026
…1957)

Ensures that all Metered Session-stores (plain and headers) pass headers
into de/serializers.

Reviewers: Uladzislau Blok <blokv75@gmail.com>, TengYao Chi
 <frankvicky@apache.org>
@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Apr 8, 2026

Merged to trunk and cherry-picked to 4.3 branch.

nileshkumar3 pushed a commit to nileshkumar3/kafka that referenced this pull request Apr 15, 2026
…ache#21957)

Ensures that all Metered Session-stores (plain and headers) pass headers
into de/serializers.

Reviewers: Uladzislau Blok <blokv75@gmail.com>, TengYao Chi
 <frankvicky@apache.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kip Requires or implements a KIP streams

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants