Skip to content

Commit 6245ac6

Browse files
Reclaim freed SQLite filesystem space
When data is removed from a SQLite database, pages are marked as free instead of being release back to the OS / filesystem. Consequently, when an app uses a lot of IndexedDB space at some point in time, even if the database contents are deleted afterwards, the database file size will remain with the max size so far. This can cause filesystem space to get exhausted in constrained environments where small volume sizes are used for storage.It can also cause issues with the database operations when full volume capacity was reached (e.g. multiple domains, local storage usage) despite not using the full "real" quota and WAL is being used. These changes attempt to mitigate this issue by running the incremental auto vacuum whenever some amount of free space is available to be released. This is currently done on database open. While not ideal, as there is no guarantee that the database will be opened again to free that space, there is also no guarantee that the database close method ( SQLiteIDBBackingStore::close() ) will be invoked in all cases. The cleanup can also not be run in sqlite hooks, as it would not be safe due potential conflict with ongoing transactions. The changes also contain a fix for the incremental vacuum operation itself, as it was not being correctly performed and was returning an error when it would actually succeed.
1 parent 5e2a97e commit 6245ac6

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ IDBError SQLiteIDBBackingStore::getOrEstablishDatabaseInfo(IDBDatabaseInfo& info
988988
return IDBError { ExceptionCode::UnknownError, "Unable to open database file on disk"_s };
989989

990990
m_sqliteDB->disableThreadingChecks();
991+
m_sqliteDB->turnOnIncrementalAutoVacuum();
991992
m_sqliteDB->enableAutomaticWALTruncation();
992993

993994
m_sqliteDB->setCollationFunction("IDBKEY"_s, [](int aLength, const void* a, int bLength, const void* b) {
@@ -1036,6 +1037,10 @@ IDBError SQLiteIDBBackingStore::getOrEstablishDatabaseInfo(IDBDatabaseInfo& info
10361037

10371038
m_databaseInfo = WTFMove(databaseInfo);
10381039
info = *m_databaseInfo;
1040+
1041+
// Check if we are be able to free up some space on the file system
1042+
incrementalVacuumIfNeeded();
1043+
10391044
return IDBError { };
10401045
}
10411046

@@ -2843,6 +2848,22 @@ void SQLiteIDBBackingStore::handleLowMemoryWarning()
28432848
m_sqliteDB->releaseMemory();
28442849
}
28452850

2851+
void SQLiteIDBBackingStore::incrementalVacuumIfNeeded()
2852+
{
2853+
ASSERT(m_sqliteDB);
2854+
ASSERT(m_sqliteDB->isOpen());
2855+
2856+
int64_t freeSpaceSize = m_sqliteDB->freeSpaceSize();
2857+
int64_t totalSize = m_sqliteDB->totalSize();
2858+
2859+
if (totalSize <= 10 * freeSpaceSize) {
2860+
int result = m_sqliteDB->runIncrementalVacuumCommand();
2861+
if (result != SQLITE_DONE)
2862+
LOG_ERROR("Failed to perform incremental vacuum on database for path '%s'", m_sqliteDB->utf8().data());
2863+
}
2864+
}
2865+
2866+
28462867
#undef TABLE_SCHEMA_PREFIX
28472868
#undef V3_RECORDS_TABLE_SCHEMA_SUFFIX
28482869
#undef V3_INDEX_RECORDS_TABLE_SCHEMA_SUFFIX

Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ class SQLiteIDBBackingStore final : public IDBBackingStore {
202202
SQLiteStatementAutoResetScope cachedStatement(SQL, ASCIILiteral);
203203
SQLiteStatementAutoResetScope cachedStatementForGetAllObjectStoreRecords(const IDBGetAllRecordsData&);
204204

205+
void incrementalVacuumIfNeeded();
206+
205207
std::unique_ptr<SQLiteStatement> m_cachedStatements[static_cast<int>(SQL::Invalid)];
206208

207209
IDBDatabaseIdentifier m_identifier;

Source/WebCore/platform/sql/SQLiteDatabase.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,17 @@ int SQLiteDatabase::runIncrementalVacuumCommand()
540540
Locker locker { m_authorizerLock };
541541
enableAuthorizer(false);
542542

543-
if (!executeCommand("PRAGMA incremental_vacuum"_s))
543+
auto statement = prepareStatement("PRAGMA incremental_vacuum"_s);
544+
if (!statement)
545+
return statement.error();
546+
547+
auto ret = statement->step();
548+
while (ret == SQLITE_ROW) {
549+
ret = statement->step();
550+
}
551+
if (ret != SQLITE_DONE) {
544552
LOG(SQLDatabase, "Unable to run incremental vacuum - %s", lastErrorMsg());
553+
}
545554

546555
enableAuthorizer(true);
547556
return lastError();

0 commit comments

Comments
 (0)