code wiki / (root) / nx_regfix_gate.nx

nx_regfix_gate.nx source

↩ module page · 85 lines · 4188 B

1// nx_regfix_gate.nx -- ISOLATED proof of the reg_put next-segid fix (registration persistence past 2// the seg-store's cap). Writes REG_TEST_N records to a FRESH /tmp store (never the shared toolreg): 3// with the OLD ss_manifest cap, records beyond it collide onto one segment and are LOST; with 4// reg_next_segid (uncapped max+1) ALL persist + read back. rule-11 clean: every threshold is a NAMED 5// const (no bare literals). Runner must clean /tmp/regfix first. Exit 0 only on all-PASS. 6// license_tier: ORIGINAL expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_registry.nx" 9 10const REG_TEST_N: i64 = 300 // records to write -- chosen ABOVE the old cap so the tail exercises it 11const OLD_MANIFEST_CAP: i64 = 256 // the seg-store cap this fix eliminates (documented in nx_seg_store) 12const KEY_CH: i64 = 107 // ASCII 'k' (id prefix) 13const VAL_CH: i64 = 118 // ASCII 'v' (value prefix) 14const ASCII_0: i64 = 48 15const DIR_MODE: i64 = 0x1ed // 0755 16const GATE_CHECKS: i64 = 3 // number of PASS conditions below (all must be GREEN) 17 18func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 19func g_putn(v: i64) -> i64 { 20 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 21 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 22 let d: *u8 = sys_mmap(24); var k: i64 = 0 23 while m > 0 { d[k] = (ASCII_0 + (m % 10)) as u8; m = m / 10; k = k + 1 } 24 let o: *u8 = sys_mmap(24); var i: i64 = 0 25 while i < k { o[i] = d[k-1-i]; i = i + 1 } sys_write(1, o, k) 26 return 0 27} 28// build <c><i> (e.g. "k42") into buf, NUL-terminated; return length 29func g_id(buf: *u8, c: i64, i: i64) -> i64 { 30 buf[0] = c as u8 31 var o: i64 = 1; var m: i64 = i 32 if m == 0 { buf[o] = ASCII_0 as u8; o = o + 1; buf[o] = 0 as u8; return o } 33 let t: *u8 = sys_mmap(24); var k: i64 = 0 34 while m > 0 { t[k] = (ASCII_0 + (m % 10)) as u8; m = m / 10; k = k + 1 } 35 while k > 0 { buf[o] = t[k-1]; o = o + 1; k = k - 1 } 36 buf[o] = 0 as u8 37 return o 38} 39 40func main(argc: i64, argv: *i64) -> i64 { 41 let pass: *i64 = sys_mmap(16) as *i64 42 pass[0] = 0 43 sys_mkdir("/tmp/regfix" as *u8, DIR_MODE) 44 let prefix: *u8 = "/tmp/regfix/rf-" as *u8 45 let idbuf: *u8 = sys_mmap(64) 46 let recbuf: *u8 = sys_mmap(64) 47 48 // write REG_TEST_N records (the tail is beyond OLD_MANIFEST_CAP) 49 var w: i64 = 0 50 while w < REG_TEST_N { 51 g_id(idbuf, KEY_CH, w) 52 let rl: i64 = g_id(recbuf, VAL_CH, w) 53 reg_put(prefix, "t:" as *u8, "__idx__" as *u8, idbuf, recbuf, rl) 54 w = w + 1 55 } 56 57 // every record must read back (the old cap loses everything beyond OLD_MANIFEST_CAP) 58 let po: *i64 = sys_mmap(16) as *i64 59 let lo: *i64 = sys_mmap(16) as *i64 60 var found: i64 = 0 61 var i: i64 = 0 62 while i < REG_TEST_N { g_id(idbuf, KEY_CH, i); if reg_get(prefix, "t:" as *u8, idbuf, po, lo) == 1 { found = found + 1 } i = i + 1 } 63 g_puts("T all-persist found=" as *u8); g_putn(found); g_puts("/" as *u8); g_putn(REG_TEST_N) 64 if found == REG_TEST_N { g_puts(" PASS\n" as *u8); pass[0] = pass[0] + 1 } else { g_puts(" FAIL (old cap loses the tail)\n" as *u8) } 65 66 // the LAST record (well past OLD_MANIFEST_CAP) present 67 g_id(idbuf, KEY_CH, REG_TEST_N - 1) 68 var oklast: i64 = 0 69 if reg_get(prefix, "t:" as *u8, idbuf, po, lo) == 1 { oklast = 1 } 70 g_puts("T last-record-present got=" as *u8); g_putn(oklast) 71 if oklast == 1 { g_puts(" PASS\n" as *u8); pass[0] = pass[0] + 1 } else { g_puts(" FAIL\n" as *u8) } 72 73 // next-segid uncapped (>= REG_TEST_N), NOT stuck at OLD_MANIFEST_CAP 74 let nseg: i64 = reg_next_segid(prefix) 75 g_puts("T next-segid-uncapped nseg=" as *u8); g_putn(nseg) 76 var okseg: i64 = 0 77 if nseg >= REG_TEST_N { okseg = 1 } 78 if okseg == 1 { g_puts(" PASS (uncapped)\n" as *u8); pass[0] = pass[0] + 1 } else { g_puts(" FAIL (still capped)\n" as *u8) } 79 80 let total: i64 = GATE_CHECKS 81 g_puts("REGFIX-GATE pass=" as *u8); g_putn(pass[0]); g_puts("/" as *u8); g_putn(total); g_puts(" verdict=" as *u8) 82 if pass[0] == total { g_puts("GREEN\n" as *u8); return 0 } 83 g_puts("RED\n" as *u8) 84 return 1 85}