code wiki / (root) / nx_ts_slot_lib.nx

nx_ts_slot_lib.nx

buildroot/runtime/nx_ts_slot_lib.nx

9468 B215 linesdepth 5pulls 8 transitivereach 2 importersview sourcekind librarytopic ts
docsdependenciesstructsconstsfunctions

about

nx_ts_slot_lib.nx -- TS3: THE SLOT-FLIP DECISION CORE (importable, no main). /compare/trafficsafety rung TS3. Two backend SLOTS on two ports behind one small front door that owns the upstream choice and is independent of both. Accept rule taken VERBATIM from trafficsafety.plan: "a flip changes which slot answers with zero failed requests across the flip, a slot that fails its warm-up probe is NEVER flipped to, and the front door's own uptime is unbroken across the whole exercise." IT DOES NOT TOUCH sites.elf OR nx_proxy_route, AND THAT IS A DESIGN DECISION, NOT AN OMISSION. The live front door is what all 69 route rows cross; editing it to gain a deploy-safety property is the one change whose blast radius is every request in the estate. So this ships as a STANDALONE router that fronts one non-critical backend. The pattern is identical and provable; adopting it for the estate's real front door is an operator decision that should be taken against this evidence, not smuggled in beneath it. THE FRONT DOOR IS THE ONLY THING THAT MUST NEVER RESTART, so it is also the only thing that must be replaceable without a gap -- and that is precisely why TS3 depends on TS1. This router takes its own listener from ts_handoff_nodrop, so the component whose restart would be an outage is itself hot-replaceable. A front door that cannot be replaced hitlessly is refused rather than deployed; this one closes that dependency in its own first line of work rather than deferring it. THE UPSTREAM CHOICE IS DATA, NOT A RECOMPILED BRANCH. The active slot lives in a conf file read through rm_conf -- the estate's line-anchored reader, not a second one -- and it is re-read PER CONNECTION. So a flip takes effect on the very next request with no signal, no restart and no reload race, and the router holds no cached routing state that could disagree with the file. A FLIP IS GUARDED BY A WARM-UP PROBE AND THE GUARD FAILS TOWARD DOING NOTHING. ts_slot_flip probes the CANDIDATE before it writes, and on a cold candidate it leaves the active slot exactly where it was and returns a NAMED refusal. A heuristic that gates a destructive action must be wrong in the direction of doing nothing, and flipping traffic onto a dead slot is the destructive action here. SCOPE OF THE PROBE, STATED RATHER THAN IMPLIED: it establishes that the candidate ACCEPTS A CONNECTION AND ANSWERS BYTES. That is liveness, not health. The estate already owns the deeper instrument -- nx_http_probe_lib's hp_run, with thirteen distinct exit codes so a compound health assertion cannot fail without naming WHICH half failed -- and the honest upgrade path is to compose that, never to re-implement a second probe here. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 4 imports · 2 importers

nx_syscalls.nx nx_http_server.nx nx_ts_drain_lib.nx nx_resmon_lib.nx nx_ts_slot_lib.nx nx_ts_slot_router.nx nx_ts_slot_router_gate.nx

imports: nx_syscalls.nxnx_http_server.nxnx_ts_drain_lib.nxnx_resmon_lib.nx

imported by: nx_ts_slot_router.nxnx_ts_slot_router_gate.nx

structs

none

consts

43const TSR_SA_BYTES: i64 = 16
46const TSR_SA_PORT_OFF: i64 = 2
47const TSR_SA_ADDR_OFF: i64 = 4
48const TSR_ADDR_BYTES: i64 = 4
49const TSR_BYTE_RADIX: i64 = 256
50const TSR_LOOPBACK_A: i64 = 127
51const TSR_LOOPBACK_D: i64 = 1
52const TSR_BACKLOG: i64 = 16
53const TSR_OUT_BYTES: i64 = 64
54const TSR_NUM_SCRATCH: i64 = 24
55const TSR_ASCII_0: i64 = 48
56const TSR_ASCII_9: i64 = 57
57const TSR_B10: i64 = 10
58const TSR_BUF_CAP: i64 = 65536
59const TSR_PROBE_BYTE: i64 = 80
63const TSR_SLOT_A: i64 = 0
64const TSR_SLOT_B: i64 = 1
65const TSR_SLOT_N: i64 = 2
69const TSR_FLIP_OK: i64 = 0
70const TSR_FLIP_NOOP: i64 = 1
71const TSR_FLIP_COLD: i64 = 2
72const TSR_FLIP_BAD_SLOT: i64 = 3
73const TSR_FLIP_WRITE_ERR: i64 = 4
75const TSR_KEY_ACTIVE: *u8 = "active_slot" as *u8
76const TSR_ARGC_MIN: i64 = 5
77const TSR_A_FRONT: i64 = 1
78const TSR_A_SLOTA: i64 = 2
79const TSR_A_SLOTB: i64 = 3
80const TSR_A_STATE: i64 = 4
81const TSR_A_SOCK: i64 = 5

functions

83func tsr_atoi(s: *u8) -> i64
called by 1: main
93func tsr_itoa(v: i64, out: *u8) -> i64
105func tsr_sa(sa: *u8, port: i64) -> i64
called by 2: tsr_dialmain
117func tsr_dial(port: i64) -> i64
130func ts_slot_active(state_path: *u8) -> i64
145func ts_slot_probe(port: i64) -> i64
160func ts_slot_flip(state_path: *u8, ports: *i64, want: i64) -> i64
187func tsr_forward(cfd: i64, upstream_port: i64, buf: *u8) -> i64
205func tsr_puts(s: *u8) -> i64
called by 1: main calls 1: sys_write
210func tsr_putn(v: i64) -> i64
called by 1: main calls 3: sys_mmaptsr_itoasys_write