Fix TTL write with Kafka NO_TIMESTAMP being stored expired in 1970 (#1141) - #1144
Open
nirajkumarbarot wants to merge 3 commits into
Open
Fix TTL write with Kafka NO_TIMESTAMP being stored expired in 1970 (#1141)#1144nirajkumarbarot wants to merge 3 commits into
nirajkumarbarot wants to merge 3 commits into
Conversation
test_a_later_good_timestamp_in_the_same_batch_still_flips already constructed the batch that reproduces the bug (an un-timestamped ttl= write alongside a well-timestamped one) but only asserted the store flipped. This adds the missing assertion: the un-anchorable key's stamp must be SENTINEL_NEVER, not the bogus 1970 expiry the bug produced. Related: quixio#1141
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Closes #1141
Summary
A
state.set(..., ttl=...)write whose record carries Kafka'sNO_TIMESTAMP(-1) could be stored with an expiry in 1970, making the record already expired the moment it lands — deleted silently on the very next TTL sweep.Root cause
In
set()/set_bytes()(bothRocksDBPartitionTransactionandMemoryPartitionTransaction), an un-timestamped write correctly avoided setting_batch_has_ttl_writes(so it couldn't wrongly trigger the store flip), but its computed stamp - a bogusNO_TIMESTAMP (-1) + ttlexpiry was still recorded in_pending_stampsunconditionally:If any other write in the same batch flipped the store, the stale stamp was applied to this record via
_restamp_default_cf_cache_for_flip, producing a born-expired record with nothing logged.Fix
Record the pending stamp under the same condition as the flip trigger:
This relies on the existing contract that a key present in the update cache but absent from
_pending_stampsfalls back toSENTINEL_NEVER(never-expiring) at flip time - trading silent deletion for silent non-expiry, which is the safer default for a dedup store, with a warning now logged for visibility._track_batch_ttl_ms(ttl)stays outside the guard: it feeds the implicit legacy TTL used when a populated store flips withoutlegacy_records_ttl, and the duration is still valid information even when the write's timestamp can't anchor an expiry.Applied identically to all four call sites (RocksDB
set/set_bytesand Memoryset/set_byteson the unflipped-partition path).Alternatives considered (and why rejected — per the issue)
Reject the write with
ValueError— breaksTestNegativeEventTimeGuard::test_negative_first_timestamp_does_not_crash_high_water, which deliberately requires such writes to be accepted.Anchor on the batch's high-water (
high_water + ttl) - gives the record a real TTL but invents an event-time anchor for a record that has none, and makes the result depend on write order within the batch.Test gap closed
test_a_later_good_timestamp_in_the_same_batch_still_flipsalready constructed the exact batch that reproduces this bug but only asserted the store flipped. Added an assertion that the un-anchorable key's stamp decodes toSENTINEL_NEVERrather than a 1970 expiry - verified red on the original code, green after the fix.Testing
pytest tests/test_quixstreams/test_state/test_rocksdb/test_no_timestamp_flip.py -v- all 4 passtests/test_quixstreams/test_state/suite — 717 passed (remaining failures are pre-existing Docker-fixture errors unrelated to this change)TestNegativeEventTimeGuard::test_negative_first_timestamp_does_not_crash_high_waterstill passes (the write-acceptance contract is preserved)