Documentation
¶
Overview ¶
Package sqlite is Harbor's SQLite-backed `artifacts.ArtifactStore` driver (Phase 18). It is the third leg of the artifact persistence triad (in-memory floor, FS, SQLite, Postgres) defined by RFC §6.10 + §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 — write contention in the conformance suite's `Concurrent_PutGet_NoRace` (N=128) and our supplemental `concurrent_test.go` does not surface caller-visible errors.
- `db.SetMaxOpenConns(1)` pins the pool to a single connection. Phase 15's StateStore driver settled this — `BEGIN IMMEDIATE` does not honor `busy_timeout` for inter-connection writer contention, so under high concurrency the conformance suite's N=128 stress can otherwise leak `SQLITE_BUSY` to callers.
- The schema is applied via embedded `migrations/*.sql` files (forward-only, brief 05 §4 + AGENTS.md §13). The runner is idempotent — re-running on an already-migrated DB is a no-op.
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 config.ArtifactsConfig) (artifacts.ArtifactStore, error)
New constructs a SQLite-backed `artifacts.ArtifactStore` against `cfg.DSN`. Production callers go through `artifacts.Open`; tests may call `New` directly to skip the registry.
DSN handling:
- Empty DSN → clear error (no silent default-fallback).
- `:memory:` → translated to a PER-OPEN uniquely named shared-cache memory URI (D-207; see uniqueMemoryDSN) so the pool can hand out multiple connections to the same in-memory database (the bare `:memory:` DSN gives every pool connection its own private DB, which would break Put+Get round-trip across pooled connections) while staying isolated from every other subsystem's `:memory:` store in the same process.
- Any other DSN is treated as a file path or URI form and passed through verbatim with the WAL + busy_timeout PRAGMAs appended as `_pragma` query params.
Errors:
- empty `cfg.DSN`
- DSN that cannot be parsed for `_pragma` augmentation
- `sql.Open` failure (rare; modernc.org/sqlite's Open is lazy)
- migration apply failure
Types ¶
This section is empty.