fix(db2-delta): refuse resident:keys with no WO_DATA at runtime
- loader stopped refusing durable:true+resident:keys once UPDATE landed; nothing replaced it at runtime - rows for such a table live only in the WAL, so every read failed with a misleading "no such row" instead of naming the problem - main.c now refuses at startup, names the class, exit(2) - residency-accept.sh gains a leg: refuses without WO_DATA, still runs with it — verified failing before the fix, passing after Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 3ea6d6452f260d45f92045c0f300fa49faa1d810)
This commit is contained in:
parent
e08c26309a
commit
49a0a9d047
2 changed files with 49 additions and 0 deletions
|
|
@ -219,6 +219,31 @@ int main(int argc, char **argv) {
|
|||
VM.rt.db = &DB;
|
||||
DB.rt = &VM.rt; /* databasev2 2 (5c): the loop a borrow reads the WAL through */
|
||||
const char *data_dir = getenv("WO_DATA");
|
||||
if (!data_dir || !data_dir[0]) {
|
||||
/* databasev2 3: the loader used to refuse `resident: keys` outright;
|
||||
* now it is accepted because UPDATE landed, but every row still
|
||||
* lives in the log, not RAM — refuse the same way the loader's own
|
||||
* durable:false+resident:keys refusal does, rather than let reads
|
||||
* silently misbehave with no WAL to fold from. */
|
||||
for (uint32_t i = 0; i < mod.class_cnt; i++) {
|
||||
if (!(mod.classes[i].flags & WO_CLASSF_RESIDENT_KEYS)) continue;
|
||||
const char *cname = "?";
|
||||
int cnlen = 1;
|
||||
uint32_t k = mod.classes[i].name;
|
||||
if (k < mod.const_cnt && mod.consts[k].s) {
|
||||
cname = mod.consts[k].s->data;
|
||||
cnlen = (int)mod.consts[k].s->len;
|
||||
}
|
||||
fprintf(stderr,
|
||||
"wovm: `%.*s` is declared `resident: keys` — its rows live only "
|
||||
"in the write-ahead log, so it cannot run without WO_DATA.\n",
|
||||
cnlen, cname);
|
||||
wo_db_destroy(&DB);
|
||||
wo_vm_destroy(&VM);
|
||||
wo_module_free(&mod);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (data_dir && data_dir[0]) {
|
||||
char wal_path[512];
|
||||
snprintf(wal_path, sizeof wal_path, "%s/shard-0.wal", data_dir);
|
||||
|
|
|
|||
|
|
@ -170,6 +170,30 @@ else
|
|||
bad "the doc example compiles" "see $LOG"
|
||||
fi
|
||||
|
||||
# ---- 6. resident:keys refuses to run without WO_DATA -----------------------
|
||||
# CRITICAL 1: the loader stopped refusing durable:true + resident:keys once
|
||||
# UPDATE landed, and nothing replaced that refusal at runtime — a table
|
||||
# declared this way ran with no WAL to fold its rows from, misreporting
|
||||
# every read as "no such row" instead of naming the real problem.
|
||||
printf '@table(name: "items", index: [k], durable: true, resident: keys)\nclass Items { k: Text }\nfn main() -> Int { insert Items { k: "a" }; return 0; }\n' > "$WORK/reskeys.wo"
|
||||
if "$WOC" --emit "$WORK/reskeys.wo" -o "$WORK/reskeys.wob" 2>"$WORK/e"; then
|
||||
out="$("$WOVM" "$WORK/reskeys.wob" 2>&1)"; rc=$?
|
||||
[[ $rc -eq 2 ]] \
|
||||
&& ok "resident:keys without WO_DATA exits 2" \
|
||||
|| bad "resident:keys without WO_DATA exits 2" "exit=$rc"
|
||||
grep -q 'Items' <<<"$out" \
|
||||
&& ok "resident:keys refusal names the offending class" \
|
||||
|| bad "resident:keys refusal names the class" "got: $out"
|
||||
mkdir -p "$WORK/d6"
|
||||
WO_DATA="$WORK/d6" "$WOVM" "$WORK/reskeys.wob" >/dev/null 2>&1
|
||||
rc2=$?
|
||||
[[ $rc2 -eq 0 ]] \
|
||||
&& ok "resident:keys WITH WO_DATA still runs" \
|
||||
|| bad "resident:keys with WO_DATA runs" "exit=$rc2"
|
||||
else
|
||||
bad "resident:keys refusal fixture compiles" "$(head -1 "$WORK/e")"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "residency-accept: $((pass + fail)) checks, $fail failures"
|
||||
[[ $fail -eq 0 ]] || exit 1
|
||||
|
|
|
|||
Loading…
Reference in a new issue