Documentation
¶
Overview ¶
Package dbmaintain implements VACUUM + ANALYZE maintenance for the cloop state database (Task 20107).
It complements pkg/dbverify (Task 20094 — integrity checking) and the statedb migration framework (Task 20101 — schema lifecycle) to round out the database lifecycle management story:
cloop db verify → detect on-disk corruption (PRAGMA integrity_check) cloop migrate → bring schema up to current binary's version cloop db maintain → reclaim freelist + refresh planner stats (this pkg)
Operations performed:
- VACUUM: rewrites the database file with no free space, returning reclaimed pages to the filesystem. Required after large deletes such as `cloop compact` or step-history pruning, otherwise the file keeps its peak size forever.
- ANALYZE: refreshes per-index statistics so the query planner picks good plans as table sizes change. Cheap; we always run it after a successful VACUUM.
- A TRUNCATE checkpoint of the write-ahead log (Task 20392). VACUUM writes the whole database through the log, and SQLite never shrinks the log file on its own, so without it a run that handed back the freelist would leave a log the size of the database behind it.
Auto-mode logic: if the current page_count exceeds AutoGrowthThreshold times the page_count recorded after the last vacuum, run; otherwise skip. First-ever invocation always runs (there is no prior baseline to compare against).
Index ¶
Constants ¶
const AutoGrowthThreshold = 1.20
AutoGrowthThreshold gates --auto runs: vacuum only when the current page_count exceeds threshold × last_vacuum.page_count_after. 1.20 = "must have grown at least 20% since the last vacuum".
Variables ¶
var ErrPeerHubLive = errors.New("dbmaintain: another hub instance is live")
ErrPeerHubLive is returned when a VACUUM is refused because another hub holds the control-plane lease. Callers match on it to print advice rather than a stack of wrapped errors.
Functions ¶
This section is empty.
Types ¶
type Options ¶
type Options struct {
// DryRun reports estimated reclaimable bytes (freelist_count × page_size)
// without performing VACUUM or ANALYZE. Nothing is written to the DB —
// not even a maintenance_log row.
DryRun bool
// Auto enables growth-gated execution. When set and a prior vacuum exists,
// Run is a no-op unless the DB has grown >AutoGrowthThreshold since.
// If no prior vacuum exists, Auto behaves as a normal run (so cron-style
// usage from a fresh project does the right thing on first call).
Auto bool
// SkipAnalyze runs only VACUUM. Useful in tests; not exposed via CLI.
SkipAnalyze bool
// Retention, when non-nil, applies the audit-trail retention window
// before vacuuming (Task 20218). Pruning without a VACUUM leaves the
// freed pages on the freelist, so the database on disk does not shrink;
// doing both in one pass is the only way an operator sees the 2.4 GB come
// back. Nil disables it, which is the default and what every caller that
// has not opted into retention gets.
//
// The prune runs first and its outcome is reported even when the
// subsequent VACUUM fails — the rows really were sealed and removed, and
// a report that hid that would send an operator looking for them.
Retention *RetentionOptions
// AllowConcurrentHub skips the live-peer check before VACUUM. It exists
// for tests and for an operator who knows the lease row is stale in a way
// the probe cannot see; it is not exposed as a plain --force because the
// failure it unblocks is rewriting a database file underneath a running
// hub's open connections.
AllowConcurrentHub bool
}
Options configures Run.
type Report ¶
type Report struct {
DBPath string
DryRun bool
AutoSkipped bool
// Reason carries human-readable rationale for the auto-mode decision
// ("auto: no prior vacuum recorded", "auto: page_count 12345 > 1.20×8000
// last vacuum", "auto: skipped — DB has grown only 5% since last vacuum").
Reason string
Before statedb.SizeStats
After statedb.SizeStats
BytesFreed int64
// Operations lists the actions performed in order, e.g. ["VACUUM",
// "ANALYZE"]. Empty for dry-run or auto-skipped runs.
Operations []string
// Retention is the audit-prune outcome when Options.Retention was set,
// nil otherwise. Populated for dry runs too, where it describes what
// would have been sealed.
Retention *auditretention.Report
// AfterPrune is the size measured between the prune and the VACUUM. It
// exists so an operator can see which of the two did the work: the prune
// moves rows to the freelist, only the VACUUM returns pages to the
// filesystem. Zero when no prune ran.
AfterPrune statedb.SizeStats
// LastEntry is the most recent maintenance_log row prior to this run,
// or nil if no maintenance has been recorded before. Populated for both
// dry-run and real runs so the UI/CLI can surface "last maintained N ago".
LastEntry *statedb.MaintenanceLogEntry
// EstimatedReclaim is the dry-run estimate of bytes that VACUUM could
// reclaim, derived from freelist_count × page_size. Only populated when
// DryRun is true.
EstimatedReclaim int64
// WALBefore and WALAfter are the write-ahead log's size when the run
// began and when it ended (Task 20392). A run that changed nothing — a
// dry run, an --auto skip, a refusal — reports the same size twice.
WALBefore int64
WALAfter int64
// WALCheckpoint is the TRUNCATE checkpoint a real run ends with, nil when
// none ran. Busy means another connection was still using the log; the
// log keeps its size and nothing failed.
WALCheckpoint *statedb.WALCheckpoint
}
Report summarises a maintain run.
type RetentionOptions ¶
type RetentionOptions struct {
// Days is the retention window. Rows older than this are sealed and
// removed. Must be positive; zero means the caller did not want
// retention and should have left Options.Retention nil.
Days int
// ExportDir is where sealed prefixes are written.
ExportDir string
// Actor is recorded on the anchor.
Actor string
}
RetentionOptions is the audit-retention half of a maintain run.