db: a dropped collection is reclaimed, not deadened

`free_collection` charged the engine's `dead_bytes` with the dropped
collection's live bytes, and then, three lines down, handed every page
that collection owned back to the pager. A drop therefore asked for a
rebuild -- a full copy of every collection that was left -- to reclaim
space that had already been reclaimed. Its own garbage was wrong the
other way: bytes that died before the drop stayed on the engine's books
after the pages holding them were freed.

Both halves of that are the same statement: `dead_bytes` is the sum of
`slab_used - live_bytes` over the collections that still exist. Make it
so on the drop path, then stop storing it separately at all --
`read_catalog` recomputes it from the collections the catalog lists, so
the watermark's copy is now a hint for anything inspecting the header
rather than a second source of truth. It would be wrong in one specific
way if it stayed one: a collection dropped after the last checkpoint is
gone from the catalog but still charged for in the hint.

`write_catalog` now returns the dead sum beside the live one and the
checkpoint asserts it the same way, under the same quiescence condition.
That is what makes the accounting checkable rather than merely intended.

Mutation-checked three ways, each red on its own: charge the drop again;
delete the subtraction of the collection's own garbage; delete the
accumulation in `read_catalog`.

163/163 unit tests in ReleaseFast and ReleaseSafe, 82/82 fuzz,
e2e 49, e2e2 concurrent 2 + crash pair, e2e3 16, e2e4 17, e2e6 72,
e2e7 86, crash-fuzz 60 cycles.
This commit is contained in:
2026-08-09 11:31:37 +03:00
parent f8a39a0965
commit 992cc2a5ab
2 changed files with 155 additions and 19 deletions

View File

@@ -27,7 +27,8 @@
//! [56..64) u64 freelist_len
//! [64..72) u64 prev_generation -- kept intact for fallback
//! [72..80) u64 live_docs -- cached hint
//! [80..88) u64 dead_bytes -- cached, drives the rebuild trigger
//! [80..88) u64 dead_bytes -- cached hint; the engine recomputes it
//! from the catalog on open
//! [88..4088) reserved (zero)
//! [4088..4096) u64 xxhash3 over [0..4088)
//! pages 3.. data, handed out by a tail-bump extent allocator