feat(db): the inline path takes the fatal rule, asymmetry documented — T3
databasev2 4 part A, task 3. Looks like a no-op; it is not — without it the two write paths would disagree about what a failure means, which is the unevenness the spec exists to remove. - inline path (a statement already on shard 0) keeps its own barrier, batch size 1. It cannot hold a reply: it returns into its OWN fiber rather than unparking a requester, so batching it would need that fiber parked on the barrier — part B's machinery, deliberately out of part A - the comment says so, and says why not to "fix" it, because the next reader will otherwise see an inconsistency and delete the commit - the ordering assumption is written down: committing here is safe only because the drain commits unconditionally whenever anything is staged, so the buffer is empty when this runs. If that stops holding, this commit would make another statement's record durable early and ack it to the wrong writer - staging and commit failures are fatal here too. The update arm's old comment admitted what it did — "RAM ahead of disk: trap, do not ack" — and that is now gone WO_T_IO no longer appears anywhere in db.c: the write path cannot be caught. Language-visible, and task 6 records it in the error catalogue. Verified: - just wovm-test: 36 suites 0 fail, cli_smoke OK - WO_SHARDS=1 db-bench-quick: 85 checks 0 failures, crash.s1.0 800 acked rows present after kill -9 — the configuration that takes this path exclusively - default shards: 85 checks 0 failures Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
76d80cc027
commit
9fc439dd47
1 changed files with 25 additions and 17 deletions
|
|
@ -25,15 +25,25 @@ int wo_builtin_db(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg) {
|
|||
: WO_T_DB;
|
||||
wo_wal *w = (wo_wal *)vm->rt.wal;
|
||||
if (w) {
|
||||
/* RAM applied, record staged, ONE commit before the ack (the
|
||||
* builtin's return). A failed commit is a failed write: the
|
||||
* row is removed again so RAM never claims what disk never
|
||||
* acknowledged, and the statement traps. */
|
||||
if (wo_wal_append_insert(w, db, cid, id) != 0 || wo_wal_commit(w) != 0) {
|
||||
wo_row_remove(db, cid, id);
|
||||
*msg = "wal commit failed";
|
||||
return WO_T_IO;
|
||||
}
|
||||
/* THE INLINE PATH KEEPS ITS OWN BARRIER, AND THAT ASYMMETRY IS
|
||||
* DELIBERATE (databasev2 4 part A). The request path batches:
|
||||
* wo_vm_adopt holds each reply and commits once per drain. This
|
||||
* path cannot, because it has no reply to hold — it returns into
|
||||
* its OWN fiber rather than unparking a requester. Batching here
|
||||
* would mean parking that fiber on the barrier, which is part B's
|
||||
* machinery and deliberately out of part A. Do not "fix" this by
|
||||
* dropping the commit: without it an inline statement would never
|
||||
* be durable at all.
|
||||
*
|
||||
* Committing here is safe because the drain commits
|
||||
* unconditionally whenever anything is staged, so the buffer is
|
||||
* empty when this runs. If that ever stops holding, this commit
|
||||
* would make another statement's record durable early and ack it
|
||||
* to the wrong writer.
|
||||
*
|
||||
* Failure is fatal, not a trap: the row is already in RAM. */
|
||||
if (wo_wal_append_insert(w, db, cid, id) != 0) wo_wal_stage_fatal(w);
|
||||
wo_wal_commit_fatal(w, 1);
|
||||
}
|
||||
R[A] = id;
|
||||
return 0;
|
||||
|
|
@ -47,10 +57,10 @@ int wo_builtin_db(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg) {
|
|||
return ek == DB_ERR_UNIQUE ? WO_T_UNIQUE : ek == DB_ERR_OOM ? WO_T_OOM : WO_T_DB;
|
||||
wo_wal *w = (wo_wal *)vm->rt.wal;
|
||||
if (w) {
|
||||
if (wo_wal_append_update(w, db, cid, id) != 0 || wo_wal_commit(w) != 0) {
|
||||
*msg = "wal commit failed"; /* RAM ahead of disk: trap, do not ack */
|
||||
return WO_T_IO;
|
||||
}
|
||||
/* was: trap and leave RAM ahead of disk, which the old comment
|
||||
* admitted. Now fatal — see the insert arm. */
|
||||
if (wo_wal_append_update(w, db, cid, id) != 0) wo_wal_stage_fatal(w);
|
||||
wo_wal_commit_fatal(w, 1);
|
||||
}
|
||||
R[A] = 0;
|
||||
return 0;
|
||||
|
|
@ -70,10 +80,8 @@ int wo_builtin_db(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg) {
|
|||
}
|
||||
wo_wal *w = (wo_wal *)vm->rt.wal;
|
||||
if (w) {
|
||||
if (wo_wal_append_remove(w, cid, id) != 0 || wo_wal_commit(w) != 0) {
|
||||
*msg = "wal commit failed";
|
||||
return WO_T_IO;
|
||||
}
|
||||
if (wo_wal_append_remove(w, cid, id) != 0) wo_wal_stage_fatal(w);
|
||||
wo_wal_commit_fatal(w, 1);
|
||||
}
|
||||
R[A] = 0;
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue