backup

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: AGPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package backup copies the SQLite database safely: a consistent snapshot with VACUUM INTO (copying the file of a live database can corrupt the copy), a rolling set of automatic snapshots while the server runs, and a restore that never overwrites data (ADR 0009, ADR 0020).

Files are named <kind>-<UTC timestamp>.db. Only automatic backups (kind "auto") are ever deleted by this package.

Index

Constants

View Source
const (
	KindAuto   = "auto"   // made by the server, pruned to the newest N
	KindManual = "manual" // made by `exhale backup`, never deleted
)

Kinds of backup. The kind is the first part of the file name.

View Source
const DBName = "exhale.db"

DBName is the database file inside the data directory.

View Source
const (
	DefaultKeep = 14
)

Defaults of the automatic backups.

Variables

View Source
var ErrExists = errors.New("backup: the data directory already has a database")

ErrExists is returned by Restore when the data directory already has a database and force is not set.

View Source
var ErrInUse = errors.New("backup: the database is in use")

ErrInUse is returned by Restore when another process has the database open.

Functions

func Prune

func Prune(dir string, keep int) ([]string, error)

Prune deletes the automatic backups in dir beyond the newest keep and returns the paths it removed. keep <= 0 keeps everything. Files of any other kind (manual, pre-migrate, or anything else in dir) are never touched.

func Restore

func Restore(ctx context.Context, src, dataDir string, force bool, now time.Time) (dst, replaced string, err error)

Restore copies the backup file src into dataDir as the database.

It refuses when dataDir already has a database, unless force is set; and even then it refuses when another process (a running Exhale) has that database open. Nothing is deleted: the database it replaces is renamed next to the new one and its path is returned in replaced.

func Snapshot

func Snapshot(ctx context.Context, db *sql.DB, dir, kind string, now time.Time) (string, error)

Snapshot writes a consistent copy of the database to dir/<kind>-<UTC timestamp of now>.db and returns its path. The server can keep running. The file is complete or absent: it is written under a temporary name and renamed once it has been checked.

func Verify

func Verify(ctx context.Context, path string) error

Verify checks that path is a healthy Exhale database: SQLite reads every page (PRAGMA quick_check) and the schema carries Exhale's migration table. The file is opened read-only and is not modified.

Types

type File

type File struct {
	Path string
	Time time.Time // from the file name, UTC
}

File is an automatic backup found on disk.

func List

func List(dir string) ([]File, error)

List returns the automatic backups in dir, newest first. A directory that does not exist yet has none.

type Service

type Service struct {
	DB   *sql.DB
	Dir  string
	Keep int // automatic backups to keep; 0 keeps all
	Log  *slog.Logger

	Every time.Duration // time between backups; default 24 h
	Delay time.Duration // wait after start before the first check; default 1 min

	// Now and Sleep are the clock; tests replace them.
	Now   func() time.Time
	Sleep func(ctx context.Context, d time.Duration) bool
}

Service makes one automatic backup a day while the server runs and keeps the newest Keep. It is a supervised service (platform.Service).

It decides from the files on disk, not from memory: a backup is due when the newest automatic one is at least Every old. Restarting the server therefore never produces extra backups, and a day missed while the machine was off is made up soon after start.

func (*Service) Serve

func (s *Service) Serve(ctx context.Context) error

Serve runs until ctx is cancelled. A failed backup is logged and tried again within the hour; it never stops the server.

func (*Service) String

func (s *Service) String() string

func (*Service) Tick

func (s *Service) Tick(ctx context.Context) time.Duration

Tick makes a backup if one is due, prunes old ones, and returns how long to wait before the next check.

Jump to

Keyboard shortcuts

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