storage: version querylog.db and migrate it in place, never reset a healthy file
querylog.db carries a schema version; migrations run at startup as one transaction after a vacuumed 0600 backup, and every failure refuses startup (exit 2, no systemd restart loop) instead of starting empty. corruption is the only automatic recreate left. the cut gate now requires a fixture-proven migration or an explicit versioned break with restore instructions, and locks shipped migration files and fixtures byte-for-byte.
This commit is contained in:
+25
-1
@@ -13,7 +13,7 @@ const validate = @import("validate.zig");
|
||||
|
||||
/// `ValidateError` enters as a whole set rather than variant by variant, so a
|
||||
/// variant added to the validator cannot silently fall through to exit 1. The
|
||||
/// five extras are the configuration faults raised outside the validator: the
|
||||
/// first five extras are the configuration faults raised outside the validator: the
|
||||
/// ZON reader (`ParseZon`), the file size limit (`ConfigTooLarge`), the managed
|
||||
/// file the operator named and this process cannot open
|
||||
/// (`ManagedConfigUnreadable`, milestone-20 ruling 2), the composition root's
|
||||
@@ -26,6 +26,16 @@ const validate = @import("validate.zig");
|
||||
/// missing file anywhere else stays a runtime failure. `config/loader.zig` owns
|
||||
/// the conversion and the closed set of open errors that qualify.
|
||||
///
|
||||
/// The four querylog schema refusals are here for the exit code, not because a
|
||||
/// `.zon` file is wrong: `SchemaTooNew` and `SchemaUnsupported` are a deliberate
|
||||
/// refusal to touch a `querylog.db` this binary does not understand, and
|
||||
/// `MigrationFailed` and `MigrationBackupFailed` are a deliberate refusal to run
|
||||
/// on a database whose migration or pre-migration backup did not complete. All
|
||||
/// four need an operator, and none of them will resolve on a retry — exit 1 puts
|
||||
/// them under systemd's `Restart=on-failure` and restart-loops a server that is
|
||||
/// refusing on purpose. The unit's `RestartPreventExitStatus=2 64` is what exit
|
||||
/// 2 buys them.
|
||||
///
|
||||
/// Not here on purpose: `error.DestructiveImport`, which reports what an import
|
||||
/// would do to the database rather than the content of a file, and is the one
|
||||
/// config-shaped exit 2 `cli` decides for itself.
|
||||
@@ -35,6 +45,10 @@ const ConfigFault = validate.ValidateError || error{
|
||||
ManagedConfigUnreadable,
|
||||
NoUsableUpstreams,
|
||||
BadCertificate,
|
||||
SchemaTooNew,
|
||||
SchemaUnsupported,
|
||||
MigrationFailed,
|
||||
MigrationBackupFailed,
|
||||
};
|
||||
|
||||
const faults: []const anyerror = blk: {
|
||||
@@ -119,6 +133,16 @@ test "the seed-file errors that used to exit 1 from run are configuration faults
|
||||
try testing.expect(isConfigFault(error.NoUpstreams));
|
||||
}
|
||||
|
||||
test "the querylog schema refusals exit 2 so systemd does not restart-loop them" {
|
||||
try testing.expect(isConfigFault(error.SchemaTooNew));
|
||||
try testing.expect(isConfigFault(error.SchemaUnsupported));
|
||||
try testing.expect(isConfigFault(error.MigrationFailed));
|
||||
try testing.expect(isConfigFault(error.MigrationBackupFailed));
|
||||
// The refusals are a closed set. A neighbouring schema error is a corrupt
|
||||
// database, not a refusal, and stays a runtime failure.
|
||||
try testing.expect(!isConfigFault(error.SchemaCorrupt));
|
||||
}
|
||||
|
||||
test "a runtime failure is not a configuration fault" {
|
||||
try testing.expect(!isConfigFault(error.OutOfMemory));
|
||||
try testing.expect(!isConfigFault(error.AccessDenied));
|
||||
|
||||
Reference in New Issue
Block a user