feat(storage): auto-VACUUM trigger after page-releasing DDL (SQLR-10)#91
Merged
Conversation
Compacts the file in place after DROP TABLE / DROP INDEX / ALTER TABLE DROP COLUMN whenever the freelist crosses a configurable fraction of page_count (default 0.25, SQLite parity). The threshold is tunable per-connection via Connection::set_auto_vacuum_threshold; pass None to opt out and keep the manual-VACUUM-only behavior. Skipped mid-txn, on in-memory / read-only DBs, and below a 16-page floor so tiny files don't churn. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Compact the database file automatically after
DROP TABLE/DROP INDEX/ALTER TABLE DROP COLUMNwhen the freelist exceeds a configurable fraction ofpage_count. Builds on SQLR-6 (which added the manualVACUUM;and the persisted freelist) — the freed pages already landed on the freelist, but the file stayed at its high-water mark until someone ranVACUUM;by hand. This trigger closes that gap.Connections ship withSome(0.25).Connection::set_auto_vacuum_threshold(Option<f32>). PassNoneto opt out (preserves the prior manual-VACUUM-only behavior). Out-of-range / NaN / Inf values return a typed error rather than silently saturating.process_command_with_renderimmediately after the existing auto-save (the freelist isn't accurate until the bottom-up rebuild populates it during save). Callspager::vacuum_databasedirectly — bypassesexecutor::execute_vacuum, whose user-facing status string and in-transaction rejection are wrong for a silent maintenance hook.Connectionruntime state — not persisted in the file header. A SQL-levelPRAGMA auto_vacuumis tracked separately as a follow-up (SQLR-13) so SDK consumers (Python/Node/Go/WASM/MCP/FFI) can tune the knob without per-binding glue.Compatibility note
Behavior changes for existing files: a
DROP TABLE/DROP INDEX/ALTER TABLE DROP COLUMNthat pushes the freelist past 25% ofpage_countwill now pay an extra full-file rewrite that didn't happen before. That's the intended fix for the bloat problem, but embedders who need the prior shape can callset_auto_vacuum_threshold(None)once after open.Files
src/sql/db/database.rsauto_vacuum_threshold: Option<f32>field +DEFAULT_AUTO_VACUUM_THRESHOLD = 0.25+ validating settersrc/sql/pager/freelist.rsshould_auto_vacuum(pager, threshold)heuristic +MIN_PAGES_FOR_AUTO_VACUUM = 16floorsrc/sql/mod.rspager::vacuum_databasewhen triggeredsrc/connection.rsConnection::auto_vacuum_threshold()/set_auto_vacuum_threshold()src/sql/pager/mod.rs,src/connection.rs(test mods)docs/pager.md,docs/supported-sql.mdTests
Eight new pager-level regression tests in
src/sql/pager/mod.rscover:DROP TABLEset_auto_vacuum_threshold(None)disables the triggerDROP INDEXandALTER TABLE DROP COLUMNpaths both triggerDROPdoes not triggerMIN_PAGES_FOR_AUTO_VACUUM) suppresses on tiny DBsPlus one
Connection-level test confirming the default and setter pass-through.Test plan
cargo build --workspace --exclude sqlrite-desktop --exclude sqlrite-python --exclude sqlrite-nodejs --all-targets— cleancargo test --workspace --exclude sqlrite-desktop --exclude sqlrite-python --exclude sqlrite-nodejs— 380 engine + 19 MCP + 12 + 8 + others, 0 failuresdrop_then_vacuum_shrinks_fileregression intact)cargo fmt --all -- --check— cleancargo clippy --workspace ... --all-targets— only pre-existing warnings (no new ones in SQLR-10 code)cargo doc --workspace ... --no-deps— cleanFollow-ups (filed separately)
PRAGMA auto_vacuumknob, so SDK consumers can tune the threshold via SQL.CREATE INDEXpanic (unknown paged-entry kind tag 0x4) on tables wide enough for the secondary index to need interior-node pages. Surfaced while writing the DROP INDEX test for this PR; unrelated to SQLR-10 itself.🤖 Generated with Claude Code