a73x

32540415

refactor: one occupied-slot count for the three live gauges

a73x   2026-08-29 10:01

Commit message
refactor: one occupied-slot count for the three live gauges

liveClients, AgentRelay.live and SessionTable.live were the same four-line
count over a fixed array of optionals; countLive is the one owner, so a
fourth table gets a gauge rather than a fourth loop. clientsInSession was
clientsIn(si, null) with a wider int and now says so.

Pinned by statsText's clients=/sessions=/agent_chans= fields, which the
bench harness and e2e split on; the four docs shrank with their bodies to
hold server.zig, server_agent.zig and server_sessions.zig at budget 0.

src/server/server.zig
Old New
@@ -131,6 +131,16 @@ pub fn boundUdpPort(l: *quic_server.Listener) u16 {
131 return std.net.Address.initPosix(@ptrCast(@alignCast(&actual))).getPort(); 131 return std.net.Address.initPosix(@ptrCast(@alignCast(&actual))).getPort();
132 } 132 }
133 133
134 /// The one occupied-slot count behind every `live` gauge: a loop per
135 /// table is a place per table to forget one.
136 pub fn countLive(slots: anytype) usize {
137 var n: usize = 0;
138 for (slots) |slot| {
139 if (slot != null) n += 1;
140 }
141 return n;
142 }
143
134 pub var shutdown_flag = std.atomic.Value(bool).init(false); 144 pub var shutdown_flag = std.atomic.Value(bool).init(false);
135 145
136 fn onShutdownSignal(_: c_int) callconv(.c) void { 146 fn onShutdownSignal(_: c_int) callconv(.c) void {
@@ -3567,24 +3577,14 @@ pub const Server = struct {
3567 std.debug.assert(@sizeOf(SessionsBuf) == proto.sessions_text_max); 3577 std.debug.assert(@sizeOf(SessionsBuf) == proto.sessions_text_max);
3568 } 3578 }
3569 3579
3570 /// A gauge, not a counter: a QUIC handshake that never attaches holds a 3580 /// A gauge: an unattached QUIC handshake holds a slot, unobservably.
3571 /// slot until its idle timeout, unobservably.
3572 fn liveClients(self: *const Server) usize { 3581 fn liveClients(self: *const Server) usize {
3573 var n: usize = 0; 3582 return countLive(&self.clients);
3574 for (self.clients) |slot| {
3575 if (slot != null) n += 1;
3576 }
3577 return n;
3578 } 3583 }
3579 3584
3580 /// The number the per-session stats segment reports: who is watching THIS 3585 /// Who is watching THIS shell, not how many sockets are open at all.
3581 /// shell, not how many sockets are open at all.
3582 fn clientsInSession(self: *const Server, si: usize) usize { 3586 fn clientsInSession(self: *const Server, si: usize) usize {
3583 var n: usize = 0; 3587 return self.clientsIn(si, null);
3584 for (0..max_clients) |i| {
3585 if (self.inSession(i, si)) n += 1;
3586 }
3587 return n;
3588 } 3588 }
3589 3589
3590 /// Text, but machine-parsed: the bench harness and the e2e tests split on 3590 /// Text, but machine-parsed: the bench harness and the e2e tests split on
src/server/server_agent.zig
Old New
@@ -19,7 +19,8 @@
19 const std = @import("std"); 19 const std = @import("std");
20 const proto = @import("protocol"); 20 const proto = @import("protocol");
21 const xdg = @import("xdg"); 21 const xdg = @import("xdg");
22 const Server = @import("server.zig").Server; 22 const srv_mod = @import("server.zig");
23 const Server = srv_mod.Server;
23 24
24 /// A bound, listening `SSH_AUTH_SOCK` for one session: the descriptor the 25 /// A bound, listening `SSH_AUTH_SOCK` for one session: the descriptor the
25 /// daemon accepts on and the name the shell was handed. The two travel 26 /// daemon accepts on and the name the shell was handed. The two travel
@@ -183,14 +184,9 @@ pub const AgentRelay = struct {
183 return .{ .fd = listener.stream.handle, .path = path }; 184 return .{ .fd = listener.stream.handle, .path = path };
184 } 185 }
185 186
186 /// Refusal counts only mean something next to it: "refused 40, holding 8" 187 /// Refusal counts only mean something next to it: 0 is nobody offering.
187 /// is a full table; "holding 0" is nobody offering.
188 pub fn live(self: *const AgentRelay) usize { 188 pub fn live(self: *const AgentRelay) usize {
189 var n: usize = 0; 189 return srv_mod.countLive(&self.chans);
190 for (self.chans) |slot| {
191 if (slot != null) n += 1;
192 }
193 return n;
194 } 190 }
195 191
196 fn freeSlot(self: *const AgentRelay) ?usize { 192 fn freeSlot(self: *const AgentRelay) ?usize {
src/server/server_sessions.zig
Old New
@@ -285,13 +285,8 @@ pub const SessionTable = struct {
285 return w.buffered(); 285 return w.buffered();
286 } 286 }
287 287
288 /// The count `sessions=` on the stats main line, and the number of per- 288 /// `sessions=` on the stats main line, and how many tail segments follow.
289 /// session tail segments to expect after it.
290 pub fn live(self: *const SessionTable) usize { 289 pub fn live(self: *const SessionTable) usize {
291 var n: usize = 0; 290 return srv_mod.countLive(&self.table);
292 for (self.table) |slot| {
293 if (slot != null) n += 1;
294 }
295 return n;
296 } 291 }
297 }; 292 };