milestone 16: behavioral fixes for silent failures, locks, counters and the query log
CI / test (push) Failing after 11s
CI / cross (push) Failing after 25s
CI / docker (push) Failing after 24s
CI / test-aarch64 (push) Failing after 2m22s
CI / frontend (push) Successful in 43s

This commit is contained in:
2026-08-07 01:54:40 +02:00
parent 5802148887
commit 25455e5ae2
31 changed files with 2054 additions and 297 deletions
+22
View File
@@ -140,6 +140,13 @@ pub const Handler = struct {
uncloak_blocked: std.atomic.Value(u64) = .init(0),
local_answers: std.atomic.Value(u64) = .init(0),
forward_zone_answers: std.atomic.Value(u64) = .init(0),
/// The three forward-client counters, folded in after every exchange.
/// `ForwardClient` is built per query and dropped with the query, so
/// these are where its numbers survive. Its `queries` counter is not
/// mirrored: `forward_zone_answers` already counts the exchanges.
forward_udp_truncated: std.atomic.Value(u64) = .init(0),
forward_foreign_datagrams: std.atomic.Value(u64) = .init(0),
forward_failures: std.atomic.Value(u64) = .init(0),
cache_hits: std.atomic.Value(u64) = .init(0),
paused_queries: std.atomic.Value(u64) = .init(0),
/// Queries answered before the first snapshot existed, so no group and
@@ -396,6 +403,11 @@ const Context = struct {
&ctx.scratch.frame,
ctx.handler.forward_read_timeout,
);
// The client lives on this query's stack, so its counters have to move
// into the handler's before it goes out of scope — on the failure path
// too, which is the one `forward_failures` exists for.
defer foldForwardStats(&ctx.handler.stats, client.stats);
const answer = client.exchange(ctx.io, ctx.query, ctx.response_buf) catch |err| {
return switch (transport.group(err)) {
.cancellation => .drop,
@@ -879,6 +891,15 @@ fn bump(counter: *std.atomic.Value(u64)) void {
_ = counter.fetchAdd(1, .monotonic);
}
/// Moves one forward-zone exchange's counters into the handler's. `stats` is a
/// plain per-instance struct and stays that way (milestone-16 ruling 14); this
/// is the one place it becomes a process-wide number.
fn foldForwardStats(into: *Handler.Stats, from: forward_client.ForwardClient.Stats) void {
_ = into.forward_udp_truncated.fetchAdd(from.udp_truncated, .monotonic);
_ = into.forward_foreign_datagrams.fetchAdd(from.foreign_datagrams, .monotonic);
_ = into.forward_failures.fetchAdd(from.failures, .monotonic);
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
@@ -1758,6 +1779,7 @@ fn fixtureManager(m: *manager.Manager, snapshot: *matcher.Snapshot) void {
.total_budget = forward_timeout,
.lock = .init,
.writer_lock = .init,
.refresh_lock = .init,
.current = snapshot,
.generation = 1,
.statuses = &.{},