diff --git a/lib/backend/sqlite.cc b/lib/backend/sqlite.cc index 7048d79615..76bac94c23 100644 --- a/lib/backend/sqlite.cc +++ b/lib/backend/sqlite.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -185,6 +186,21 @@ static int sqlite_init(rpmdb rdb, const char * dbhome) return rc; } +static int64_t sqlite_free_space_kb(sqlite3 * db) +{ + int64_t result = 0; + sqlite3_stmt *s = NULL; + const char *cmd = "SELECT (freelist_count*page_size) as FreeSizeEstimate" + " FROM pragma_freelist_count, pragma_page_size"; + if (sqlite3_prepare_v2(db, cmd, -1, &s, NULL) == SQLITE_OK) { + while (sqlite3_step(s) == SQLITE_ROW) { + result = sqlite3_column_int64(s, 0); + } + sqlite3_finalize(s); + } + return result / 1024; +} + static int sqlite_fini(rpmdb rdb) { int rc = 0; @@ -194,8 +210,21 @@ static int sqlite_fini(rpmdb rdb) rdb->db_opens--; } else { if (sqlite3_db_readonly(sdb, NULL) == 0) { + sqlexec(sdb, "PRAGMA optimize"); sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE"); + + int max_size = rpmExpandNumeric("%{?_sqlite_vacuum_kb}"); + if (max_size <= 0) + max_size = 20*1024; + int64_t free_space = sqlite_free_space_kb(sdb); + + if (free_space > max_size) { + sqlexec(sdb, "VACUUM"); + rpmlog(RPMLOG_DEBUG, "rpmdb sqlite backend VACUUM maxfree:" + " %ikB, free: %" PRIu64 "kB -> %" PRIu64 "kB\n", + max_size, free_space, sqlite_free_space_kb(sdb)); + } } rdb->db_dbenv = NULL; int xx = sqlite3_close(sdb); diff --git a/tests/rpmdb.at b/tests/rpmdb.at index f210594f44..5c2ed91bc6 100644 --- a/tests/rpmdb.at +++ b/tests/rpmdb.at @@ -683,3 +683,20 @@ runroot rpm -q 'versiontest-1.0~2-1' []) RPMTEST_CLEANUP + +# ------------------------------ +AT_SETUP([rpmdb vacuum]) +AT_KEYWORDS([install rpmdb sqlite]) +RPMDB_INIT +RPMTEST_CHECK([ +runroot rpm -U --noscripts --nodeps --ignorearch --noverify \ + /data/RPMS/hello-1.0-1.i386.rpm +runroot rpm -D "_sqlite_vacuum_kb 1" -vv -U --noscripts --nodeps --ignorearch \ + /data/RPMS/hello-2.0-1.i686.rpm 2>&1 | grep VACUUM +], +[0], +[D: VACUUM: 0 +D: rpmdb sqlite backend VACUUM maxfree: 1kB, free: 8kB -> 0kB +], +[]) +RPMTEST_CLEANUP