nx_lock_reap.nx source
↩ module page · 61 lines · 3239 B
1// nx_lock_reap.nx -- CLI of the sovereign stale-lock reaper (R-ORCH-2a). Reaps ONE abandoned lock
2// so a crashed workstream never blocks its siblings -- the janitorial pillar of the orchestration
3// north-star, as an organ (never the ps|grep|rm shell sin).
4// usage: nx_lock_reap <lockpath> <max_age_s> <owner_needle> [dry]
5// owner_needle = a substring of the owner process's /proc cmdline (e.g. "nx_mgmt_api", "git");
6// pass "-" for no owner-check (age-only, for cross-boundary locks where /proc can't see the owner).
7// Reaps iff exists AND owner not alive AND age > max_age_s. dry -> report only. Always exits 0
8// (a reaper must never fail its cron); appends a line to knowledge/status/lock_reap.log.
9// license_tier: ORIGINAL expect_exit: 0
10import "nx_syscalls.nx"
11import "nx_lock_reap_core.nx"
12const K_MAGIC_1024: i64 = 1024
13
14func r_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
15func r_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 }
16
17func main(argc: i64, argv: *i64) -> i64 {
18 if argc < 4 { r_puts("usage: nx_lock_reap <lockpath> <max_age_s> <owner_needle|-> [dry]\n" as *u8); return 0 }
19 let lockpath: *u8 = argv[1] as *u8
20 let ep: *i64 = sys_mmap(16) as *i64
21 let maxage: i64 = ccz_num_at(argv[2] as *u8, ccz_slen(argv[2] as *u8), 0, ep)
22 let needle: *u8 = argv[3] as *u8
23 var dry: i64 = 0
24 if argc >= 5 { if r_streq(argv[4] as *u8, "dry" as *u8) == 1 { dry = 1 } }
25
26 let now: i64 = sys_now_realtime_sec()
27 let exists: i64 = lr_exists(lockpath)
28 var owner: i64 = 0
29 if r_streq(needle, "-" as *u8) == 0 { if exists == 1 { owner = lr_owner_alive(needle) } }
30 let age: i64 = lr_age_s(lockpath, now)
31 let decide: i64 = lr_should_reap(exists, owner, age, maxage)
32
33 let line: *u8 = sys_mmap(K_MAGIC_1024)
34 var o: i64 = 0
35 o = ccz_cat_str(line, o, "LOCKREAP path=" as *u8)
36 o = ccz_cat_str(line, o, lockpath)
37 o = ccz_cat_str(line, o, " exists=" as *u8)
38 o = ccz_cat_num(line, o, exists)
39 o = ccz_cat_str(line, o, " owner_alive=" as *u8)
40 o = ccz_cat_num(line, o, owner)
41 o = ccz_cat_str(line, o, " age_s=" as *u8)
42 o = ccz_cat_num(line, o, age)
43 o = ccz_cat_str(line, o, " max=" as *u8)
44 o = ccz_cat_num(line, o, maxage)
45 o = ccz_cat_str(line, o, " -> " as *u8)
46 if decide == 1 {
47 if dry == 1 { o = ccz_cat_str(line, o, "WOULD-REAP (dry)" as *u8) } else {
48 let rc: i64 = lr_unlink(lockpath)
49 if rc == 0 { o = ccz_cat_str(line, o, "REAPED (stale, unowned)" as *u8) } else { o = ccz_cat_str(line, o, "REAP-FAILED" as *u8) }
50 }
51 } else {
52 if exists == 0 { o = ccz_cat_str(line, o, "NO-LOCK" as *u8) } else {
53 if owner == 1 { o = ccz_cat_str(line, o, "HELD (owner alive -- fail-safe, no reap)" as *u8) } else { o = ccz_cat_str(line, o, "TOO-FRESH (fail-safe, no reap)" as *u8) }
54 }
55 }
56 o = ccz_cat_str(line, o, "\n" as *u8)
57 sys_write(1, line, o)
58 let lfd: i64 = sys_openat_append("knowledge/status/lock_reap.log" as *u8, 420)
59 if lfd >= 0 { sys_write(lfd, line, o); sys_close(lfd) }
60 return 0
61}