store

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package store persists the engine's authoritative state in one SQLite file: projects, plans and their task graphs, jobs with their leases and fencing tokens, sessions, runners, agents, outcomes, messages, hashed tokens and the append-only event log. No state lives only in a session, so everything needed to continue after a crash or a lost engine is here; the plan file in the repo is a mirror of this store, never the other way around.

Index

Constants

This section is empty.

Variables

View Source
var ErrTooNew = errors.New("store schema is newer than this binary")

ErrTooNew reports a store whose user_version is newer than the newest migration this binary carries. An older binary must refuse such a store outright rather than guess its way through a newer schema.

Functions

func IsBusy

func IsBusy(err error) bool

IsBusy reports whether err is SQLite refusing the database to the caller: SQLITE_BUSY or SQLITE_LOCKED, the "database is locked" family, as another connection held the write lock past the busy timeout. A bounded retry can ride that out; anything else cannot. The driver's error text is matched unwrapped, since every wrapping on the way up (fmt.Errorf's %w included) keeps the text.

func Restore

func Restore(ctx context.Context, snapshot, dst string) error

Restore copies the snapshot file into a new store file at dst, through the backup API in reverse. dst must not exist: the caller moves a lost store aside first. The result is the snapshot as it was, not yet opened or migrated; Open does that.

func RetryBusy

func RetryBusy(ctx context.Context, fn func() error) error

RetryBusy runs fn and re-runs it while it fails busy (IsBusy), with the backoff doubling from busyFirstBackoff and bounded by busyAttempts. A fn that fails any other way, or succeeds, ends the retry with that result; a context that runs out ends it with the last busy error. fn must be safe to re-run — a failed transaction rolled back, so its effects are gone — and it should begin on a context that does not cancel under it, or the retry inherits the very failure it is meant to ride out.

Types

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is a handle to the engine's SQLite database: one file holding all authoritative state (design §11), opened with the pragmas the engine relies on and migrated to the newest schema this binary knows.

func Open

func Open(ctx context.Context, path string) (*Store, error)

Open opens the SQLite database at path, creating the file when missing, and migrates the schema as far as this binary knows.

The path ":memory:" opens a private in-memory database on a single pooled connection — a second connection would see a fresh, empty database — which is what tests want. The journal-mode pragma is a harmless no-op there: an in-memory database cannot use write-ahead logging.

A path containing '?' or '#' is refused: dsn appends the pragmas as query parameters, so either character would be read as a delimiter and the pragmas would silently not apply.

func (*Store) Backup

func (s *Store) Backup(ctx context.Context, dst string) error

Backup writes a consistent copy of the store to the file at dst through SQLite's backup API — never a file copy of a live database, which could catch a write half done. dst must not exist; it is a complete database once Backup returns.

func (*Store) Close

func (s *Store) Close() error

Close closes the store's database handle.

func (*Store) Path

func (s *Store) Path() string

Path is the store file's path as opened — ":memory:" for a private in-memory store — so callers can place the engine's other files (artifact blobs, §9) beside the one database.

func (*Store) Update

func (s *Store) Update(ctx context.Context, fn func(tx *sql.Tx) error) error

Update runs fn in one transaction on the store, committing when fn returns nil and rolling back when it does not. The connection string already makes every transaction begin immediately (see dsn), so fn holds the database's write lock from its first statement: two callers cannot interleave inside fn, whatever pool connection each rides on and however many processes share the file.

func (*Store) View

func (s *Store) View(ctx context.Context, fn func(tx *sql.Tx) error) error

View runs fn in one read-only transaction on the store: the begin is deferred, not immediate, so under write-ahead logging a reader holds no write lock — a long writer (a lease poll, an upload) cannot lock it out and it cannot hold a writer up. What fn sees is still one consistent snapshot of the store. fn must only read: a write inside a deferred transaction would try to upgrade its lock mid-transaction and can meet busy where an Update would have waited up front.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL