Skip to main content

Module ledger

Module ledger 

Source
Expand description

Per-file schema migration ledger.

Every SQLite file carries a meerkat_schema(domain TEXT PRIMARY KEY, version INTEGER NOT NULL) table with exactly one row per schema domain. Each store registers its ordered, idempotent migrations; the existing DDL of every store is migration 0001 of its domain.

§The pinned transaction protocol

Idempotent migration functions alone do not make concurrent opens safe, so the runner pins a minimal protocol (consumed unchanged by downstream adopters):

  1. exactly one ledger row per domain;
  2. BEGIN IMMEDIATE;
  3. re-read the version inside that transaction;
  4. reject a future version before any mutation (SqliteStoreError::SchemaFromTheFuture);
  5. execute the pending migrations and the ledger update atomically in the same transaction — custody is verified with a runner-owned savepoint around each body, so a body that COMMITs or ROLLBACKs underneath the runner is refused (SqliteStoreError::MigrationBrokeTransaction) even when it re-BEGINs a fresh transaction afterwards.

A table merely named meerkat_schema is not trusted: before any read the pinned column shape is validated against main’s catalog, versions must be positive, and at most one row may exist per domain (SqliteStoreError::LedgerMalformed otherwise). All ledger SQL is main.-qualified, so a TEMP table shadowing the name can neither satisfy nor bypass the ledger.

Concurrent opens race safely: the loser’s in-transaction re-read sees the winner’s committed version and applies nothing.

§Migrations on files older than the ledger

Files written before the ledger existed carry tables of some historical vintage and no meerkat_schema row (version 0). Migration 0001 is the store’s CREATE ... IF NOT EXISTS DDL, which converges missing tables without touching existing ones; later migrations guard internally (for example PRAGMA table_info probes before ALTER TABLE) exactly like the historical upgrade functions they were lifted from. Running the full sequence therefore converges a file of any vintage and stamps it — this is also what the offline ledger-baseline migration case does, under the maintenance fence.

Foreign domain rows (other stores co-tenanting the same file) are never read or written; the ledger keys strictly by domain name.

Structs§

LedgerReport
Outcome of apply_domain_migrations.
Migration
One schema migration step for a domain.
SchemaDomain
A store’s schema domain: its ledger name plus the ordered migration list.

Functions§

apply_domain_migrations
Bring domain up to date in the file behind conn, per the pinned protocol. Returns the version movement.
domain_version
Read a domain’s ledger version without applying anything.
refuse_future_schema
Refuse when the file’s ledger already records a version of domain newer than this binary supports, without mutating anything.