code wiki / _hdl_build / nx_store_query.nx
nx_store_query.nx source
↩ module page · 212 lines · 6888 B
1// nx_store_query.nx -- the FRONT DOOR to the sovereign information store
2// (knowledge/store/im-*). Pure NishiLang, NO SQL -- the operator's queryable
3// interface to the team's own substrate:
4// get <key> latest record state (FOUND + printable dump / GONE / ABSENT)
5// term <word> full-text term search, current-state semantics
6// and <w1> <w2>..multi-term AND search (up to 8 terms, postings-driven
7// intersection, same current-state semantics)
8// hist <key> every stored version, oldest -> newest (the time-travel surface)
9// histall <key> FULL history incl. compaction-archived segments (labeled)
10// compact fold live segments (also the FORMAT-UPGRADE path: old
11// segments without .terms become searchable after compaction)
12// license_tier: ORIGINAL
13
14import "nx_syscalls.nx"
15import "nx_seg_store.nx"
16
17func sq_p(s: *u8) -> i64 {
18 var n: i64 = 0
19 while s[n] != (0 as u8) { n = n + 1 }
20 sys_write(1, s, n)
21 return 0
22}
23
24func sq_pn(v: i64) -> i64 {
25 let bb: *u8 = sys_mmap(28)
26 var m: i64 = v
27 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
28 let t: *u8 = sys_mmap(28)
29 var k: i64 = 0
30 if m == 0 { t[0] = 48 as u8; k = 1 }
31 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
32 var i: i64 = 0
33 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
34 sys_write(1, bb, k)
35 return 0
36}
37
38func sq_streq(a: *u8, b: *u8) -> i64 {
39 var i: i64 = 0
40 while 1 == 1 {
41 if a[i] != b[i] { return 0 }
42 if a[i] == (0 as u8) { return 1 }
43 i = i + 1
44 }
45 return 0
46}
47
48// print bytes with non-printables as '.' (canonical records hold binary lengths)
49func sq_dump(p: *u8, n: i64) -> i64 {
50 let ob: *u8 = sys_mmap(n + 8)
51 var i: i64 = 0
52 while i < n {
53 var c: i64 = p[i]
54 if c < 32 { c = 46 }
55 if c > 126 { c = 46 }
56 ob[i] = c as u8
57 i = i + 1
58 }
59 sys_write(1, ob, n)
60 return 0
61}
62
63func main(argc: i64, argv: *i64) -> i64 {
64 let prefix: *u8 = "knowledge/store/im-" as *u8
65 if argc < 2 {
66 sq_p("usage: nx_store_query <get <key>|term <word>|and <w1> <w2>..|hist <key>|histall <key>|compact>\n" as *u8)
67 return 2
68 }
69 let cmd: *u8 = argv[1] as *u8
70
71 if sq_streq(cmd, "compact" as *u8) == 1 {
72 let rid: i64 = ss_compact(prefix, sys_now_us())
73 if rid > 0 {
74 sq_p("COMPACTED -> seg-" as *u8)
75 sq_pn(rid)
76 sq_p(" (history archived in manifest-archive.txt)\n" as *u8)
77 return 0
78 }
79 sq_p("COMPACT FAILED rc=" as *u8)
80 sq_pn(rid)
81 sq_p("\n" as *u8)
82 return 1
83 }
84
85 if argc < 3 {
86 sq_p("usage: nx_store_query <get <key>|term <word>|and <w1> <w2>..|hist <key>|histall <key>|compact>\n" as *u8)
87 return 2
88 }
89 let arg: *u8 = argv[2] as *u8
90
91 if sq_streq(cmd, "get" as *u8) == 1 {
92 let h: *i64 = ss_open(prefix)
93 let pp: *i64 = sys_mmap(16) as *i64
94 let ll: *i64 = sys_mmap(16) as *i64
95 let g: i64 = ss_hget(h, arg, pp, ll)
96 if g == 1 {
97 sq_p("FOUND len=" as *u8)
98 sq_pn(ll[0])
99 sq_p(" :: " as *u8)
100 sq_dump(pp[0] as *u8, ll[0])
101 sq_p("\n" as *u8)
102 return 0
103 }
104 if g == 0 { sq_p("GONE (tombstoned; history retains prior versions)\n" as *u8); return 0 }
105 sq_p("ABSENT\n" as *u8)
106 return 1
107 }
108
109 if sq_streq(cmd, "term" as *u8) == 1 {
110 let h: *i64 = ss_open(prefix)
111 let kp: *i64 = sys_mmap(8 * 256) as *i64
112 let kl: *i64 = sys_mmap(8 * 256) as *i64
113 let n: i64 = ss_term(h, arg, kp, kl, 256)
114 if n == (0 - 2) {
115 sq_p("OLD-FORMAT segment(s) lack a term index -- run: nx_store_query compact\n" as *u8)
116 return 1
117 }
118 sq_p("MATCHES " as *u8)
119 sq_pn(n)
120 sq_p("\n" as *u8)
121 var i: i64 = 0
122 while i < n {
123 sq_p(" " as *u8)
124 sys_write(1, kp[i] as *u8, kl[i])
125 sq_p("\n" as *u8)
126 i = i + 1
127 }
128 return 0
129 }
130
131 if sq_streq(cmd, "and" as *u8) == 1 {
132 var nt: i64 = argc - 2
133 if nt > 8 { nt = 8 }
134 let terms: *i64 = sys_mmap(8 * 8) as *i64
135 var ti: i64 = 0
136 while ti < nt { terms[ti] = argv[2 + ti]; ti = ti + 1 }
137 let h: *i64 = ss_open(prefix)
138 let kp: *i64 = sys_mmap(8 * 256) as *i64
139 let kl: *i64 = sys_mmap(8 * 256) as *i64
140 let n: i64 = ss_term_and(h, terms, nt, kp, kl, 256)
141 if n == (0 - 2) {
142 sq_p("OLD-FORMAT segment(s) lack a term index -- run: nx_store_query compact\n" as *u8)
143 return 1
144 }
145 sq_p("MATCHES " as *u8)
146 sq_pn(n)
147 sq_p(" (current records containing ALL " as *u8)
148 sq_pn(nt)
149 sq_p(" terms)\n" as *u8)
150 var i: i64 = 0
151 while i < n {
152 sq_p(" " as *u8)
153 sys_write(1, kp[i] as *u8, kl[i])
154 sq_p("\n" as *u8)
155 i = i + 1
156 }
157 return 0
158 }
159
160 if sq_streq(cmd, "histall" as *u8) == 1 {
161 let kinds: *i64 = sys_mmap(8 * 260) as *i64
162 let ptrs: *i64 = sys_mmap(8 * 260) as *i64
163 let lens: *i64 = sys_mmap(8 * 260) as *i64
164 let srcs: *i64 = sys_mmap(8 * 260) as *i64
165 let n: i64 = ss_scan_all(prefix, arg, kinds, ptrs, lens, srcs)
166 sq_p("VERSIONS " as *u8)
167 sq_pn(n)
168 sq_p(" (FULL history: compaction-archived segments + live)\n" as *u8)
169 var i: i64 = 0
170 while i < n {
171 sq_p(" v" as *u8)
172 sq_pn(i)
173 if srcs[i] == 0 { sq_p(" ARCHIVED" as *u8) } else { sq_p(" LIVE" as *u8) }
174 if kinds[i] == 2 { sq_p(" TOMBSTONE\n" as *u8) } else {
175 sq_p(" len=" as *u8)
176 sq_pn(lens[i])
177 sq_p(" :: " as *u8)
178 sq_dump(ptrs[i] as *u8, lens[i])
179 sq_p("\n" as *u8)
180 }
181 i = i + 1
182 }
183 return 0
184 }
185
186 if sq_streq(cmd, "hist" as *u8) == 1 {
187 let kinds: *i64 = sys_mmap(8 * 260) as *i64
188 let ptrs: *i64 = sys_mmap(8 * 260) as *i64
189 let lens: *i64 = sys_mmap(8 * 260) as *i64
190 let n: i64 = ss_scan(prefix, arg, kinds, ptrs, lens)
191 sq_p("VERSIONS " as *u8)
192 sq_pn(n)
193 sq_p(" (live segments only; compacted history in archive)\n" as *u8)
194 var i: i64 = 0
195 while i < n {
196 sq_p(" v" as *u8)
197 sq_pn(i)
198 if kinds[i] == 2 { sq_p(" TOMBSTONE\n" as *u8) } else {
199 sq_p(" len=" as *u8)
200 sq_pn(lens[i])
201 sq_p(" :: " as *u8)
202 sq_dump(ptrs[i] as *u8, lens[i])
203 sq_p("\n" as *u8)
204 }
205 i = i + 1
206 }
207 return 0
208 }
209
210 sq_p("unknown command\n" as *u8)
211 return 2
212}