code wiki / _hdl_build / nx_livemap_fast.nx

nx_livemap_fast.nx source

↩ module page · 128 lines · 5228 B

1// nx_livemap_fast.nx -- LINEAR live-doc map construction, to replace the quadratic one in ss_open2. 2// 3// THE PROBLEM (nx_seg_store.nx:1739-1790): for every key in every segment, the current code scans 4// EVERY NEWER SEGMENT calling ss_idx_find to ask `has a later segment shadowed this key`. That is 5// O(keys x segments) index probes -- tens of millions on the live 94-segment web shard -- and it is 6// QUADRATIC IN SEGMENT COUNT, so it degrades every time the crawler commits. It is the measured 7// cause of the ~8 minute docportal pre-warm and, through that, of tonight's search wedge. 8// 9// THE INSIGHT: the shadow question is `does any NEWER segment know this key`. Answering it per-key 10// by rescanning newer segments repeats the same work once per key. Walk the segments ONCE from 11// NEWEST to OLDEST instead, recording the first (= newest) segment that knows each key. Then a key 12// in segment s is shadowed iff its recorded newest segment is greater than s. One pass, one probe. 13// 14// NOTHING HERE IS WIRED INTO PRODUCTION. This file only ADDS functions; ss_open2 is untouched. The 15// companion gate proves this produces BYTE-IDENTICAL maps to the existing implementation on the real 16// shard before anyone considers swapping. A faster live-doc map that is subtly different does not 17// make search quick, it makes search WRONG -- these maps decide which documents are visible at all. 18// license_tier: ORIGINAL No hw writes (Rule 26). 19import "nx_seg_store.nx" 20const LMF_MAGIC_16777619: i64 = 16777619 21 22const LMF_LOAD_NUM: i64 = 2 // table sized 2x key count: open addressing wants <=50% load 23const LMF_EMPTY: i64 = 0 - 1 24 25// Round up to a power of two so the probe can mask instead of divide. 26func lmf_pow2(n: i64) -> i64 { 27 var p: i64 = 16 28 while p < n { p = p * 2 } 29 return p 30} 31 32// Total key-index entries across all segments -- sizes the table in one cheap pass. 33func lmf_total_keys(h: *i64, ns: i64) -> i64 { 34 var t: i64 = 0 35 var s: i64 = 0 36 while s < ns { 37 let kb: *u8 = h[1 + 8 * s] as *u8 38 let ksz: i64 = h[2 + 8 * s] 39 if ksz >= 8 { t = t + ss_r32(kb, 4) } 40 s = s + 1 41 } 42 return t 43} 44 45// Compare a key stored in segment `seg` at entry offset `eo` against a candidate byte range. 46func lmf_key_eq(h: *i64, seg: i64, eo: i64, kb2: *u8, eo2: i64) -> i64 { 47 let kb: *u8 = h[1 + 8 * seg] as *u8 48 let kl: i64 = ss_r32(kb, eo + 1) 49 let kl2: i64 = ss_r32(kb2, eo2 + 1) 50 if kl != kl2 { return 0 } 51 var i: i64 = 0 52 while i < kl { 53 if kb[eo + 5 + i] != kb2[eo2 + 5 + i] { return 0 } 54 i = i + 1 55 } 56 return 1 57} 58 59// FNV over the key bytes of one index entry. 60func lmf_hash_entry(kb: *u8, eo: i64) -> i64 { 61 let kl: i64 = ss_r32(kb, eo + 1) 62 var hsh: i64 = 0x811c9dc5 63 var i: i64 = 0 64 while i < kl { 65 hsh = hsh ^ (kb[eo + 5 + i] as i64) 66 hsh = (hsh * LMF_MAGIC_16777619) & 0xffffffff 67 i = i + 1 68 } 69 return hsh 70} 71 72// Build key -> NEWEST segment that knows it. tbl_seg/tbl_eo are parallel arrays of size cap. 73// Walking newest-first and refusing to overwrite an occupied slot means the FIRST writer wins, 74// which is by construction the newest segment. No comparison of segment numbers is needed. 75func lmf_build(h: *i64, ns: i64, tbl_seg: *i64, tbl_eo: *i64, cap: i64) -> i64 { 76 var i: i64 = 0 77 while i < cap { tbl_seg[i] = LMF_EMPTY; i = i + 1 } 78 let mask: i64 = cap - 1 79 var inserted: i64 = 0 80 var s: i64 = ns - 1 81 while s >= 0 { 82 let kb: *u8 = h[1 + 8 * s] as *u8 83 let ksz: i64 = h[2 + 8 * s] 84 if ksz >= 8 { 85 let m: i64 = ss_r32(kb, 4) 86 var e: i64 = 0 87 while e < m { 88 let eo: i64 = 8 + 4 * m + ss_r32(kb, 8 + 4 * e) 89 let kl: i64 = ss_r32(kb, eo + 1) 90 if kl < 500 { 91 var slot: i64 = lmf_hash_entry(kb, eo) & mask 92 var placed: i64 = 0 93 while placed == 0 { 94 if tbl_seg[slot] == LMF_EMPTY { 95 tbl_seg[slot] = s 96 tbl_eo[slot] = eo 97 inserted = inserted + 1 98 placed = 1 99 } else { 100 if lmf_key_eq(h, tbl_seg[slot], tbl_eo[slot], kb, eo) == 1 { 101 placed = 1 // already recorded by a NEWER segment: keep it 102 } else { 103 slot = (slot + 1) & mask 104 } 105 } 106 } 107 } 108 e = e + 1 109 } 110 } 111 s = s - 1 112 } 113 return inserted 114} 115 116// Newest segment known to contain the key at (kb, eo); -1 if absent. 117func lmf_lookup(h: *i64, tbl_seg: *i64, tbl_eo: *i64, cap: i64, kb: *u8, eo: i64) -> i64 { 118 let mask: i64 = cap - 1 119 var slot: i64 = lmf_hash_entry(kb, eo) & mask 120 var guard: i64 = 0 121 while guard < cap { 122 if tbl_seg[slot] == LMF_EMPTY { return 0 - 1 } 123 if lmf_key_eq(h, tbl_seg[slot], tbl_eo[slot], kb, eo) == 1 { return tbl_seg[slot] } 124 slot = (slot + 1) & mask 125 guard = guard + 1 126 } 127 return 0 - 1 128}