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
+9 -6
View File
@@ -91,7 +91,6 @@ pub const Snapshot = struct {
idle_timeouts: u64,
connection_errors: u64,
bad_requests: u64,
dropped_no_permit: u64,
};
pub const DohServer = struct {
@@ -117,6 +116,7 @@ pub const DohServer = struct {
pub const Owner = DohServer;
pub const ConnPayload = Payload;
pub const serveConn = serveOne;
pub const closing = wakeBudgetWaiters;
pub const read_buffer_len = recv_buffer_len;
pub const write_buffer_len = send_buffer_len;
pub const log = std.log.scoped(.doh_server);
@@ -165,7 +165,6 @@ pub const DohServer = struct {
.idle_timeouts = core.idle_timeouts.load(.monotonic),
.connection_errors = core.connection_errors.load(.monotonic),
.bad_requests = self.stats.bad_requests.load(.monotonic),
.dropped_no_permit = core.dropped_no_permit.load(.monotonic),
};
}
@@ -174,6 +173,10 @@ pub const DohServer = struct {
self.core.serve(io);
}
fn wakeBudgetWaiters(self: *DohServer, io: std.Io) void {
self.budget.wakeWaiters(io);
}
pub fn deinit(self: *DohServer, io: std.Io) void {
self.core.deinit(io);
self.* = undefined;
@@ -389,10 +392,10 @@ pub const DohServer = struct {
request: *http.Server.Request,
query: []const u8,
) error{ WriteFailed, HttpExpectationFailed }!Next {
const work = self.budget.tryAcquire(io) orelse {
listener.bump(&self.core.stats.dropped_no_permit);
return .close;
};
// Bounded like a read: a query still waiting when the idle budget runs
// out closes the connection, with the timeout counted by the budget.
const permit_deadline: std.Io.Clock.Timestamp = .fromNow(io, self.options.idle_timeout);
const work = self.budget.acquire(io, permit_deadline, &self.core.run_state) catch return .close;
defer self.budget.release(io, work);
const outcome = self.handler.handle(