nx_mvault_walk.nx
buildroot/runtime/nx_mvault_walk.nx
about
nx_mvault_walk.nx -- the LIVE reindex DRIVER, VW02 (MV-1 bulk-migration engine).
VW01 was a single-level, full-read walk: it SKIPPED >512MiB files (seq119 OOM
guard) -- i.e. most cam recordings -- and its one-reg_put-per-item store path
would have both crawled (a new segment per put) and corrupted the ids index
past ~15k items (fixed 1MiB index buffer). VW02 is the measured rebuild:
* RECURSIVE: iterative BFS dir queue, ONE shared getdents buffer.
* STREAMING CID: every file hashes in chunks (the head window doubles as
the sniff bytes) -- nothing is skipped for size, RAM is O(1) per file.
* IN-MEMORY DEDUP SETS seeded once from mv:ids / p:ids -- zero per-file
store reads; BATCHED commits (one segment per ~24MiB of records, not one
per item) -- the seg-store quadratic + index-rewrite blowup is dodged.
* PATH-RESUME PLANE knowledge/store/mvaultpath-: key p:<cid of "path|size">,
val = content CID. Re-runs skip already-hashed unchanged paths (daily DVR
ingest = incremental by design). Size-keyed, not mtime-keyed: recordings
are append-once; an in-place same-size rewrite would be missed (declared).
* BG MODE (`bg <logfile>`): forks a detached worker; fds 0/1/2 close so the
tools-daemon capture pipe EOFs immediately; progress + final JSON append
to <logfile>. TB-scale hashing runs for hours -- a synchronous MCP call
drops its response at ~15s.
* POLICY FILTERS (counted, never silent): dot-names skipped (.trickplay
sidecar dirs), *-poster.jpg sidecars skipped, 0-byte files skipped
(hard-crash torn artifacts must not become vault records).
* selftest: KAT-anchored teeth, emits verdict=GREEN|RED (D001 anchor).
RECORD-ONLY = NON-MUTATING BY CONSTRUCTION (unchanged): never moves a byte;
only the seg-store index planes are written (and only on commit).
ENVELOPE (declared): set ~950k cids / queue 16MiB dirs / ids blob 64MiB --
overflow sets fatal=1 in the output, never a silent cap.
nx_mvault_walk <dir> <gen|real> <source> [commit|dry] [bg <logfile>]
nx_mvault_walk selftest
license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 13 imports · 0 importers
diagram shows first 10 each side; +3 more imports, +0 more importers in the complete lists below.
imports: nx_syscalls.nxnx_sha256.nxnx_canon_cid.nxnx_proc_ctl.nxnx_media_pool.nxnx_media_sniff.nxnx_mvault_ingest.nxnx_mvault_context.nxnx_mvault_record.nxnx_mvault_layout.nxnx_mvault_reclaim.nxnx_mvault_reindex.nxnx_seg_store.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 45 | const MW_MAGIC_4096: i64 = 4096 |
| 46 | const MW_MAGIC_8192: i64 = 8192 |
| 47 | const MW_MAGIC_8191: i64 = 8191 |
| 48 | const MW_MAGIC_300000: i64 = 300000 |
| 49 | const MW_MAGIC_1024: i64 = 1024 |
| 51 | const MW_DIRBUF: i64 = 1048576 // 1 MiB getdents buffer (shared; BFS reuses it) |
| 52 | const MW_PATH: i64 = 4096 |
| 53 | const MW_LARGE: i64 = 104857600 // 100 MiB -> "large file surfaced for value review" |
| 54 | const MW_HEAD: i64 = 1048576 // head window: sniff bytes + first hash read |
| 55 | const MW_CHUNK: i64 = 4194304 // 4 MiB streaming read chunk |
| 56 | const MW_QCAP: i64 = 16777216 // dir-queue arena (~280k dirs) |
| 57 | const MW_SETSLOTS: i64 = 1048576 // dedup hash slots (pow2; fills at 75%) |
| 58 | const MW_SETARENA: i64 = 67108864 // 64 MiB cid arena (~950k cids) |
| 59 | const MW_IDSCAP: i64 = 67108864 // ids-index blob cap (rewritten per flush) |
| 60 | const MW_WCAP: i64 = 33554432 // 32 MiB batch writer buffer |
| 61 | const MW_FLUSH: i64 = 25165824 // flush a batch past 24 MiB of records |
| 62 | const MW_PROG: i64 = 256 // progress line every N hashed files (bg) |
| 63 | const MW_OLDMAX: i64 = 536870912 // VW01's skip threshold -- now just a counter |
| 413 | const MW_HB_SECS: i64 = 30 |
| 628 | const MW_VM_ITERS: i64 = 200 |
| 634 | const MW_VM_SLACK_KB: i64 = 850 |
functions
| 65 | func mw_seq(a: *u8, b: *u8) -> i64 called by 1: main |
| 76 | func mw_join(dst: *u8, dir: *u8, name: *u8) -> i64 called by 1: mw_run |
| 89 | func mw_ext(name: *u8, ext: *u8) -> i64 called by 1: mw_run |
| 110 | func mw_ch(dst: *u8, off: i64, c: i64) -> i64 { dst[off] = c as u8; return off + 1 } |
| 111 | func mw_cat(dst: *u8, off: i64, s: *u8) -> i64 |
| 118 | func mw_udec(dst: *u8, off: i64, v: i64) -> i64 |
| 136 | func mw_is_poster(name: *u8) -> i64 called by 1: mw_run |
| 151 | func mws_new() -> *i64 |
| 162 | func mws_hash(cid: *u8) -> i64 |
| 174 | func mws_eq(a: *u8, b: *u8) -> i64 |
| 179 | func mws_has(h: *i64, cid: *u8) -> i64 |
| 193 | func mws_add(h: *i64, cid: *u8) -> i64 |
| 217 | func mw_load_ids(prefix: *u8, idxkey: *u8, h: *i64, blob: *u8, bloblen: *i64) -> i64 |
| 248 | func mw_sha_free(c: *Sha256) -> i64 |
| 260 | func mw_hash_file(path: *u8, ctx: *Sha256, headbuf: *u8, chunkbuf: *u8, called by 2: mw_runmw_selftest calls 8: sys_openat_rdsha256_initsys_readsha256_updatesys_closesha256_final+2 |
| 304 | func mw_pathkey(path: *u8, sz: i64, ctx: *Sha256, pkbuf: *u8, dg: *u8, pkcid: *u8) -> i64 |
| 320 | func mw_ids_append(idsbuf: *u8, lenbox: *i64, cid: *u8) -> i64 called by 1: mw_run |
| 331 | func mw_add_rec(wbox: *i64, kp: *u8, cid: *u8, val: *u8, vlen: i64, kbuf: *u8) -> i64 |
| 342 | func mw_flush_plane(prefix: *u8, wbox: *i64, idxkey: *u8, idsbuf: *u8, idslen: i64) -> i64 |
| 358 | func mw_prog(logfd: i64, st: *i64, buf: *u8) -> i64 |
| 372 | func mw_fail(out: *u8, msg: *u8) -> i64 |
| 381 | func mw_emit(out: *u8, st: *i64, commit: i64) -> i64 |
| 415 | func mw_run(root: *u8, prov: i64, source: *u8, commit: i64, called by 2: mw_selftestmain calls 37: mv_classsys_now_realtime_secsys_mmapmv_reclaim_newmws_newmw_load_ids+31 |
| 602 | func mw_st_write(path: *u8, bytes: *u8, n: i64) -> i64 |
| 616 | func mw_st_tooth(name: *u8, ok: i64, passbox: *i64) -> i64 |
| 635 | func mw_vmsize() -> i64 |
| 674 | func mw_selftest() -> i64 |
| 843 | func main(argc: i64, argv: *i64) -> i64 |