New src/pager.zig, engine-unused at this commit: the structures move onto it in the commits that follow, and landing it alone keeps that change reviewable. The file is an array of 4 KiB pages with a tail-bump extent allocator. PLAN D6.1 asked for a region table; it cannot be one, because there is a node arena per index and a document slab per collection, so the region count is dynamic and unbounded and N contiguous regions cannot all grow at the tail. One page array means exactly one growth path, so the write-then-extend discipline lives in exactly one place, and `ls`/`du` stay honest for the backup story. The mapping is a PROT_NONE anonymous NORESERVE reservation that new file-backed suffixes are mmap'd into with MAP_FIXED. That is one VMA and zero committed pages, and it means **the base never moves for the life of the process**, so a pointer handed out before a growth is still valid after it. The ArrayList-backed arena this replaces could not promise that -- the promoted-key scratch buffer in index.zig exists solely to work around it, and phase8 records a dangling-slab-pointer bug of exactly that shape. Growth is `setLength` and *then* `mmap`, never the reverse: a store into a mapped page past end-of-file raises SIGBUS, which no error path can catch. The accessors assert against `mapped_pages`, so a violation is a panic with a message instead of a signal. `page_mut` is deliberately the only way to obtain a writable page. Copy-on-write hooks in there (commit 12), and funnelling every write through one function is what makes that a change of one body rather than of every caller. `sync` is msync + fsync and only the checkpoint calls it. Between checkpoints dirty pages may sit in the page cache indefinitely, because recovery is `image + replay(seq > watermark)` and the image's pages are never written *differently* -- which is what keeps the write path at exactly one fsync, the WAL's (PLAN amendment A1). This is the one place in src/ that reaches for std.posix, against the house style, and the module comment says why: std.Io.File.MemoryMap prefaults by default, exposes no NORESERVE/FIXED/address hint so it cannot express a reservation, and its setLength is mremap on Linux and unsupported on darwin. Mutation-checked, all four red: remapping the prefix at a kernel-chosen address; dropping the uuid comparison (which is what stops one database's log being replayed onto another's checkpoint); dropping the header hash comparison; and moving setLength after mmap. An empty file is treated as absent rather than as corruption, so a create that died before its header landed still opens.
28 lines
864 B
Zig
28 lines
864 B
Zig
// multiforadb core library. Public entry point for tests and the server.
|
|
|
|
pub const assert = @import("assert.zig");
|
|
pub const bson = @import("bson.zig");
|
|
pub const wire = @import("wire.zig");
|
|
pub const commands = @import("commands.zig");
|
|
pub const server = @import("server.zig");
|
|
pub const storage = @import("storage.zig");
|
|
pub const db = @import("db.zig");
|
|
pub const query = @import("query.zig");
|
|
pub const update = @import("update.zig");
|
|
pub const index = @import("index.zig");
|
|
pub const pager = @import("pager.zig");
|
|
|
|
test {
|
|
_ = @import("assert.zig");
|
|
_ = @import("bson.zig");
|
|
_ = @import("wire.zig");
|
|
_ = @import("commands.zig");
|
|
_ = @import("server.zig");
|
|
_ = @import("storage.zig");
|
|
_ = @import("db.zig");
|
|
_ = @import("query.zig");
|
|
_ = @import("update.zig");
|
|
_ = @import("index.zig");
|
|
_ = @import("pager.zig");
|
|
}
|