code wiki / _hdl_build / nx_gossip.nx
nx_gossip.nx source
↩ module page · 60 lines · 3075 B
1// nx_gossip.nx -- LIB: EPIDEMIC / ANTI-ENTROPY gossip so the Napster index spreads across the mesh with NO central
2// bottleneck (operator: "lots of peers can share with lots of peers ... spoke to spoke or hub to hub"). Each node
3// holds a local content registry (nx_dist_index rows). A gossip round reconciles two nodes: exchange a compact
4// DIGEST (the set of cids each holds) -> each side selects the rows the other LACKS -> merge (idempotent by cid).
5// After a symmetric round both nodes hold the UNION -> run pairwise across the mesh and knowledge converges
6// epidemically. Composes nx_dist_index (row parsing, di_has_cid). No TLS. license_tier: ORIGINAL
7import "nx_dist_index.nx"
8import "nx_syscalls.nx"
9
10// DIGEST: newline-separated cids present in reg (the compact "I have these" summary sent to a peer).
11func gossip_digest(reg: *u8, rlen: i64, out: *u8) -> i64 {
12 var o: i64=0; var ls: i64=0
13 while ls<rlen {
14 let le: i64 = di_eol(reg, ls, rlen)
15 let t1: i64 = di_tab(reg, ls, le); let cs: i64 = t1+1; let ce: i64 = di_tab(reg, cs, le)
16 var k: i64=cs; while k<ce { out[o]=reg[k]; o=o+1; k=k+1 } out[o]=10 as u8; o=o+1
17 ls = le+1
18 }
19 out[o]=0 as u8; return o
20}
21// does a digest (newline cids) already list this cid?
22func gossip_digest_has(digest: *u8, dlen: i64, cid: *u8) -> i64 {
23 let cl: i64 = di_strlen(cid); var ls: i64=0
24 while ls<dlen {
25 let le: i64 = di_eol(digest, ls, dlen)
26 if le-ls==cl { if di_memeq((digest as i64 + ls) as *u8, cid, cl)==1 { return 1 } }
27 ls = le+1
28 }
29 return 0
30}
31// SELECT: append every row of my_reg whose cid is NOT in the peer's digest (what I can teach the peer). Returns len.
32func gossip_select(my_reg: *u8, mlen: i64, peer_digest: *u8, dlen: i64, out: *u8) -> i64 {
33 var o: i64=0; var ls: i64=0
34 while ls<mlen {
35 let le: i64 = di_eol(my_reg, ls, mlen)
36 let t1: i64 = di_tab(my_reg, ls, le); let cs: i64 = t1+1; let ce: i64 = di_tab(my_reg, cs, le)
37 let tmp: *u8 = sys_mmap(128); var j: i64=0; while cs+j<ce { tmp[j]=my_reg[cs+j]; j=j+1 } tmp[j]=0 as u8
38 if gossip_digest_has(peer_digest, dlen, tmp)==0 {
39 var k: i64=ls; while k<le { out[o]=my_reg[k]; o=o+1; k=k+1 } out[o]=10 as u8; o=o+1
40 }
41 ls = le+1
42 }
43 out[o]=0 as u8; return o
44}
45// MERGE: fold incoming rows into dst (idempotent by cid -- additive-only). Returns new dst length.
46func gossip_merge(dst: *u8, dlen: i64, incoming: *u8, ilen: i64) -> i64 {
47 var out: i64=dlen; var ls: i64=0
48 while ls<ilen {
49 let le: i64 = di_eol(incoming, ls, ilen)
50 if le>ls {
51 let t1: i64 = di_tab(incoming, ls, le); let cs: i64 = t1+1; let ce: i64 = di_tab(incoming, cs, le)
52 let tmp: *u8 = sys_mmap(128); var j: i64=0; while cs+j<ce { tmp[j]=incoming[cs+j]; j=j+1 } tmp[j]=0 as u8
53 if di_has_cid(dst, out, tmp)==0 {
54 var k: i64=ls; while k<le { dst[out]=incoming[k]; out=out+1; k=k+1 } dst[out]=10 as u8; out=out+1
55 }
56 }
57 ls = le+1
58 }
59 return out
60}