Switch to incremental vacuum for non-blocking space reclamation

- Use PRAGMA incremental_vacuum instead of full VACUUM
- Frees ~1000 pages (~4MB) per run without blocking writes
- Run every 10 minutes instead of 6 hours since it's lightweight
- Set auto_vacuum=INCREMENTAL pragma for new databases
- Remove blocking VACUUM on startup
This commit is contained in:
2025-12-29 16:00:33 +07:00
parent da6d605e4d
commit d7e6f46320
2 changed files with 23 additions and 19 deletions

View File

@@ -113,6 +113,7 @@ func (d *Database) Initialize() error {
"PRAGMA wal_checkpoint(TRUNCATE)", // Checkpoint and truncate WAL now
"PRAGMA busy_timeout=5000", // 5 second busy timeout
"PRAGMA analysis_limit=0", // Disable automatic ANALYZE
"PRAGMA auto_vacuum=INCREMENTAL", // Enable incremental vacuum (new DBs only)
}
for _, pragma := range pragmas {
@@ -126,12 +127,6 @@ func (d *Database) Initialize() error {
return err
}
// Run VACUUM on startup to optimize database
d.logger.Info("Running VACUUM to optimize database (this may take a moment)")
if err := d.exec("VACUUM"); err != nil {
d.logger.Warn("Failed to VACUUM database", "error", err)
}
return nil
}
@@ -1951,11 +1946,15 @@ func (d *Database) getIPv6Info(ctx context.Context, ip string, parsedIP net.IP)
return info, nil
}
// Vacuum runs the SQLite VACUUM command to reclaim unused space and defragment the database.
// Vacuum runs incremental vacuum to reclaim unused pages without blocking writes.
// It frees up to the specified number of pages per call (0 = all freeable pages).
func (d *Database) Vacuum(ctx context.Context) error {
_, err := d.db.ExecContext(ctx, "VACUUM")
// Free up to 1000 pages per call (~4MB with default 4KB page size)
// This keeps each vacuum operation quick and non-blocking
const pagesToFree = 1000
_, err := d.db.ExecContext(ctx, fmt.Sprintf("PRAGMA incremental_vacuum(%d)", pagesToFree))
if err != nil {
return fmt.Errorf("failed to vacuum database: %w", err)
return fmt.Errorf("failed to run incremental vacuum: %w", err)
}
return nil