db-mode config changes apply live in-process
settings and upstream writes now follow a prepare, commit, publish, retire contract: candidates are built and validated before the database transaction, published as infallible pointer swaps, and old generations retire after their readers drain. per-query policy values snapshot once per query; upstream pool, cache, rate limiter, sessions, api limiter, log sink, blocklist scheduler and the query-log queue each gained one named live operation. restart_required shrinks from every scalar key to the bind keys and web.enabled; the admin ui drops its restart notices for everything else. file mode is unchanged.
This commit is contained in:
+37
-16
@@ -34,6 +34,7 @@ const events_mod = @import("../storage/events.zig");
|
||||
const http_util = @import("http_util.zig");
|
||||
const logging = @import("../platform/logging.zig");
|
||||
const pool_mod = @import("../upstream/pool.zig");
|
||||
const upstream_owner = @import("../upstream/owner.zig");
|
||||
const rate_limiter = @import("../server/rate_limiter.zig");
|
||||
const retention_mod = @import("../storage/retention.zig");
|
||||
const safe_url = @import("../safe_url.zig");
|
||||
@@ -187,28 +188,36 @@ pub fn collect(state: *server.WebState, io: std.Io, arena: Allocator) Allocator.
|
||||
if (state.handler) |handler| {
|
||||
sample.dns = dnsCounters(&handler.stats);
|
||||
|
||||
if (handler.cache) |cache| {
|
||||
// The pointer is loaded under the same mutex a query loads it under,
|
||||
// never before it: a live `cache.size` or `dns.rate_limit` change
|
||||
// frees the object it displaced as soon as the swap returns.
|
||||
{
|
||||
handler.cache_mutex.lockUncancelable(io);
|
||||
defer handler.cache_mutex.unlock(io);
|
||||
sample.cache = .{
|
||||
if (handler.cache) |cache| sample.cache = .{
|
||||
.stats = cache.stats,
|
||||
.entries = cache.len(),
|
||||
.memory_bytes = cache.memoryBytes(),
|
||||
};
|
||||
}
|
||||
|
||||
if (handler.limiter) |limiter| {
|
||||
{
|
||||
handler.limiter_mutex.lockUncancelable(io);
|
||||
defer handler.limiter_mutex.unlock(io);
|
||||
sample.limiter = .{ .stats = limiter.stats, .tracked_clients = limiter.table.count() };
|
||||
if (handler.limiter) |limiter| {
|
||||
sample.limiter = .{ .stats = limiter.stats, .tracked_clients = limiter.table.count() };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.logger) |logger| sample.logger = .{
|
||||
.queries_dropped = logger.queries_dropped.load(.monotonic),
|
||||
.rows_written = logger.rows_written.load(.monotonic),
|
||||
.batches_gated = logger.batches_gated.load(.monotonic),
|
||||
};
|
||||
if (state.logger) |controller| {
|
||||
const reading = controller.sample(io);
|
||||
sample.logger = .{
|
||||
.queries_dropped = reading.queries_dropped,
|
||||
.rows_written = reading.rows_written,
|
||||
.batches_gated = reading.batches_gated,
|
||||
};
|
||||
}
|
||||
|
||||
if (state.tracker) |tracker| sample.tracker = .{
|
||||
.stats = tracker.snapshotStats(io),
|
||||
@@ -259,7 +268,11 @@ pub fn collect(state: *server.WebState, io: std.Io, arena: Allocator) Allocator.
|
||||
sample.udp_listener = sumListeners(udp_server.Snapshot, udp_server.UdpServer, state.udp_listeners);
|
||||
sample.tcp_listener = sumListeners(tcp_server.Snapshot, tcp_server.TcpServer, state.tcp_listeners);
|
||||
|
||||
if (state.pool) |pool| sample.upstreams = try upstreams(pool, io, arena);
|
||||
if (state.upstreams) |owner| {
|
||||
const generation = owner.acquire(io);
|
||||
defer owner.release(io, generation);
|
||||
if (generation.pool) |pool| sample.upstreams = try upstreams(pool, io, arena);
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
@@ -700,18 +713,23 @@ fn writeLabelValue(w: *std.Io.Writer, value: []const u8) std.Io.Writer.Error!voi
|
||||
|
||||
const db = @import("../storage/db.zig");
|
||||
const local_tables = @import("../server/local_tables.zig");
|
||||
const logger_controller = @import("../storage/logger_controller.zig");
|
||||
const logger_mod = @import("../storage/logger.zig");
|
||||
const migrations = @import("../storage/migrations.zig");
|
||||
const transport = @import("../upstream/transport.zig");
|
||||
const testing = std.testing;
|
||||
|
||||
/// Backs `testHandler`'s owner. File-scope because the handler is returned by
|
||||
/// value and its `*Owner` has to outlive the return; nothing here exchanges, so
|
||||
/// the generation behind it is never acquired.
|
||||
var unreachable_upstream: upstream_owner.Borrowed = .{};
|
||||
|
||||
/// A handler with no upstream reachable: every test here reads counters and
|
||||
/// never runs a query.
|
||||
fn testHandler() dns_handler.Handler {
|
||||
return .{
|
||||
.upstream = .{ .ptr = undefined, .exchangeFn = undefined },
|
||||
.blocking = .{ .mode = .zero, .ttl = 5 },
|
||||
.forward_read_timeout = .{ .raw = .fromMilliseconds(50), .clock = .awake },
|
||||
.upstream = unreachable_upstream.client(.{ .ptr = undefined, .exchangeFn = undefined }),
|
||||
.policy = .{ .blocking = .{ .mode = .zero, .ttl = 5 }, .forward_read_timeout = .{ .raw = .fromMilliseconds(50), .clock = .awake } },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1600,9 +1618,12 @@ test "collect reads the live counters of the components it is given" {
|
||||
var queue_buf: [4]logger_mod.Entry = undefined;
|
||||
var query_logger: logger_mod.Logger = .init(.{}, &queue_buf);
|
||||
query_logger.rows_written.store(90, .monotonic);
|
||||
var log_owner: logger_controller.Borrowed = .{};
|
||||
|
||||
var tracker: clients.Tracker = .init(30);
|
||||
var retention: retention_mod.Retention = .init(.{});
|
||||
var tracker_days: retention_mod.RetentionDays = .init(30);
|
||||
var tracker: clients.Tracker = .init(&tracker_days);
|
||||
var retention_days: retention_mod.RetentionDays = .init(30);
|
||||
var retention: retention_mod.Retention = .init(&retention_days);
|
||||
var tables: local_tables.LocalTables = .empty;
|
||||
var names: client_names.Resolver = .init(&tables);
|
||||
names.stats.no_zone = 4;
|
||||
@@ -1611,7 +1632,7 @@ test "collect reads the live counters of the components it is given" {
|
||||
var state: server.WebState = .{
|
||||
.gpa = testing.allocator,
|
||||
.handler = &handler,
|
||||
.logger = &query_logger,
|
||||
.logger = log_owner.over(&query_logger),
|
||||
.tracker = &tracker,
|
||||
.client_names = &names,
|
||||
.retention = &retention,
|
||||
|
||||
Reference in New Issue
Block a user