code wiki / _hdl_build / nx_metrics_ring.nx
nx_metrics_ring.nx source
↩ module page · 130 lines · 5295 B
1// nx_metrics_ring.nx -- SOVEREIGN metrics time-series store (the TSDB the maturity census named as the
2// supervisor domain's #1 observability gap: /status is point-in-time, there was NO history). A fixed-size
3// binary RING (no SQL, no float, no TSV -- append-only, WRAPS at capacity so disk is BOUNDED by construction,
4// respecting the disk-budget law). Each sample = 32 bytes: ts_sec | name_hash(FNV-1a) | verdict | fails.
5// Library half (no main): the sampler daemon appends; the CLI + nx_heal query. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7const MR_MAGIC_2166136261: i64 = 2166136261
8const MR_MAGIC_16777619: i64 = 16777619
9const MR_MAGIC_4294967295: i64 = 4294967295
10
11const MR_MAGIC: i64 = 5928237 // ring header sentinel
12const MR_HDR: i64 = 64 // header bytes
13const MR_REC: i64 = 32 // record bytes: ts(8) namehash(8) verdict(8) fails(8)
14const MR_CAP: i64 = 262144 // ~8.4MB file, ~29h of 37-daemon 15s samples (bounded)
15const MR_V_SERVING: i64 = 1
16const MR_V_REFUSED: i64 = 2
17const MR_V_HUNG: i64 = 3
18const MR_V_BADRESP: i64 = 4
19
20func mr_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
21// FNV-1a 32-bit (masked, positive) -- daemon identity without variable-length strings in the record.
22func mr_hash(s: *u8) -> i64 {
23 var h: i64 = MR_MAGIC_2166136261
24 var i: i64 = 0
25 while s[i] != (0 as u8) {
26 h = h ^ (s[i] as i64)
27 h = (h * MR_MAGIC_16777619) & MR_MAGIC_4294967295
28 i = i + 1
29 }
30 return h
31}
32// read n bytes at offset off into buf; returns bytes read (or -1)
33func mr_pread(fd: i64, off: i64, buf: *u8, n: i64) -> i64 {
34 if sys_lseek(fd, off, 0) < 0 { return 0 - 1 }
35 var t: i64 = 0
36 while t < n { let r: i64 = sys_read(fd, (buf as i64 + t) as *u8, n - t); if r <= 0 { return t } t = t + r }
37 return t
38}
39func mr_pwrite(fd: i64, off: i64, buf: *u8, n: i64) -> i64 {
40 if sys_lseek(fd, off, 0) < 0 { return 0 - 1 }
41 var t: i64 = 0
42 while t < n { let w: i64 = sys_write(fd, (buf as i64 + t) as *u8, n - t); if w <= 0 { return 0 - 1 } t = t + w }
43 return 0
44}
45func mr_geti(buf: *u8, o: i64) -> i64 {
46 var v: i64 = 0
47 var i: i64 = 0
48 while i < 8 { v = v | ((buf[o + i] as i64) << (i * 8)); i = i + 1 }
49 return v
50}
51func mr_puti(buf: *u8, o: i64, v: i64) -> i64 {
52 var i: i64 = 0
53 while i < 8 { buf[o + i] = ((v >> (i * 8)) & 255) as u8; i = i + 1 }
54 return 0
55}
56
57// append one sample. Self-contained + FAIL-SAFE (any error -> return negative, never crashes a caller).
58// open O_RDWR|CREAT, init header if new/foreign, write record at write_index, advance (wrap), rewrite header.
59func mr_append(path: *u8, ts: i64, namehash: i64, verdict: i64, fails: i64) -> i64 {
60 let fd: i64 = sys_openat_rdwr(path, 420)
61 if fd < 0 { return 0 - 1 }
62 let hdr: *u8 = sys_mmap(MR_HDR)
63 let got: i64 = mr_pread(fd, 0, hdr, MR_HDR)
64 var widx: i64 = 0
65 var wrapped: i64 = 0
66 if got == MR_HDR { if mr_geti(hdr, 0) == MR_MAGIC {
67 widx = mr_geti(hdr, 24)
68 wrapped = mr_geti(hdr, 32)
69 } }
70 // (re)write a valid header baseline
71 var hi: i64 = 0; while hi < MR_HDR { hdr[hi] = 0 as u8; hi = hi + 1 }
72 mr_puti(hdr, 0, MR_MAGIC)
73 mr_puti(hdr, 8, MR_REC)
74 mr_puti(hdr, 16, MR_CAP)
75 // record
76 let rec: *u8 = sys_mmap(MR_REC)
77 mr_puti(rec, 0, ts)
78 mr_puti(rec, 8, namehash)
79 mr_puti(rec, 16, verdict)
80 mr_puti(rec, 24, fails)
81 let recoff: i64 = MR_HDR + widx * MR_REC
82 if mr_pwrite(fd, recoff, rec, MR_REC) != 0 { sys_close(fd); sys_munmap(hdr, MR_HDR); sys_munmap(rec, MR_REC); return 0 - 2 }
83 var nidx: i64 = widx + 1
84 if nidx >= MR_CAP { nidx = 0; wrapped = 1 }
85 mr_puti(hdr, 24, nidx)
86 mr_puti(hdr, 32, wrapped)
87 mr_pwrite(fd, 0, hdr, MR_HDR)
88 sys_close(fd)
89 // free per-call scratch -- mr_append runs in the sampler's hot loop (the bounded-VSZ discipline)
90 sys_munmap(hdr, MR_HDR)
91 sys_munmap(rec, MR_REC)
92 return 0
93}
94
95// count of valid records currently stored
96func mr_count(fd: i64, hdr: *u8) -> i64 {
97 if mr_pread(fd, 0, hdr, MR_HDR) != MR_HDR { return 0 }
98 if mr_geti(hdr, 0) != MR_MAGIC { return 0 }
99 if mr_geti(hdr, 32) == 1 { return MR_CAP }
100 return mr_geti(hdr, 24)
101}
102
103// uptime permille for namehash over [now-window, now]. -1 if no samples. verdict==SERVING = "up".
104func mr_uptime(path: *u8, namehash: i64, window_sec: i64, now: i64) -> i64 {
105 let fd: i64 = sys_openat_rd(path)
106 if fd < 0 { return 0 - 1 }
107 let hdr: *u8 = sys_mmap(MR_HDR)
108 let cnt: i64 = mr_count(fd, hdr)
109 if cnt <= 0 { sys_close(fd); return 0 - 1 }
110 let rec: *u8 = sys_mmap(MR_REC)
111 var total: i64 = 0
112 var up: i64 = 0
113 let lo: i64 = now - window_sec
114 var i: i64 = 0
115 while i < cnt {
116 if mr_pread(fd, MR_HDR + i * MR_REC, rec, MR_REC) == MR_REC {
117 if mr_geti(rec, 8) == namehash {
118 let ts: i64 = mr_geti(rec, 0)
119 if ts >= lo { if ts <= now {
120 total = total + 1
121 if mr_geti(rec, 16) == MR_V_SERVING { up = up + 1 }
122 } }
123 }
124 }
125 i = i + 1
126 }
127 sys_close(fd)
128 if total <= 0 { return 0 - 1 }
129 return up * 1000 / total
130}