Groundwork for M0: the node arena and overflow slab are about to move into an mmap'd data file where a write to a page belonging to the last durable checkpoint has to copy that page first (PLAN amendment A1). Two changes make that a small commit rather than a sixty-site one, plus the reformat of this file (see the preceding style commit for why it rides along here). Accessors. Every read of a node page now goes through page(), every write through page_mut(), and every overflow read through ovf(); nothing else touches nodes.items or overflow.items. Which of the 55 sites mutate was decided by the compiler rather than by inspection -- page() returns *const Node, so every mutating site failed to compile until flipped -- and the result is that the copy-on-write hook has exactly one home. Records the rule COW will impose (never hold a *Node across a page_mut of the same id) and the audit showing today's callers already comply. Comptime layout asserts. These structures are about to become an on-disk format, and nothing pinned them. Pinning also surfaced that @sizeOf(Slot) is 32, not the 20 its 160 declared bits suggest -- the backing integer's 16-byte alignment rounds it up, so 12 of every 32 slot bytes are padding and a node holds 127 slots where 203 would fit. Pinned, deliberately not fixed: narrowing the slot changes the fanout and so the on-disk shape of every index, which belongs in the commit that reshapes leaf records. reserve_for. The old bound stood in for "levels a batch can add" with n/8, which is ~125 levels for a 1000-entry batch and demands ~528 MiB of headroom. Growing by g levels needs at least 2^g entries, so log2_ceil(n+1)+1 bounds it, giving ~70 MiB for that batch. Harmless as ArrayList capacity; real file growth once the arena is file-backed. Overrunning the reservation is a buffer overrun on a path that has already appended to the log and cannot report failure, so alloc_node and store_record now assert, using assert.zig so the checks survive ReleaseFast. Mutation-checked by dropping the reservation entirely: six tests go red with the new message. Worth noting the assert guards the allocation, not the arithmetic -- ensureUnusedCapacity over-allocates, so a slightly-too-small bound is masked until the reservation becomes exact. build.zig gains a `fuzz` step. spill, spill2, stress and fuzz_split were in no build step and are not in lib.zig's test block, so `zig build test` could not see an API break in the only coverage for records past the inline limit and for randomized split/remove interleavings -- exactly what this work puts at risk.
2.9 KiB
2.9 KiB