code wiki / _hdl_build / nx_segbloom.nx

nx_segbloom.nx

buildroot/runtime/_hdl_build/nx_segbloom.nx

10071 B225 linesdepth 4pulls 6 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_segbloom.nx -- EVIDENCE FIRST: does a per-segment TERM BLOOM actually skip enough segments to be worth wiring into the hot search path? MEASURES ONLY. It writes nothing, changes no live code and touches no existing call site -- because the honest order is prove-the-win, then wire it. THE DEFECT IT TARGETS (measured 2026-08-06): /api/search costs a FIXED ~6.6s even for a query that matches ZERO documents, against a 42ms control on the same daemon. ss_term (nx_seg_store:2441) walks EVERY live segment and calls ss_terms_find on that segment's mmap'd terms block: while s < ns { let tb = h[5+8*s]; ss_terms_find(tb, h[6+8*s], term, outs) ... } The blocks are already mapped, so the cost is ONE PAGE FAULT PER SEGMENT -- ~896 segments x ~8ms. A resident bloom per segment answers "definitely not here" without touching the mapping at all, so the fault never happens. Segments are IMMUTABLE in an append-only store, which is what makes this sound: a per-segment term bloom is computed once and can never go stale. REUSE, NOT REINVENTION: the bloom is nx_sketch_bloom (v2, murmur3 + Kirsch-Mitzenmacher double hashing, already used in production by nx_ingest_runner) and the bits/item + k constants are the pre-computed FPR breakpoints from nx_bloom_capacity. Nothing here is a new filter. nx_segbloom stat <domain> [maxsegs] nx_segbloom probe <domain> <profile 1=10pct|2=1pct> <term> [maxsegs] license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 3 imports · 0 importers

nx_seg_store.nx nx_sketch_bloom.nx nx_syscalls.nx nx_segbloom.nx

imports: nx_seg_store.nxnx_sketch_bloom.nxnx_syscalls.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main sb_puts sb_w sys_write sb_slen sys_exit sb_slen ↻ sb_atoi cmd_stat sb_open sys_mmap nxa_die sys_write ↻ sys_exit ↻ nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sb_prefix sb_cat sb_puts ↻ ss_open2 ss_open3 sys_now_us sys_mmap ↻ sys_clock_gettime_mono sys_mmap ↻ ss_manifest_dyn ss_manifest_file_dyn ss3_admit ss3_ann sys_now_us ↻ ss3_streq

structs

none

consts

25const SB_PATHCAP: i64 = 512
26const SB_SMALL: i64 = 64
27const SB_MAXSEGS: i64 = 8192
29const SB_BITS_10PCT: i64 = 5
30const SB_K_10PCT: i64 = 3
31const SB_BITS_1PCT: i64 = 10
32const SB_K_1PCT: i64 = 7

functions

34func sb_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
35func sb_w(s: *u8, n: i64) -> i64 { sys_write(1, s, n); return 0 }
called by 3: sb_putssb_numcmd_probe calls 1: sys_write
36func sb_puts(s: *u8) -> i64 { sb_w(s, sb_slen(s)); return 0 }
37func sb_num(v: i64) -> i64
50func sb_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o+i] = s[i]; i = i + 1 } return o + i }
called by 1: sb_prefix
53func sb_prefix(domain: *u8, out: *u8) -> i64
called by 1: sb_open calls 1: sb_cat
61func sb_next_pow2(n: i64) -> i64
called by 1: cmd_probe
66func sb_open(domain: *u8) -> *i64
74func cmd_stat(domain: *u8, maxsegs: i64) -> i64
103func cmd_probe(domain: *u8, profile: i64, term: *u8, maxsegs: i64) -> i64
190func sb_atoi(s: *u8) -> i64
called by 1: main
202func main(argc: i64, argv: *i64) -> i64