db-mode config changes apply live in-process
Gates / frontend (push) Successful in 1m43s
Gates / test (push) Successful in 2m14s
Gates / test-aarch64 (push) Successful in 8m3s
Gates / package (push) Successful in 5m42s
Gates / container (push) Successful in 54s
CI / gates (push) Successful in 50m24s
Gates / frontend (push) Successful in 1m43s
Gates / test (push) Successful in 2m14s
Gates / test-aarch64 (push) Successful in 8m3s
Gates / package (push) Successful in 5m42s
Gates / container (push) Successful in 54s
CI / gates (push) Successful in 50m24s
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:
@@ -13,24 +13,36 @@
|
||||
const std = @import("std");
|
||||
|
||||
const logger = @import("../storage/logger.zig");
|
||||
const logger_controller = @import("../storage/logger_controller.zig");
|
||||
const sse = @import("../web/sse.zig");
|
||||
|
||||
pub const QuerySink = struct {
|
||||
logger: *logger.Logger,
|
||||
/// The controller, not a `Logger`: `logging.query_log_buffer_max` can
|
||||
/// change while the server runs, and the generation a producer enqueues
|
||||
/// into has to be the one that is live at that moment.
|
||||
controller: *logger_controller.Controller,
|
||||
/// Null when `web.enabled` is false: nothing subscribes, so nothing needs
|
||||
/// a hub, and the DNS path pays one null check.
|
||||
hub: ?*sse.Hub,
|
||||
|
||||
pub fn init(query_logger: *logger.Logger, hub: ?*sse.Hub) QuerySink {
|
||||
return .{ .logger = query_logger, .hub = hub };
|
||||
pub fn init(controller: *logger_controller.Controller, hub: ?*sse.Hub) QuerySink {
|
||||
return .{ .controller = controller, .hub = hub };
|
||||
}
|
||||
|
||||
/// Transforms once, publishes, then enqueues. Never blocks the query path
|
||||
/// and never fails: both consumers drop rather than wait.
|
||||
///
|
||||
/// The borrow spans both halves. A resize that lands between them would
|
||||
/// otherwise leave this entry going into a queue retirement has already
|
||||
/// closed, and that is exactly the drop window the controller exists to
|
||||
/// make impossible.
|
||||
pub fn log(self: *QuerySink, io: std.Io, entry: logger.Entry) void {
|
||||
const transformed = self.logger.transformed(entry);
|
||||
const generation = self.controller.acquire(io);
|
||||
defer self.controller.release(io, generation);
|
||||
|
||||
const transformed = generation.logger.transformed(entry);
|
||||
if (self.hub) |hub| hub.publish(io, transformed);
|
||||
self.logger.logTransformed(io, transformed);
|
||||
generation.logger.logTransformed(io, transformed);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,7 +72,8 @@ test "the sink publishes and logs the same entry" {
|
||||
|
||||
var queue_buf: [4]logger.Entry = undefined;
|
||||
var query_logger: logger.Logger = .init(.{}, &queue_buf);
|
||||
var sink: QuerySink = .init(&query_logger, hub);
|
||||
var owner: logger_controller.Borrowed = .{};
|
||||
var sink: QuerySink = .init(owner.over(&query_logger), hub);
|
||||
|
||||
const id = hub.subscribe(io).?;
|
||||
defer hub.unsubscribe(io, id);
|
||||
@@ -87,7 +100,8 @@ test "fanout does not depend on the entry reaching the queue" {
|
||||
|
||||
var queue_buf: [4]logger.Entry = undefined;
|
||||
var query_logger: logger.Logger = .init(.{}, &queue_buf);
|
||||
var sink: QuerySink = .init(&query_logger, hub);
|
||||
var owner: logger_controller.Borrowed = .{};
|
||||
var sink: QuerySink = .init(owner.over(&query_logger), hub);
|
||||
|
||||
const id = hub.subscribe(io).?;
|
||||
defer hub.unsubscribe(io, id);
|
||||
@@ -115,7 +129,8 @@ test "the privacy transforms run once, before both consumers" {
|
||||
.{ .hide_domains = true, .hide_client_ips = true },
|
||||
&queue_buf,
|
||||
);
|
||||
var sink: QuerySink = .init(&query_logger, hub);
|
||||
var owner: logger_controller.Borrowed = .{};
|
||||
var sink: QuerySink = .init(owner.over(&query_logger), hub);
|
||||
|
||||
const id = hub.subscribe(io).?;
|
||||
defer hub.unsubscribe(io, id);
|
||||
@@ -138,7 +153,8 @@ test "a sink without a hub still logs" {
|
||||
|
||||
var queue_buf: [4]logger.Entry = undefined;
|
||||
var query_logger: logger.Logger = .init(.{}, &queue_buf);
|
||||
var sink: QuerySink = .init(&query_logger, null);
|
||||
var owner: logger_controller.Borrowed = .{};
|
||||
var sink: QuerySink = .init(owner.over(&query_logger), null);
|
||||
|
||||
sink.log(io, sampleEntry(5, "nohub.example"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user