writeonce/database/src/db.h
shoney.arickathil 1ed4922fdd feat: arc stage 3 T7 — transparent DB actor (WO_T_DB hole closed)
- worker DB builtins marshal to shard 0: requester-side slot encode
  (VM heaps never read cross-shard), owner executes serialized in
  adopt, reply unparks via new WO_PARK_INBOX park + envelope 3/4
- engine gains thread-agnostic slot entry points (insert_slots,
  update_field_slot, val_encode/clone, wo_db_exec_req); traps and
  messages byte-identical to the local path
- main.c: engine + replay boot BEFORE shards spawn; workers assert
  rt.db/rt.wal NULL; busy shard adopts inbox once per slice
- latent stage-1 bug fixed: shared io_uring params static raced by
  lazy worker init lost park wakes (~1/20 hangs); params per-vm,
  short submit now fails loud
- new sample docs/examples/db-actor + just db-actor gate 8/0 (multi
  x3, uring/epoll forced, single byte-exact, WAL replay pair);
  ASan+TSan 6/6; full battery green

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 13:10:26 +02:00

56 lines
2.5 KiB
C

/* db.h — DB statement executors (iteration 9, Task 3+).
*
* The VM reaches the engine through one dispatcher with the same contract
* as every builtin family: 0 = ok, else a WO_T_* code with *msg set. The
* engine and WAL handles ride the runtime context as opaque pointers
* (obj.h's rt.db / rt.wal) — set by main.c at boot, NULL in test binaries
* that never touch DB statements (a DB builtin with rt.db == NULL traps
* WO_T_DB "engine not initialized").
*
* Commit contract per statement (until iteration 8 brings ticks): the
* insert applies to RAM, stages its WAL record, and COMMITS before the
* builtin returns — the builtin returning IS the acknowledgment, so the
* ack-after-fsync doctrine holds at statement granularity. No WAL
* (rt.wal == NULL, no WO_DATA) means RAM-only: every test and every
* corpus fixture runs that way; durability is opt-in by pointing WO_DATA
* at a directory. */
#ifndef WO_DB_H
#define WO_DB_H
#include "vm.h"
int wo_builtin_db(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
/* ---- arc stage 3: one marshaled DB statement (the transparent DB actor).
* A worker shard fills the request on ITS thread — args pre-encoded into
* engine slots, since VM heaps are never read cross-shard — and ships it
* to shard 0 in an envelope; the owner executes it via wo_db_exec_req and
* ships it back. Ownership: `slots` VALUES pass to the owner (consumed by
* the op), the array and every reply buffer pass back to the requester.
* The envelope handoff (mutex + eventfd) orders `done` on both sides. */
typedef struct wo_db_req {
/* request */
uint32_t op; /* WO_B_DB_INSERT..WO_B_DB_PROBE */
uint32_t cid, field, index;
uint64_t id;
uint64_t *slots; /* INSERT: field_cnt; UPDATE: 1; PROBE: 1 (the key) */
uint32_t slot_cnt;
/* routing */
uint32_t from_shard;
void *fiber; /* the parked wo_fiber*, opaque to the engine */
int done;
/* reply */
int status; /* 0 ok, else the WO_T_* the local path would trap */
const char *msg; /* static literal, safe cross-thread */
uint64_t result; /* INSERT: the new id */
uint64_t *ids; /* SCAN/PROBE: malloc'd id list */
uint32_t id_cnt;
uint8_t val_kind; /* GET_FIELD: a cloned engine value */
uint64_t val;
} wo_db_req;
/* Execute one marshaled statement on the OWNER shard (vm = shard 0's; its
* rt.db/rt.wal are the engine). Fills the reply fields; never traps. */
void wo_db_exec_req(wo_vm *vm, wo_db_req *q);
#endif /* WO_DB_H */