Skip to main content

Crate meerkat_sqlite

Crate meerkat_sqlite 

Source
Expand description

Shared SQLite mechanics for Meerkat stores.

This crate is the single home for the connection policy, schema-evolution, and maintenance-fence machinery that was previously copy-pasted across the store crates (six independently authored PRAGMA setups with divergent busy timeouts, CREATE TABLE IF NOT EXISTS everywhere, and no version ledger). See docs/plans/storage-unification-plan.md (Phase 3) in the workspace root for the design rationale.

What lives here:

  • profile: DDL-free connection opening under named policy profiles (ConnectionProfile::Primary, ConnectionProfile::ReadOnly, ConnectionProfile::Maintenance). Opening a connection never runs schema DDL; stores apply their ledger domain after opening. The optional OpenOptions::schema_preflight refuses a future file before any mutating pragma, and WriteContact types each profile’s honest no-write guarantee (WAL reads may need sidecar files).
  • ledger: the per-file migration ledger (meerkat_schema(domain, version)) with the pinned concurrent-open transaction protocol and the typed SqliteStoreError::SchemaFromTheFuture refusal. Ledger state that is malformed (wrong shape, duplicate rows, non-positive versions) is refused typed, never healed.
  • json_column: the TEXT-or-BLOB tolerant JSON column codec.
  • fence: the per-operation maintenance-fence guards. Store operations take a shared guard; offline migration takes the exclusive side and waits for in-flight operations to drain. Stores built on this crate hold no bespoke opener, which is what makes them fence-aware for free.
  • error: the crate error type plus the storage-level error classification (transient / corrupt) that store crates layer their staleness semantics on top of. Adoption contract: store crates route every raw rusqlite error through classify_sqlite_error instead of re-matching SQLite error codes locally.

§Retryability

Error classification alone does not authorize a retry: a transient failure can land after a write committed but before success became observable, and blind retry duplicates non-idempotent effects. Automatic retry is only sound for idempotent or CAS-keyed operations; an indeterminate non-idempotent write requires outcome reconciliation (read back, then decide) before any retry. Bounded waiting for lock contention is the connection busy handler’s job, not a caller retry loop.

Re-exports§

pub use error::SqliteErrorClass;
pub use error::SqliteStoreError;
pub use error::classify_sqlite_error;
pub use error::is_busy_or_locked;
pub use fence::ExclusiveFence;
pub use fence::OperationGuard;
pub use fence::fence_lock_path;
pub use json_column::JsonColumnBytes;
pub use ledger::LedgerReport;
pub use ledger::Migration;
pub use ledger::SchemaDomain;
pub use ledger::apply_domain_migrations;
pub use ledger::domain_version;
pub use ledger::refuse_future_schema;
pub use profile::ConnectionProfile;
pub use profile::OpenOptions;
pub use profile::SHARED_BUSY_TIMEOUT;
pub use profile::WriteContact;
pub use profile::begin_immediate;
pub use profile::open;
pub use profile::open_with;

Modules§

error
Crate error type and storage-level error classification.
fence
Per-operation maintenance-fence guards.
json_column
Read boundary for UTF-8 JSON payload columns.
ledger
Per-file schema migration ledger.
profile
DDL-free connection opening under named policy profiles.