overview: one endpoint, live projections and a response cache (m36)

This commit is contained in:
2026-08-27 17:48:20 +02:00
parent 7cdb74ec17
commit c8470724ce
40 changed files with 3298 additions and 2242 deletions
+22 -10
View File
@@ -30,6 +30,7 @@
//! `writer_failed`, so the loss is visible rather than silent.
const std = @import("std");
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
const db = @import("db.zig");
@@ -555,13 +556,17 @@ pub const Logger = struct {
/// group it cancels for exactly that reason.
///
/// `monitor` is the §11.6 gate. Null disables gating.
///
/// `gpa` belongs to the `BatchWriter` for that writer's whole life; it
/// allocates the projection deltas of one batch and nothing else.
pub fn runWriter(
self: *Logger,
io: std.Io,
gpa: Allocator,
database: *db.Db,
monitor: ?*disk_monitor.Monitor,
) std.Io.Cancelable!void {
var writer = queries_repo.BatchWriter.init(database) catch |err| {
var writer = queries_repo.BatchWriter.init(gpa, database) catch |err| {
scope.warn("query logger: preparing the batch statements failed: {s}", .{@errorName(err)});
// Without a writer there is no consumer, so leaving the queue open
// would silently swallow every later entry.
@@ -1134,7 +1139,7 @@ test "an entry with every provenance field set survives the queue, toRow, insert
var database = try openLog();
defer database.close();
var writer = try queries_repo.BatchWriter.init(&database);
var writer = try queries_repo.BatchWriter.init(testing.allocator, &database);
defer writer.deinit();
var buf: [4]Entry = undefined;
@@ -1466,6 +1471,7 @@ test "shutdown writes the batch the writer holds and the rest of the queue" {
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, null),
});
@@ -1502,7 +1508,7 @@ test "entries that arrive inside one window reach the database in one batch" {
var database = try openLog();
defer database.close();
var writer = try queries_repo.BatchWriter.init(&database);
var writer = try queries_repo.BatchWriter.init(testing.allocator, &database);
defer writer.deinit();
var buf: [16]Entry = undefined;
@@ -1559,6 +1565,7 @@ test "the writer holds an entry for the length of the flush interval" {
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, null),
});
@@ -1611,6 +1618,7 @@ test "a full batch flushes without waiting for the interval" {
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, null),
});
@@ -1658,6 +1666,7 @@ test "the writer's next cycle uses the interval set since its last one" {
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, null),
});
@@ -1700,7 +1709,7 @@ test "a gated flush holds the batch until the disk recovers" {
var database = try openLog();
defer database.close();
var writer = try queries_repo.BatchWriter.init(&database);
var writer = try queries_repo.BatchWriter.init(testing.allocator, &database);
defer writer.deinit();
var buf: [4]Entry = undefined;
@@ -1754,7 +1763,7 @@ test "a failing batch is dropped whole and the writer stays usable" {
\\BEGIN SELECT RAISE(ABORT, 'refused'); END;
);
var writer = try queries_repo.BatchWriter.init(&database);
var writer = try queries_repo.BatchWriter.init(testing.allocator, &database);
defer writer.deinit();
var buf: [4]Entry = undefined;
@@ -1789,7 +1798,7 @@ test "a writer that cannot prepare closes the queue and counts every entry" {
for (0..3) |i| logger.log(io, sampleEntry(@intCast(i), "early.example"));
try logger.runWriter(io, &database, null);
try logger.runWriter(io, testing.allocator, &database, null);
try testing.expect(logger.writer_failed.load(.acquire));
try testing.expectEqual(@as(u64, 3), logger.queries_dropped.load(.monotonic));
@@ -1842,6 +1851,7 @@ test "the gating episode opens on the gate, turns losing on a drop, and clears o
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, &monitor),
});
@@ -2023,6 +2033,7 @@ test "a canceled writer counts the batch it was holding" {
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, &monitor),
});
@@ -2072,6 +2083,7 @@ test "a disk-gated writer drops what it holds at shutdown instead of hanging" {
var future = try io.concurrent(Logger.runWriter, .{
&logger,
io,
testing.allocator,
&database,
@as(?*disk_monitor.Monitor, &monitor),
});
@@ -2121,7 +2133,7 @@ test "an empty batch touches neither the database nor the counters" {
var database = try openLog();
defer database.close();
var writer = try queries_repo.BatchWriter.init(&database);
var writer = try queries_repo.BatchWriter.init(testing.allocator, &database);
defer writer.deinit();
var buf: [4]Entry = undefined;
@@ -2155,7 +2167,7 @@ test "a dropped batch opens an error episode the next good batch closes" {
try fx.init(io, 1000);
defer fx.deinit();
var writer = try queries_repo.BatchWriter.init(&database);
var writer = try queries_repo.BatchWriter.init(testing.allocator, &database);
defer writer.deinit();
var buf: [4]Entry = undefined;
@@ -2198,7 +2210,7 @@ test "a writer that cannot prepare leaves an episode no recovery path claims" {
var logger: Logger = .init(.{}, &buf);
logger.diagnostics = &fx.store;
try logger.runWriter(io, &database, null);
try logger.runWriter(io, testing.allocator, &database, null);
try testing.expectEqualStrings("writer", try fx.text(
"SELECT subject_key FROM operational_events WHERE resolved_at IS NULL",
@@ -2209,7 +2221,7 @@ test "a writer that cannot prepare leaves an episode no recovery path claims" {
// The writer returned, so nothing can ever close this. A second run finds
// the queue closed and adds no second episode.
try logger.runWriter(io, &database, null);
try logger.runWriter(io, testing.allocator, &database, null);
try testing.expectEqual(
@as(i64, 1),
try fx.count("SELECT count(*) FROM operational_events WHERE resolved_at IS NULL"),