You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
gc-storage: refuse to sweep when the mark is incomplete (#1117)
A live server's periodic `d/gc-storage` deleted every key of a store except
`:branches` (dev.simm.is system DB, 2026-09-29; datahike 0.8.1744). The mark's
go block in `reachable-in-branch` died on a java.lang.AssertionError
(core.async's 1024-pending-takes limit, reached through an unrelated leak of
parked `<? S` takes in the same JVM). `go-try`/`go-try-` catch Exception, not
Error, so the walk's channel closed EMPTY; `async/merge` + `<<?` simply
yielded one result fewer, and the sweep ran against a whitelist of
#{:branches}.
The hole is still on main: any Error inside a walk (AssertionError,
StackOverflowError, OutOfMemoryError), a `:branches` read that comes back
nil, or a branch-head record that reads back nil, each turns into "nothing
to keep" and the sweep deletes the database.
Fail closed instead:
- `:branches` must read back non-empty (`:gc-branches-unreadable`);
- every seed must produce exactly one mark (`:gc-incomplete-mark`), at all
three merge sites in `gc-storage!` and in `reachable-store-refs`;
- a BRANCH head record that cannot be read aborts the mark
(`:gc-branch-head-unreadable`); absent ancestor/root records keep the
existing "lineage ends here" tolerance.
Regression test injects each failure and asserts that no key is deleted
and the database still opens; all three fail (whole store swept) without
the fix.