fix(rollout): seal the memtable in cleanup_own_shard before merging - #189
Merged
Conversation
`ROLLOUT_FLUSH_INTERVAL_SECS=0` is documented as falling back to the cleanup/merge path for visibility, but that fallback could not work. `cleanup_own_shard` delegates to `merge_own_shard_if_ready(1)`, which reads the shard manifest and returns early when `flushed_generations` is empty. With no periodic flush nothing ever seals the active memtable, so that list stayed empty forever: the merge was never reached, and rows that `add` had durably persisted stayed invisible until a process restart replayed the WAL. Flush before the threshold check so cleanup is a genuine standalone fallback. Confirmed by a probe: with a row added and no flush, `cleanup_own_shard` returned 0 and the row stayed invisible; it now returns 1 and the row is readable. Also warn at startup when both the flush and cleanup intervals are 0, since that combination still leaves nothing to seal, and correct the config doc which promised the fallback unconditionally. The new test fails on the parent commit (`reclaimed` 0 != 1) and passes here. Closes #184 Co-Authored-By: Claude <noreply@anthropic.com>
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.
Fixes #184.
Problem
ROLLOUT_FLUSH_INTERVAL_SECS's documentation says0disables periodic flush and rows "then only become visible when the cleanup/merge path flushes them". That fallback did not exist.cleanup_own_sharddelegates tomerge_own_shard_if_ready(1), which reads the shard manifest and short-circuits:With no periodic flush, nothing seals the active memtable, so
flushed_generationsis always empty, so this returns0and never reachesmerge_own_shard— which contains the only otherclose()(and therefore the only other seal) on that path.Net effect with
ROLLOUT_FLUSH_INTERVAL_SECS=0:addpersists the WAL entry, so no data loss, but the rows are invisible to every reader indefinitely — until the process restarts and replays the WAL.Verification
Confirmed with a throwaway probe before writing the fix:
Change
cleanup_own_shardflushes before the threshold check (rollout_store.rs). One line, plus a comment explaining why the ordering matters. Cleanup becomes a genuine standalone fallback, as the config already claimed.Startup warning when both intervals are
0(main.rs). Cleanup-alone is now sufficient, but flush=0 and cleanup=0 still leaves nothing to seal. That is a legitimate (if unusual) configuration, so it warns rather than refusing to boot.Config doc corrected to describe what each combination actually does.
Testing
New
cleanup_own_shard_seals_before_mergingasserts a single cleanup pass seals, merges, and exposes the row, with the count trigger explicitly disabled so cleanup is the only path that can help.I verified it is a real guard by reverting just the
self.flush().await?line:Full runs:
lance-context-core --lib161 passed /lance-context-server49 passed.Note on scope
ShardWriter::close()does seal the active memtable (lance-7.0.0write.rs:1911-1921), andRolloutStore'sDropspawns a detached close — so LRU eviction is not affected by this bug. That was the concern in #185, which I will close separately with these findings.🤖 Generated with Claude Code