Skip to content

KAFKA-20158: Add AggregationWithHeaders, serialization support and tests (1/N)#21511

Merged
bbejeck merged 4 commits intoapache:trunkfrom
bbejeck:KAFKA-20158_session_store_w_headers_part_1
Feb 24, 2026
Merged

KAFKA-20158: Add AggregationWithHeaders, serialization support and tests (1/N)#21511
bbejeck merged 4 commits intoapache:trunkfrom
bbejeck:KAFKA-20158_session_store_w_headers_part_1

Conversation

@bbejeck
Copy link
Copy Markdown
Member

@bbejeck bbejeck commented Feb 18, 2026

This PR introduces AggregationWithHeaders and serialization support
introduced in KIP-1271 for storing session aggregations with headers.

@bbejeck bbejeck requested a review from frankvicky February 18, 2026 21:43
@bbejeck bbejeck changed the title KAFKA-20158: Add AggregationWithHeaders, serialization support and tests KAFKA-20158: Add AggregationWithHeaders, serialization support and tests (1/N) Feb 18, 2026
Copy link
Copy Markdown
Contributor

@aliehsaeedii aliehsaeedii left a comment

Choose a reason for hiding this comment

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

Thanks @bbejeck. I left some minor comments.


return baos.toByteArray();
} catch (final IOException e) {
throw new SerializationException("Failed to serialize AggregationWithHeaders", e);
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.

Should we add topic to the exception message for better debugging?

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.

if so, we should also add it to ValueTimestampHeadersSerializer

* @return the byte array containing the read bytes
* @throws SerializationException if buffer doesn't have enough bytes or length is negative
*/
private static byte[] readBytes(final ByteBuffer buffer, final int length) {
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.

This may not be directly related to this PR, but we could refactor the code so that this method lives in a shared place and can be reused by other classes as well.

Copy link
Copy Markdown
Member Author

@bbejeck bbejeck Feb 20, 2026

Choose a reason for hiding this comment

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

Great idea! But we currently don't have a Utils class (at least that I know of) can we defer this to a follow-up PR and maybe consider other code as well?

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seems in HeaderDeserializer we don't have such a helper at all, and just use

final byte[] bytes = new byte[length];
buffer.get(bytes);

Might be good to also start using it there for better error messages.

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.

What would be a good location for a Utils class for this - maybe just a standalone one at the root of org.apache.kafka.streams.state.internals ?

* @throws SerializationException if buffer doesn't have enough bytes or length is negative
*/
private static byte[] readBytes(final ByteBuffer buffer, final int length) {
if (length < 0) {
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.

thanks. I like this check. We dont have it in other places.

* Extract aggregation from serialized AggregationWithHeaders.
*/
static <T> T aggregation(final byte[] rawAggregationWithHeaders, final Deserializer<T> deserializer) {
if (rawAggregationWithHeaders == null) {
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.

Not sure why we need this method, but we can go ahead and remove it if it's not needed.

final byte[] rawAggregation = readBytes(buffer, buffer.remaining());
final AGG aggregation = aggregationDeserializer.deserialize(topic, headers, rawAggregation);

return AggregationWithHeaders.make(aggregation, 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.

here if aggregation is null, then make returns null. I think this should not be the desired behaviour. Same for ValueTimestampDeserializer.deserialize. WDYT @frankvicky?

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.

hmmm...
Make sense, even if we have a null value after deserialization, the headers might still be meaningful.
We should replace with makeAllowNullable

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.

Overall LGTM.
Could you please rebase on the trunk?
There are some changes of deserializer/serializer of headers.

@bbejeck bbejeck force-pushed the KAFKA-20158_session_store_w_headers_part_1 branch from 23ff16b to 3110503 Compare February 20, 2026 17:03
@bbejeck
Copy link
Copy Markdown
Member Author

bbejeck commented Feb 20, 2026

@aliehsaeedii @frankvicky all comments addressed ready for another review

Copy link
Copy Markdown
Contributor

@aliehsaeedii aliehsaeedii left a comment

Choose a reason for hiding this comment

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

Thanks @bbejeck

* @return the byte array containing the read bytes
* @throws SerializationException if buffer doesn't have enough bytes or length is negative
*/
private static byte[] readBytes(final ByteBuffer buffer, final int length) {
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.

return null;
}

final ByteBuffer buffer = ByteBuffer.wrap(rawAggregationWithHeaders);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seems this duplicates some code from above (inside deserialize). Should we unify it?


private AggregationWithHeaders(final AGG aggregation, final Headers headers) {
this.aggregation = aggregation;
this.headers = headers == null ? new RecordHeaders() : headers;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we allow null at all? For the aggregation it's different, as it might be a tombstone that we need to handle -- but for headers I am wondering if we need null or if we should just disallow it entirly?

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 dissallow null headers here, which makes since how instances get created, the headers really won't ever be null. But this is the same as ValueTimestampHeaders should probably follow the same pattern. \cc @frankvicky @aliehsaeedii

@bbejeck bbejeck force-pushed the KAFKA-20158_session_store_w_headers_part_1 branch from 3110503 to 6573fa6 Compare February 24, 2026 00:48
@bbejeck bbejeck merged commit 7b46af6 into apache:trunk Feb 24, 2026
23 checks passed
@bbejeck
Copy link
Copy Markdown
Member Author

bbejeck commented Feb 24, 2026

Merged #21511 into trunk

@mjsax mjsax added the kip Requires or implements a KIP label Mar 6, 2026
Shekharrajak pushed a commit to Shekharrajak/kafka that referenced this pull request Mar 31, 2026
…sts (1/N) (apache#21511)

This PR introduces `AggregationWithHeaders`  and serialization  support
introduced in KIP-1271 for storing session aggregations with  headers.
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.

4 participants