code wiki / _hdl_build / nx_ha_replication.nx
nx_ha_replication.nx source
↩ module page · 49 lines · 2867 B
1// nx_ha_replication.nx -- CAP-HA-REPLICATION: append-only log-shipping replication (WAL-style) to kill the DATA
2// SPOF (the single NAS). The primary appends records; rep_ship copies new bytes to a standby/backup so it holds a
3// BYTE-EXACT prefix of the primary. Usable TODAY as backup/DR (single-node), and the sync target when a standby host
4// exists. Append-only = history sacred (never rewrites). Deterministic; rep_in_sync proves byte-identity, rep_lag
5// measures how far behind the replica is. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7const K_MAGIC_1048576: i64 = 1048576
8
9// end position (bytes) of a log; 0 if absent/empty.
10func rep_position(path: *u8) -> i64 {
11 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 }
12 let sz: i64 = sys_lseek(fd, 0, 2); sys_close(fd) // whence 2 = SEEK_END
13 if sz < 0 { return 0 }
14 return sz
15}
16// append a record to the primary log; returns the new end position.
17func rep_append(path: *u8, record: *u8, n: i64) -> i64 {
18 let fd: i64 = sys_openat_append(path, 0x1a4); if fd < 0 { return 0 - 1 }
19 sys_write(fd, record, n); sys_close(fd)
20 return rep_position(path)
21}
22func rep_read_all(path: *u8, out: *u8, cap: i64) -> i64 {
23 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 }
24 var total: i64 = 0; var go: i64 = 1
25 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 } }
26 sys_close(fd); return total
27}
28// ship primary[from_pos .. end] and APPEND it to the standby. Returns bytes shipped.
29func rep_ship(primary: *u8, standby: *u8, from_pos: i64) -> i64 {
30 let fd: i64 = sys_openat_rd(primary); if fd < 0 { return 0 }
31 sys_lseek(fd, from_pos, 0) // SEEK_SET
32 let buf: *u8 = sys_mmap(K_MAGIC_1048576)
33 var total: i64 = 0; var go: i64 = 1
34 while go == 1 { let nr: i64 = sys_read(fd, (buf as i64 + total) as *u8, K_MAGIC_1048576 - total); if nr <= 0 { go = 0 } if nr > 0 { total = total + nr } if total >= K_MAGIC_1048576 { go = 0 } }
35 sys_close(fd)
36 if total > 0 { let sfd: i64 = sys_openat_append(standby, 0x1a4); if sfd >= 0 { sys_write(sfd, buf, total); sys_close(sfd) } }
37 return total
38}
39// replication lag in bytes (primary_end - standby_end); 0 = caught up.
40func rep_lag(primary: *u8, standby: *u8) -> i64 { return rep_position(primary) - rep_position(standby) }
41// 1 iff the standby is a BYTE-EXACT prefix of the primary (a valid replica), else 0.
42func rep_in_sync(primary: *u8, standby: *u8) -> i64 {
43 let pb: *u8 = sys_mmap(K_MAGIC_1048576); let pn: i64 = rep_read_all(primary, pb, K_MAGIC_1048576)
44 let sb: *u8 = sys_mmap(K_MAGIC_1048576); let sn: i64 = rep_read_all(standby, sb, K_MAGIC_1048576)
45 if sn > pn { return 0 }
46 var i: i64 = 0
47 while i < sn { if pb[i] != sb[i] { return 0 } i = i + 1 }
48 return 1
49}