VACUUM snapshot metadata through the sqlite driver, not a CLI (closes #120)
check / check (pull_request) Successful in 2m40s

snapshot create vacuumed the exported metadata database by shelling out
to a sqlite3 binary, so a backup failed at the very end on any host
without that CLI. vacuumDatabase now opens the database with the
modernc.org/sqlite driver and runs VACUUM through it, outside any
transaction; internal/snapshot no longer imports os/exec. The database
opens in WAL mode, so the close after VACUUM checkpoints the rewrite
into the main file that is compressed and uploaded. A new test deletes
marked rows, vacuums, and asserts the file shrank and no longer holds
the deleted bytes. script/bootstrap and the Dockerfile test image stop
installing the CLI.

Disclosure: the Dockerfile test-image change was not exercised by local
make check, which builds only the lint image.

Model: opus-4-8
This commit is contained in:
2026-09-21 13:11:22 +00:00
parent d2a0510cb4
commit 68f4366989
7 changed files with 129 additions and 15 deletions
+21 -5
View File
@@ -44,7 +44,6 @@ import (
"errors"
"fmt"
"io"
"os/exec"
"path/filepath"
"strings"
"time"
@@ -669,14 +668,31 @@ func (sm *SnapshotManager) collectCleanupStats(
// vacuumDatabase runs VACUUM on the database to remove deleted data and compact
// This is critical for security - ensures no stale/deleted data pages are uploaded
//
// VACUUM runs through the modernc.org/sqlite driver, on a freshly opened
// connection with no transaction in flight (VACUUM cannot run inside one).
// The database opens in WAL mode, so VACUUM's rewrite lands in the WAL; the
// checkpoint on Close flushes it into the main file, which is the file we
// then compress and upload.
func (sm *SnapshotManager) vacuumDatabase(ctx context.Context, dbPath string) error {
log.Debug("Running VACUUM on database", "path", dbPath)
//nolint:gosec // G204: fixed argv; dbPath is our own temp file path
cmd := exec.CommandContext(ctx, "sqlite3", dbPath, "VACUUM;")
output, err := cmd.CombinedOutput()
db, err := database.New(ctx, dbPath)
if err != nil {
return fmt.Errorf("running VACUUM: %w (output: %s)", err, string(output))
return fmt.Errorf("opening database for VACUUM: %w", err)
}
defer func() {
cerr := db.Close()
if cerr != nil {
log.Debug("Failed to close database after VACUUM",
"path", dbPath, "error", cerr)
}
}()
_, err = db.ExecWithLog(ctx, "VACUUM")
if err != nil {
return fmt.Errorf("running VACUUM: %w", err)
}
return nil