Skip to content

KAFKA-20875: Headers window store adapters must expose the retention they wrap - #23037

Open
alanlau28 wants to merge 1 commit into
apache:trunkfrom
alanlau28:headers-retention-fix
Open

KAFKA-20875: Headers window store adapters must expose the retention they wrap#23037
alanlau28 wants to merge 1 commit into
apache:trunkfrom
alanlau28:headers-retention-fix

Conversation

@alanlau28

@alanlau28 alanlau28 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

issue: https://issues.apache.org/jira/browse/KAFKA-20875

PlainToHeadersWindowStoreAdapter and
TimestampedToHeadersWindowStoreAdapter hold the store they wrap in a
field rather than participating in the WrappedStateStore chain, so
ProcessorStateManager.StateStoreMetadata.extractRetentionPeriod
which finds a store's retention by unwrapping to the innermost layer —
terminates on the adapter and resolves -1.

A -1 fails the windowed restore gate retentionPeriod > 0 && retentionPeriod != Long.MAX_VALUE, so the restore seeks the beginning
of the changelog rather than skipping data the store would discard
anyway. On a changelog with delete retention that means starting at the
offset retention is deleting from, with no margin against being lapped.

Each adapter now implements WithRetentionPeriod and unwraps its own
delegate.

…they wrap

PlainToHeadersWindowStoreAdapter and TimestampedToHeadersWindowStoreAdapter hold
the store they wrap in a field rather than participating in the WrappedStateStore
chain, so ProcessorStateManager.StateStoreMetadata.extractRetentionPeriod -- which
finds a store's retention by unwrapping to the innermost layer -- terminates on the
adapter and resolves -1.

A -1 fails the windowed restore gate
"retentionPeriod > 0 && retentionPeriod != Long.MAX_VALUE", so the restore seeks the
beginning of the changelog rather than skipping data the store would discard anyway.
On a changelog with delete retention that means starting at the offset retention is
deleting from, with no margin against being lapped.

Each adapter now implements WithRetentionPeriod and unwraps its own delegate, which
follows the convention already in this code: TimestampedWindowStoreWithHeadersBuilder
special-cases the adapter by type to walk through it rather than making it a
WrappedStateStore. Making the adapters WrappedStateStore instead would let chain
walks reach the inner store's format flags -- isTimestamped() would report true for
a store whose observable format is post-conversion -- which is what these adapters
exist to prevent.

Also raises the log level when a windowed store reports no usable retention. Every
branch of this path logged at debug, so a store that never got optimised looked
identical to one that did.
@github-actions github-actions Bot added triage PRs from the community streams small Small PRs and removed triage PRs from the community labels Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant