nx_segopen_absent_gate.nx source
↩ module page · 196 lines · 9860 B
1// nx_segopen_absent_gate.nx -- THE REFEREE FOR ss_open2's FAIL-SAFE SEGMENT ADMISSION (2026-09-02, debt 1788361379).
2//
3// WHY THIS GATE EXISTS, MEASURED: nishifamily.com/search was 503 for ~16h. The serving daemon's parent
4// SIGSEGV'd inside the accept-path shard refresh, and the guard's respawn then SPUN 15.9h of user CPU inside
5// ss_open2 with the listen port never opened (State R, voluntary ctxsw 8, nonvoluntary 26.1M). Its /proc maps
6// held one manifest segment with its .idx mapped and NO .docs: ss_open2 sized that segment's live map from
7// dsz (== 0, one page) but bounded the marks by the .post doc count, so the marks wrote past the page --
8// SIGSEGV when the next page was unmapped, silent table corruption and an endless probe when it was mapped.
9// The fix makes an index-present/docs-absent row contribute NO live docs and ANNOUNCES it on stderr.
10//
11// IN-PROCESS over nx_seg_store.nx, deliberately: the subject is a library function, the fixture plane lives
12// in /tmp/<gate>/ (never knowledge/store, which the segguard beat sweeps), and every outcome tooth is
13// preceded by a fixture-reached-the-condition tooth so a setup failure cannot pass for a verdict.
14// STATE, NOT MESSAGE: the live-map bytes of the handle are read directly (h[1 + 8*ns + s]), because a
15// leaking or overflowing open answers the same bytes to every caller -- only the map can prove it.
16// The segment NAME is read back from the manifest the writer produced, never recomputed from the id the
17// gate asked for: ss_commit re-derives the id under the plane lock, so a leftover file from an earlier run
18// would otherwise make the gate rename the wrong file and fail its own fixture tooth.
19// PRE-FIX this gate reads RED on exactly the two load-bearing teeth (marks written for absent docs, no
20// announce) and GREEN on every fixture tooth; POST-FIX it reads GREEN throughout. That asymmetry is the bite.
21
22import "nx_seg_store.nx"
23import "nx_syscalls.nx"
24import "nx_gate_verdict.nx"
25
26const SG_DIR: *u8 = "/tmp/nx_segopen_absent_gate"
27const SG_PREFIX: *u8 = "/tmp/nx_segopen_absent_gate/soa-"
28const SG_ERR1: *u8 = "/tmp/nx_segopen_absent_gate/stderr-control.txt"
29const SG_ERR2: *u8 = "/tmp/nx_segopen_absent_gate/stderr-absent.txt"
30const SG_MODE_DIR: i64 = 493 // 0755
31const SG_MODE_FILE: i64 = 420 // 0644
32const SG_DOCS: i64 = 12 // docs in the ONE fixture segment; every one must read live in the control
33const SG_SEGCAP: i64 = 65536
34const SG_KIND_LIVE: i64 = 1
35const SG_KEYCAP: i64 = 64
36const SG_VALCAP: i64 = 64
37const SG_PATHCAP: i64 = 512
38const SG_SAVED_FD: i64 = 20 // where fd 2 is parked while an open's stderr is captured
39const SG_SUBJECTS: i64 = 3 // opens driven: control, absent-docs, restored
40
41func sg_key(out: *u8, i: i64) -> i64 {
42 // "doc:<i+1>" NUL-terminated -- the ONLY key shape ss_doc_count counts, so the index-side census is real
43 var o: i64 = 0
44 o = ss_cat(out, o, "doc:" as *u8)
45 o = ss_catn(out, o, i + 1)
46 out[o] = 0 as u8
47 return o
48}
49
50func sg_reset(prefix: *u8) -> i64 {
51 let mf: *u8 = sys_mmap(SG_PATHCAP)
52 var o: i64 = ss_cat(mf, 0, prefix)
53 o = ss_cat(mf, o, "manifest.txt" as *u8)
54 mf[o] = 0 as u8
55 let e: *u8 = sys_mmap(16)
56 ss_writefile(mf, e, 0)
57 return 0
58}
59
60// count live-map marks for segment s over the first n doc indexes -- the STATE the serve path reads
61func sg_marks(h: *i64, s: i64, n: i64) -> i64 {
62 let ns: i64 = h[0]
63 let lm: *u8 = h[1 + 8 * ns + s] as *u8
64 if (lm as i64) == 0 { return 0 - 1 }
65 var c: i64 = 0
66 var i: i64 = 0
67 while i < n { if lm[i] == (1 as u8) { c = c + 1 } i = i + 1 }
68 return c
69}
70
71func sg_seg_path(prefix: *u8, segname: *u8, suffix: *u8, out: *u8) -> i64 {
72 var o: i64 = ss_cat(out, 0, prefix)
73 o = ss_cat(out, o, segname)
74 o = ss_cat(out, o, suffix)
75 out[o] = 0 as u8
76 return o
77}
78
79func sg_contains(hay: *u8, hn: i64, needle: *u8) -> i64 {
80 var nn: i64 = 0
81 while needle[nn] != (0 as u8) { nn = nn + 1 }
82 if hn < nn { return 0 }
83 var i: i64 = 0
84 while i + nn <= hn {
85 var j: i64 = 0
86 var ok: i64 = 1
87 while j < nn { if hay[i + j] != needle[j] { ok = 0; break } j = j + 1 }
88 if ok == 1 { return 1 }
89 i = i + 1
90 }
91 return 0
92}
93
94// run ONE ss_open2 with fd 2 redirected to errpath, restore fd 2, return the handle
95func sg_open_captured(prefix: *u8, errpath: *u8) -> *i64 {
96 let efd: i64 = sys_openat_wr(errpath, SG_MODE_FILE)
97 sys_dup3(2, SG_SAVED_FD, 0)
98 if efd >= 0 { sys_dup3(efd, 2, 0) }
99 let h: *i64 = ss_open2(prefix, 1)
100 sys_dup3(SG_SAVED_FD, 2, 0)
101 if efd >= 0 { sys_close(efd) }
102 return h
103}
104
105func main(argc: i64, argv: *i64) -> i64 {
106 gv_head("nx_segopen_absent_gate -- ss_open2 fail-safe admission of an index-present / docs-absent segment" as *u8)
107 let ctr: *i64 = gv_ctr()
108 gv_subjects("shard opens driven" as *u8, SG_SUBJECTS, ctr)
109
110 sys_mkdir(SG_DIR, SG_MODE_DIR)
111 sg_reset(SG_PREFIX)
112
113 // ---- FIXTURE: one segment, SG_DOCS live docs, committed through the real writer ----
114 let wr: *i64 = ss_begin_cap(SG_SEGCAP)
115 let key: *u8 = sys_mmap(SG_KEYCAP)
116 let val: *u8 = sys_mmap(SG_VALCAP)
117 var i: i64 = 0
118 while i < SG_DOCS {
119 sg_key(key, i)
120 var vn: i64 = ss_cat(val, 0, "live doc number " as *u8)
121 vn = ss_catn(val, vn, i + 1)
122 val[vn] = 0 as u8
123 ss_add(wr, SG_KIND_LIVE, key, val, vn)
124 i = i + 1
125 }
126 let crc: i64 = ss_commit(SG_PREFIX, wr, ss_next_segid(SG_PREFIX))
127 gv_check("fixture-setup-commit-succeeded" as *u8, crc == 0, ctr)
128 // the segment NAME comes from the manifest the writer produced (ss_commit re-derives the id under lock)
129 let sp: *i64 = sys_mmap(8) as *i64
130 let ns0: i64 = ss_manifest_dyn(SG_PREFIX, sp)
131 let segs0: *i64 = sp[0] as *i64
132 gv_check("fixture-setup-manifest-names-exactly-one-segment" as *u8, ns0 == 1, ctr)
133 let segname: *u8 = sys_mmap(SG_KEYCAP)
134 var sno: i64 = 0
135 if ns0 >= 1 { sno = ss_cat(segname, 0, segs0[0] as *u8) }
136 segname[sno] = 0 as u8
137 if ns0 >= 1 { ss_manifest_free(segs0, ns0) }
138 var opened: i64 = 0
139
140 // ---- POSITIVE CONTROL: docs present -> every doc live, nothing announced ----
141 let h1: *i64 = sg_open_captured(SG_PREFIX, SG_ERR1)
142 opened = opened + 1
143 gv_check("control-open-sees-exactly-one-segment" as *u8, h1[0] == 1, ctr)
144 gv_check("control-docs-loaded-nonzero" as *u8, h1[4] > 0, ctr)
145 gv_check("control-index-loaded" as *u8, h1[2] >= 8, ctr)
146 gv_check("control-post-blob-loaded" as *u8, h1[8] >= 8, ctr)
147 gv_check("control-every-doc-marked-live" as *u8, sg_marks(h1, 0, SG_DOCS) == SG_DOCS, ctr)
148 gv_check("control-index-census-counts-every-doc" as *u8, ss_doc_count(h1) == SG_DOCS, ctr)
149 let e1n: *i64 = sys_mmap(16) as *i64
150 let e1: *u8 = ss_readall(SG_ERR1, e1n)
151 var e1len: i64 = e1n[0]
152 if e1len < 0 { e1len = 0 }
153 gv_check("neg-control-a-healthy-open-announces-no-skip" as *u8, sg_contains(e1, e1len, "SSOPEN SKIP" as *u8) == 0, ctr)
154 ss_close(h1)
155
156 // ---- REACH THE CONDITION: the manifest still names the segment, its .docs is gone, its .idx stays ----
157 let pdocs: *u8 = sys_mmap(SG_PATHCAP)
158 let phid: *u8 = sys_mmap(SG_PATHCAP)
159 sg_seg_path(SG_PREFIX, segname, ".docs" as *u8, pdocs)
160 sg_seg_path(SG_PREFIX, segname, ".docs.hidden" as *u8, phid)
161 let mrc: i64 = sys_renameat(pdocs, phid)
162 gv_check("fixture-reached-condition-docs-renamed-away" as *u8, mrc == 0, ctr)
163
164 let h2: *i64 = sg_open_captured(SG_PREFIX, SG_ERR2)
165 opened = opened + 1
166 // If the open crashed or spun, this line is never reached and the runner's timeout is the RED.
167 gv_check("absent-docs-open-returns-a-handle" as *u8, (h2 as i64) != 0, ctr)
168 gv_check("absent-docs-handle-still-names-the-segment" as *u8, h2[0] == 1, ctr)
169 // ss_loadfile reports an absent file as ss_readall's -1 and an empty one as 0: both are "did not load"
170 gv_check("fixture-reached-condition-docs-size-not-positive" as *u8, h2[4] <= 0, ctr)
171 gv_check("fixture-reached-condition-index-still-loaded" as *u8, h2[2] >= 8, ctr)
172 gv_check("fixture-reached-condition-post-blob-still-loaded" as *u8, h2[8] >= 8, ctr)
173 // THE LOAD-BEARING TOOTH: with no docs behind it, the segment must mark NOTHING live. Pre-fix the marks
174 // are written anyway (bounded by the .post count, not by the docs) -- for a 12-doc fixture they land
175 // inside the one page and read 12; on the 5.3M-entry web shard they landed past it.
176 gv_check("absent-docs-segment-marks-NO-doc-live" as *u8, sg_marks(h2, 0, SG_DOCS) == 0, ctr)
177 gv_check("index-census-still-sees-the-docs-so-the-skip-was-a-decision" as *u8, ss_doc_count(h2) == SG_DOCS, ctr)
178 let e2n: *i64 = sys_mmap(16) as *i64
179 let e2: *u8 = ss_readall(SG_ERR2, e2n)
180 var e2len: i64 = e2n[0]
181 if e2len < 0 { e2len = 0 }
182 gv_check("skip-is-ANNOUNCED-on-stderr" as *u8, sg_contains(e2, e2len, "SSOPEN SKIP seg=" as *u8) == 1, ctr)
183 gv_check("announce-names-the-condition" as *u8, sg_contains(e2, e2len, "docs-absent" as *u8) == 1, ctr)
184 ss_close(h2)
185
186 // ---- RESTORE and re-open: the marks return, proving the state was the FILE, not the code ----
187 let rrc: i64 = sys_renameat(phid, pdocs)
188 gv_check("fixture-restore-docs-renamed-back" as *u8, rrc == 0, ctr)
189 let h3: *i64 = ss_open2(SG_PREFIX, 1)
190 opened = opened + 1
191 gv_check("restored-docs-every-doc-marked-live-again" as *u8, sg_marks(h3, 0, SG_DOCS) == SG_DOCS, ctr)
192 ss_close(h3)
193
194 gv_check("denominator-every-declared-open-was-driven" as *u8, opened == SG_SUBJECTS, ctr)
195 return gv_verdict("nx_segopen_absent_gate" as *u8, ctr, "in-process over nx_seg_store ss_open2: an index-present / docs-absent manifest row contributes no live docs, is announced on stderr, and neither crashes nor spins the open" as *u8)
196}