diff --git a/database/src/CODE-LOGIC.md b/database/src/CODE-LOGIC.md index 6fb7985..3dd3aa6 100644 --- a/database/src/CODE-LOGIC.md +++ b/database/src/CODE-LOGIC.md @@ -58,6 +58,28 @@ tear). The crash battery in `runtime/test/test_wal.c` is the module's meaning proven: acked-over-a-pipe after commit, SIGKILL mid-stream, replay, zero acked-but-missing. +**Where the log lives (databasev2 7, 2026-09-10).** `wo_wal_resolve_data_path` +turns `WO_DATA` into the log path before main.c opens anything: an existing +directory or a trailing `/` → `/shard-0.wal` byte for byte (the pre-7 +form, `//` after a trailing slash included); anything else IS the log — +opened if a regular file, created by `wo_wal_open` if absent. Two refusals, +exit 2, one stderr line each, worded in main.c from the resolver's codes: +`WO_WAL_PATH_NO_PARENT` (the parent comes back in `out`, so the line names +the path AND the parent; no `mkdir -p` — a typo must not plant a store +somewhere unexpected, the operator creates directories, the runtime never +does) and `WO_WAL_PATH_NOT_A_FILE` (fifo, socket, device). +`WO_WAL_PATH_TOO_LONG` refuses what the old 512-byte `snprintf` silently +truncated. A trailing slash on a MISSING directory is still the directory +form and still fails at `wo_wal_open` (`cannot open`), unchanged on purpose. +Nothing below main.c knows which form was used: compaction and migration +build `.compact` and fsync `parent_dir_of(log path)` — the same +static helper the resolver's parent check uses, so the directory checked at +boot is the directory synced after every rename. Tests: +`test_resolve_data_path` (every arm of the rule, fifo via `mkfifo`) and +`test_file_form_temps_beside_log` (a directory planted at `.compact` +makes compaction and migration refuse with the log untouched; removed, both +succeed and the file is the only artifact beside a decoy sibling directory). + ## db.c — statement executors (iteration 9, Task 3) One dispatcher, the builtin contract (0 ok, else WO_T_* + msg). The engine diff --git a/docs/plan/oop-vm/04-db-binding.md b/docs/plan/oop-vm/04-db-binding.md index 67735d1..8ef3802 100644 --- a/docs/plan/oop-vm/04-db-binding.md +++ b/docs/plan/oop-vm/04-db-binding.md @@ -107,6 +107,37 @@ intact record count and prefix end — the crash battery's verifier (`runtime/test/test_wal.c`: five rounds of insert/commit/ack-over-pipe with SIGKILL mid-stream; every acked row present and exact after replay). +**Where the log lives (databasev2 7, 2026-09-10).** `WO_DATA` is always a +path, never a sentinel (ephemerality is `WO_EPHEMERAL=1`, databasev2 2 task +6a), and it names the store in one of two forms, resolved by +`wo_wal_resolve_data_path` (`wal.{c,h}`) before anything is opened: + +- **Directory form** — an existing directory, or any path ending in `/`: the + log is `/shard-0.wal`, byte for byte what every deployment and gate + before this iteration used (a trailing slash still yields the `//` the + pre-7 driver produced, and a trailing slash on a missing directory still + fails at open: `wovm: cannot open //shard-0.wal`, exit 2). +- **File form** — anything else: the path IS the log (`app.db`, `store.wo.db` + — the name is the operator's). An existing regular file is opened; an + absent path is created by `wo_wal_open`, but only when its parent directory + already exists. Two refusals, each exit 2 and ONE stderr line: a parent + that is not an existing directory — `wovm: WO_DATA= — its parent + is not an existing directory; create it first (wovm never runs + mkdir -p).` — because a typo must not plant a store somewhere unexpected; + and a path that exists but is neither a regular file nor a directory + (fifo, socket, device). A result longer than the driver's path buffer is + refused as well, never truncated. + +One file is the whole store at any core count (shard 0 is the only WAL +writer since arc stage 3). Compaction (databasev2 3) and schema migration +(databasev2 12) rewrite through `.compact` beside the log and +fsync the log's parent after the `rename` — both derive that from the log +path, never from `WO_DATA`, so the file form inherits their crash safety +unchanged; the boot-time parent check and the post-rename fsync share one +derivation (`parent_dir_of`). `WO_EPHEMERAL` set together with either form +refuses exactly as 6a says. Pinned by `runtime/test/test_wal.c` +`test_resolve_data_path` and `test_file_form_temps_beside_log`. + ## Insert (Task 3) — builtin 61, `database/src/db.c` `insert Class { field: expr, … }` is a typed expression (statement position