server: a query that finds every permit taken waits for one instead of failing, the budget is 64, permit and upstream turns wait on a futex with one thread each, the thread pool has no task limit, and transparent huge pages are off for the process

This commit is contained in:
2026-10-22 20:26:25 +02:00
parent 63cc5f8dc3
commit 91ed5ae774
26 changed files with 1114 additions and 305 deletions
+10 -7
View File
@@ -60,7 +60,6 @@ pub const StatsSnapshot = struct {
tls_handshake_failures: u64,
idle_timeouts: u64,
connection_errors: u64,
dropped_no_permit: u64,
};
pub const DotServer = struct {
@@ -83,6 +82,7 @@ pub const DotServer = struct {
pub const Owner = DotServer;
pub const ConnPayload = Payload;
pub const serveConn = serveOne;
pub const closing = wakeBudgetWaiters;
pub const read_buffer_len = stream_buffer_len;
pub const write_buffer_len = stream_buffer_len;
pub const log = std.log.scoped(.dot_server);
@@ -121,6 +121,10 @@ pub const DotServer = struct {
self.core.serve(io);
}
fn wakeBudgetWaiters(self: *DotServer, io: std.Io) void {
self.budget.wakeWaiters(io);
}
pub fn deinit(self: *DotServer, io: std.Io) void {
self.core.deinit(io);
self.* = undefined;
@@ -138,7 +142,6 @@ pub const DotServer = struct {
.tls_handshake_failures = self.stats.tls_handshake_failures.load(.monotonic),
.idle_timeouts = core.idle_timeouts.load(.monotonic),
.connection_errors = core.connection_errors.load(.monotonic),
.dropped_no_permit = core.dropped_no_permit.load(.monotonic),
};
}
@@ -219,11 +222,11 @@ pub const DotServer = struct {
},
}
// There is no framing for "no answer", so the connection ends.
const work = self.budget.tryAcquire(io) orelse {
listener.bump(&stats.dropped_no_permit);
return;
};
// Bounded like a read: a query still waiting when the idle budget
// runs out ends the connection, with the timeout counted by the
// budget. There is no framing for "no answer".
const permit_deadline: std.Io.Clock.Timestamp = .fromNow(io, budget);
const work = self.budget.acquire(io, permit_deadline, &self.core.run_state) catch return;
defer self.budget.release(io, work);
const outcome = self.handler.handle(