Documentation
¶
Overview ¶
Package sqlite is Harbor's SQLite-backed `memory.MemoryStore` driver (Phase 25). It is the second leg of the memory persistence triad (in-memory floor, SQLite, Postgres) defined by RFC §6.6 + §9.
The driver is built on `modernc.org/sqlite` — a CGo-free SQLite engine (D-013, AGENTS.md §5). Builds remain `CGO_ENABLED=0`.
Operating model:
- Database opened against `cfg.DSN`. Bare file paths and the special `:memory:` sentinel are supported. URI-form DSNs (`file:foo.db?...`) pass through with `_pragma` + `_txlock` query params layered on top so per-connection PRAGMAs survive `database/sql`'s connection lifecycle.
- WAL journal mode is pinned at open. WAL gives concurrent readers + a single writer with no `SQLITE_BUSY` storms in the read path.
- `busy_timeout=5000` (5 s) absorbs `SQLITE_BUSY` retries transparently.
- `db.SetMaxOpenConns(1)` pins the pool to a single connection. This matches Phase 15's StateStore + Phase 18's ArtifactStore-blob driver — `BEGIN IMMEDIATE` does not honor `busy_timeout` for inter-connection writer contention, so under high concurrency the conformance suite's N=128 stress would otherwise leak `SQLITE_BUSY` to callers.
- The schema is applied via embedded `migrations/*.sql` files (forward-only, AGENTS.md §13). The runner is idempotent.
Memory state lives in its OWN `memory_state` table — the SQLite memory driver does NOT piggyback on the SQLite StateStore driver's `state_records` table. The injected `state.StateStore` dep is accepted to satisfy the shared `memory.Deps` contract but is unused by the persistent drivers; the `events.EventBus` dep IS used (for the fail-closed identity-rejection emit path).
The driver self-registers under `"sqlite"` from its `init()`. The production binary picks it up via blank import in `cmd/harbor/main.go`; tests may call `New` directly to skip the registry.
Concurrency contract (D-025):
- The driver struct holds a `*sql.DB` (an internally-synchronized connection pool, pinned to one connection) and an `atomic.Bool` close flag. Both are safe for N concurrent goroutines without external locking.
- Per-call state lives on the call stack / supplied `ctx`. Nothing mutable on the driver ever crosses run boundaries.
- SQLite's single-writer-per-database invariant is enforced by the engine; `busy_timeout` ensures concurrent writers serialize transparently.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func New ¶
func New(cfg memory.ConfigSnapshot, deps memory.Deps) (memory.MemoryStore, error)
New constructs a SQLite-backed `memory.MemoryStore` against `cfg.DSN`. Production callers go through `memory.Open`; tests may call `New` directly to skip the registry.
Strategy unsupported at Phase 23/25 (anything other than `StrategyNone` or empty-equivalent) returns `ErrStrategyNotImplemented` rather than silently coercing — Phase 24 widens the supported set, and the SQLite driver will inherit that widening automatically through the shared conformance suite.
DSN handling mirrors the SQLite StateStore + ArtifactStore drivers: bare file paths and the special `:memory:` sentinel are supported; the driver appends `_pragma=busy_timeout(5000)` + `_pragma=journal_mode(WAL)` + `_txlock=immediate` query params so every pooled connection sees the same per-connection PRAGMAs.
`deps.Bus` is required (for the fail-closed identity-rejection emit path). `deps.State` is accepted to satisfy `memory.Deps` but is unused — persistent memory state lives in this driver's own `memory_state` table.
Types ¶
This section is empty.