- 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>
56 lines
2.5 KiB
C
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 */
|