code wiki / _hdl_build / nx_dr_incremental.nx

nx_dr_incremental.nx source

↩ module page · 94 lines · 6383 B

1// nx_dr_incremental.nx -- CAP-DR-INCREMENTAL: only re-copy CHANGED files (incremental backup, rsync/restic-style). 2// Reads the prior ARCHIVE_RECEIPT.tsv (name<TAB>sha256), and for each manifest source computes sha256; if the 3// receipt already has that name with the SAME hash -> SKIP (unchanged); else copy + verify + record. Writes a fresh 4// receipt covering all current files. Turns an O(all-bytes) re-archive into O(changed-bytes) -- the difference 5// between backing up 957 B and backing up 40 GB of galx every run. argv: [1]=manifest [2]=archive-dir. 6// Additive-safe (reads sources, writes only the archive dir). license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_site_lock_lib.nx" 9import "nx_sha256.nx" 10import "nx_seg_store.nx" 11const IN_MAGIC_1536: i64 = 1536 12const IN_MAGIC_262144: i64 = 262144 13const IN_MAGIC_1024: i64 = 1024 14 15const IN_CAP: i64 = 67108864 16 17func in_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 18func in_wn(v: i64) -> i64 { var t: i64=v; if t<0{sys_write(1,"-" as *u8,1);t=0-t} let tm:*u8=sys_mmap(24); var k:i64=0; if t==0{tm[0]=48 as u8;k=1} while t>0{tm[k]=(48+(t%10)) as u8;t=t/10;k=k+1} let b:*u8=sys_mmap(24); var j:i64=0; while j<k{b[j]=tm[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 19func in_read(path: *u8, out: *u8, cap: i64) -> i64 { 20 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 - 1 } 21 var total: i64 = 0; var go: i64 = 1 22 while go == 1 { let nr: i64 = sys_read(fd, (out as i64 + total) as *u8, cap - total); if nr <= 0 { go = 0 } if nr > 0 { total = total + nr } if total >= cap { go = 0 } } 23 sys_close(fd); return total 24} 25func in_write(path: *u8, buf: *u8, n: i64) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd < 0 { return 0 - 1 } sys_write(fd, buf, n); sys_close(fd); return n } 26func in_join(out: *u8, dir: *u8, name: *u8) -> i64 { var o: i64=0; var i: i64=0; while dir[i]!=(0 as u8){out[o]=dir[i];o=o+1;i=i+1} out[o]=47 as u8; o=o+1; i=0; while name[i]!=(0 as u8){out[o]=name[i];o=o+1;i=i+1} out[o]=0 as u8; return o } 27func in_field(reg: *u8, ls: i64, le: i64, f: i64, out: *u8, cap: i64) -> i64 { 28 let fs: *i64=sys_mmap(8); let fe: *i64=sys_mmap(8) 29 if slk_field(reg, ls, le, f, fs, fe) == 1 { var o: i64=0; let l: i64=fe[0]-fs[0]; while o<l { if o<cap-1 { out[o]=reg[fs[0]+o] } o=o+1 } out[o]=0 as u8; return l } 30 out[0]=0 as u8; return 0 31} 32func in_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8) { if a[i]!=b[i] { return 0 } i=i+1 } if b[i]!=(0 as u8) { return 0 } return 1 } 33func in_hex(buf: *u8, n: i64, out: *u8) -> i64 { 34 let dig: *u8 = sys_mmap(64); sha256_digest(buf, n, dig) 35 let hx: *u8 = "0123456789abcdef" as *u8 36 var h: i64=0; while h<32 { let by: i64=(dig[h] as i64)&0xff; out[h*2]=hx[(by>>4)&15]; out[h*2+1]=hx[by&15]; h=h+1 } out[64]=0 as u8; return 0 37} 38// look up `name`'s prior hash in the SOVEREIGN receipt (nx_seg_store ss_get, binary-search .keys); copy 64-hex to 39// out; 1 found / 0 absent. No TSV scan. 40func in_prior_hash(rprefix: *u8, name: *u8, out: *u8) -> i64 { 41 let pq: *i64 = sys_mmap(16) as *i64; let lq: *i64 = sys_mmap(16) as *i64 42 if ss_get(rprefix, name, pq, lq) == 1 { let v: *u8 = pq[0] as *u8; var i: i64=0; while i<64 { out[i]=v[i]; i=i+1 } out[64]=0 as u8; return 1 } 43 return 0 44} 45 46func main(argc: i64, argv: *i64) -> i64 { 47 if argc < 3 { in_w("usage: nx_dr_incremental <manifest> <archive-dir>\n" as *u8); sys_exit(2); return 2 } 48 let manifest: *u8 = argv[1] as *u8; let adir: *u8 = argv[2] as *u8 49 in_w("=== nx_dr_incremental: only re-copy CHANGED files (skip unchanged by hash) ===\n" as *u8) 50 sys_mkdir(adir, 0x1ed) 51 52 // SOVEREIGN receipt: prior read via ss_get, new written via ss_begin/ss_commit (append-only segment) -- NO TSV 53 let rprefix: *u8 = sys_mmap(IN_MAGIC_1536); in_join(rprefix, adir, "receipt" as *u8) 54 // ROOT FIX (count-as-segid, id 1785519700): ss_manifest RETURNS THE ROW COUNT, not an id. Past 55 // SS_MANIFEST_LEGACY_CAP (256) the count PINS at 256, so every later write reuses id 257 and OVERWRITES 56 // the previous segment -- data loss by CLOBBER (distinct from the seq1730 pointer poison, which loses 57 // data by SHADOWING). ss_next_segid parses the real ids and is what the lib header prescribes. 58 // The ss_segs[] buffer was filled and never read, so it goes with the call. 59 let ss_segid: i64 = ss_next_segid(rprefix) 60 let w: *i64 = ss_begin() 61 62 let reg: *u8 = sys_mmap(IN_MAGIC_262144); let rn: i64 = in_read(manifest, reg, IN_MAGIC_262144) 63 if rn <= 0 { in_w(" FATAL: cannot read manifest\n" as *u8); sys_exit(3); return 3 } 64 65 let src: *u8=sys_mmap(IN_MAGIC_1024); let name: *u8=sys_mmap(512); let dest: *u8=sys_mmap(IN_MAGIC_1536) 66 let fbuf: *u8=sys_mmap(IN_CAP); let hexb: *u8=sys_mmap(80); let phex: *u8=sys_mmap(128) 67 var copied: i64=0; var unchanged: i64=0; var skipped: i64=0 68 var ls: i64=0 69 70 while ls < rn { 71 let le: i64 = slk_line_end(reg, rn, ls) 72 if le > ls { if reg[ls] != (35 as u8) { 73 if in_field(reg, ls, le, 0, src, IN_MAGIC_1024) > 0 { 74 in_field(reg, ls, le, 1, name, 512) 75 let n: i64 = in_read(src, fbuf, IN_CAP) 76 if n < 0 { in_w(" skip(absent) " as *u8); in_w(src); in_w("\n" as *u8); skipped=skipped+1 } 77 else { 78 in_hex(fbuf, n, hexb) 79 let had: i64 = in_prior_hash(rprefix, name, phex) 80 var same: i64 = 0 81 if had == 1 { var i: i64=0; same=1; while i<64 { if phex[i]!=hexb[i] { same=0 } i=i+1 } } 82 if same == 1 { unchanged=unchanged+1; in_w(" unchanged " as *u8); in_w(name); in_w("\n" as *u8) } 83 else { in_join(dest, adir, name); in_write(dest, fbuf, n); copied=copied+1; in_w(" COPIED " as *u8); in_w(name); in_w(" bytes=" as *u8); in_wn(n); in_w("\n" as *u8) } 84 ss_add(w, 1, name, hexb, 64) // sovereign: record current state (name -> sha256hex) 85 } 86 } 87 } } 88 ls = le + 1 89 } 90 ss_commit(rprefix, w, ss_segid) 91 in_w(" ---- copied=" as *u8); in_wn(copied); in_w(" unchanged=" as *u8); in_wn(unchanged); in_w(" skipped=" as *u8); in_wn(skipped); in_w("\n" as *u8) 92 in_w("=== INCREMENTAL OK (only changed bytes re-copied; receipt refreshed) ===\n" as *u8) 93 sys_exit(0); return 0 94}