code wiki / _hdl_build / nx_web_shard_compact.nx

nx_web_shard_compact.nx

buildroot/runtime/_hdl_build/nx_web_shard_compact.nx

18606 B363 linesdepth 4pulls 7 transitivereach 0 importersview sourcekind tooltopic web
docsdependenciesstructsconstsfunctions

about

nx_web_shard_compact.nx -- SCALE compaction for big multi-segment shards (the web shard's rung). ss_compact/ss_compact_cap have EXACT semantics (last entry per key wins, tombstones kept, retired segments archived then an atomic manifest swap) but their key dedup is a LINEAR table scan = O(entries^2): fine at 4k keys, unusable at the web shard's ~1.4M entries (bulk docs + pr: priors). This organ is the same merge with an open-addressing HASH dedup = O(entries), plus a post-swap verification pass. Semantics kept byte-equal to ss_compact: chronological walk, last wins, ALL kinds carried (incl. kind-2 tombstones), archive-before-swap, every failure path returns BEFORE the swap. BYTE-BUDGETED SUFFIX FOLD (2026-07-29): an unbounded whole-shard merge materializes the merged segment in anonymous RAM (the writer buffer, plus aux blobs and key tables that all scale with merged bytes) -- the OOM killer reaped it twice at bytes-in=1883885124 on 2026-07-25, mid-merge, before the swap (never-brick held; shard untouched). The merge therefore now folds the LONGEST NEWEST contiguous manifest suffix whose .docs bytes fit a budget derived from the box itself (MemAvailable/WSC_BUDGET_SHARE; argv[2] in MB overrides). Replacing a contiguous suffix with its fold preserves last-wins semantics EXACTLY: the run is merged in chronological order, kind-2 tombstones are carried, and older (kept) segments remain shadowed by the merged tail precisely as they were by the unmerged tail. Repeated runs converge the shard LSM-style with bounded memory; a streaming (file-backed) writer that lifts the budget entirely is the named next rung. usage: nx_web_shard_compact <domain> [budget-MB] license_tier: ORIGINAL

dependencies 1 imports · 0 importers

nx_docportal_search_seg.nx nx_web_shard_compact.nx

imports: nx_docportal_search_seg.nx

imported by: nobody (leaf or entry point)

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

main dss_prefix sys_openat_append wc9_puts sys_flock ss_manifest_cap ss_manifest_file_cap sys_mmap ss_cat ss_readall sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_close wc9_num wsc_memavail sys_read ↻ ss_loadfile sys_map_file sys_openat_rd ↻ sys_lseek ↻ sys_close ↻ ss_readall ↻ ss_r32 wsc_slot ss_kcmp ss_begin_cap sys_mmap ↻ ss_add2 ss_w32 ss_write_seg ss_segid_ok sys_mmap ↻ ss_cat ↻ ss_catn sys_mmap ↻ sys_write ss_segname ss_cat ↻

structs

none

consts

22const WSC_MAGIC_1125899906842597: i64 = 1125899906842597
23const WSC_MAGIC_1048576: i64 = 1048576
24const WSC_MAGIC_65536: i64 = 65536
26const WSC_MAXSEGS: i64 = 8192 // manifest lines we can fold in one run
27const WSC_MAXENT: i64 = 134217728 // hard sanity ceiling on entries (2^27; ~an order past any near plan)
28const WSC_HMUL: i64 = 7046029254386353131 // odd 63-bit multiplicative-mix constant (same family as pagerank_build)
29const WSC_BUDGET_SHARE: i64 = 32 // /32 (was /16) 2026-07-30: the /16 reasoning below is RIGHT about the 9-10x amplification but it reserves a share of MemAvailable AT START on a box with OTHER GROWING CONSUMERS (torrent stack, jellyfin, syno services) -- the share is stale the moment it is computed, and it assumes this job is the only claimant. MEASURED TODAY: with ~25GB available at start the /16 budget projected a peak of ~15GB and this organ was caught at 21GB RSS with 536MB free, minutes from OOM, taking mgmt + the tools daemon down with it. /32 projects ~7-8GB, which also keeps it clear of the 16GiB RLIMIT_AS ceiling now imposed by hc_spawn_searchpipe_job -- TWO CONTROLS THAT CONTRADICT EACH OTHER ARE ONE CONTROL AND ONE OUTAGE, so the soft budget must project a peak BELOW the hard cap. Original note, still accurate on the amplification: fold budget = MemAvailable/16. MEASURED 2026-07-29 (death #3, OOM in ss_build_terms): a 1.88GB run took MemAvailable from 19.4GB to 1.2GB before the kill => PEAK TOUCH ~9-10x run bytes (occ arrays + pairs + writer + key tables + input page cache), not the ~6x the seq1048 memo estimated. /16 caps projected peak at ~60% of MemAvailable so the box keeps serving
30const WSC_BUDGET_FALLBACK: i64 = 268435456 // 256MB: used ONLY when /proc/meminfo is unreadable -- conservative enough to be safe on any box that boots this stack, keeps the pinned no-arg hostctl sub from wedging into a permanent refuse
31const WSC_BUDGET_FLOOR: i64 = 67108864 // 64MB: below this the box is too tight to merge anything safely -> refuse loudly rather than thrash
32const WSC_LOCK_EX: i64 = 2 // flock LOCK_EX on <prefix>plock -- the plane-lock discipline segguard + nx_seg_compact_cli already honor; a lockless manifest swap under a concurrent fold LOSES rows (the proven seq349 race)
33const WSC_MEMINFO_BUF: i64 = 8192 // scratch size for the bounded /proc/meminfo read (file is ~1.5KB)
34const WSC_MEMINFO_CAP: i64 = 7900 // read cap under the scratch -- headroom below WSC_MEMINFO_BUF
35const WSC_KB: i64 = 1024 // /proc/meminfo reports MemAvailable in kB

functions

37func wc9_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
called by 1: main
38func wc9_num(v: i64) -> i64
called by 1: main
49func wsc_slot(k: *u8, kl: i64, hshift: i64, hmask: i64) -> i64
called by 1: main
61func wsc_memavail() -> i64
called by 1: main calls 1: sys_read
100func main(argc: i64, argv: *i64) -> i64