mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
sql: enable auto_vacuum=INCREMENTAL
Previously default of `auto_vacuum=NONE` was used. `PRAGMA auto_vacuum=INCERMENTAL` allows running `PRAGMA incremental_vacuum`. Unlike `VACUUM`, `PRAGMA incremental_vacuum` frees unused pages without rebuilding the whole database, like the `VACUUM` does, so it does not require additional disk space to build a vacuumed copy of the database. This may even free enough space on the disk to run `VACUUM` afterwards. New setting will only be enabled for new databases or if the `VACUUM` command runs successfully. Currently `VACUUM` is only executed on backup export, but may fail nevertheless if there is not enough space on the disk. Also try to run `PRAGMA incremental_vacuum` during housekeeping. It may not be the best strategy, but likely does not make any difference under normal usage when the database only grows and there are no free pages. Free pages are created only if enough data is deleted to free at least one database page of 4096 bytes, for example when automatic deletion of messages is deleted for the first time. In the future if more data is placed into the database, like avatars and other blobs, it may be necessary to revise this strategy, for example to keep some free pages instead of removing all of them each time by querying `PRAGMA freelist_pages` and running `PRAGMA incremental_vacuum(N)`.
This commit is contained in:
35
src/sql.rs
35
src/sql.rs
@@ -123,6 +123,15 @@ impl Sql {
|
||||
if !readonly {
|
||||
{
|
||||
let conn = self.get_conn().await?;
|
||||
|
||||
// Try to enable auto_vacuum. This will only be
|
||||
// applied if the database is new or after successful
|
||||
// VACUUM, which usually happens before backup export.
|
||||
// When auto_vacuum is INCREMENTAL, it is possible to
|
||||
// use PRAGMA incremental_vacuum to return unused
|
||||
// database pages to the filesystem.
|
||||
conn.pragma_update(None, "auto_vacuum", &"INCREMENTAL".to_string())?;
|
||||
|
||||
// journal_mode is persisted, it is sufficient to change it only for one handle.
|
||||
conn.pragma_update(None, "journal_mode", &"WAL".to_string())?;
|
||||
|
||||
@@ -604,6 +613,16 @@ pub async fn housekeeping(context: &Context) -> Result<()> {
|
||||
|
||||
context.schedule_quota_update().await?;
|
||||
|
||||
// Try to clear the freelist to free some space on the disk. This
|
||||
// only works if auto_vacuum is enabled.
|
||||
if let Err(err) = context
|
||||
.sql
|
||||
.execute("PRAGMA incremental_vacuum", paramsv![])
|
||||
.await
|
||||
{
|
||||
warn!(context, "Failed to run incremental vacuum: {}", err);
|
||||
}
|
||||
|
||||
if let Err(e) = context
|
||||
.set_config(Config::LastHousekeeping, Some(&time().to_string()))
|
||||
.await
|
||||
@@ -728,6 +747,22 @@ mod tests {
|
||||
assert!(!t.ctx.sql.col_exists("foobar", "foobar").await.unwrap());
|
||||
}
|
||||
|
||||
/// Tests that auto_vacuum is enabled for new databases.
|
||||
#[async_std::test]
|
||||
async fn test_auto_vacuum() -> Result<()> {
|
||||
let t = TestContext::new().await;
|
||||
|
||||
let conn = t.sql.get_conn().await?;
|
||||
let auto_vacuum = conn.pragma_query_value(None, "auto_vacuum", |row| {
|
||||
let auto_vacuum: i32 = row.get(0)?;
|
||||
Ok(auto_vacuum)
|
||||
})?;
|
||||
|
||||
// auto_vacuum=2 is the same as auto_vacuum=INCREMENTAL
|
||||
assert_eq!(auto_vacuum, 2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_housekeeping_db_closed() {
|
||||
let t = TestContext::new().await;
|
||||
|
||||
Reference in New Issue
Block a user