From c3df8d87147fb279c8b865cd1d91fd02de7bac5c Mon Sep 17 00:00:00 2001 From: Bart De Vries Date: Thu, 14 Jul 2022 15:32:58 +0200 Subject: [PATCH] Fix "database is locked" errors caused by concurrent writes --- src/database.cpp | 6 +++++- src/datamanager.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/database.cpp b/src/database.cpp index 6a9ef03c..490a723e 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -171,7 +171,11 @@ bool Database::execute(QSqlQuery &query) bool Database::transaction(const QString &connectionName) { - return QSqlDatabase::database(connectionName).transaction(); + // use IMMEDIATE transaction here to avoid deadlocks with writes happening + // in different threads + QSqlQuery query(QSqlDatabase::database(connectionName)); + query.prepare(QStringLiteral("BEGIN IMMEDIATE TRANSACTION;")); + return execute(query); } bool Database::commit(const QString &connectionName) diff --git a/src/datamanager.cpp b/src/datamanager.cpp index 0ef2d8c6..ce38fe5d 100644 --- a/src/datamanager.cpp +++ b/src/datamanager.cpp @@ -71,6 +71,11 @@ DataManager::DataManager() // Check for "new" entries if (SettingsManager::self()->autoQueue()) { + // start an immediate transaction since this non-blocking read query + // can change into a blocking write query if the entry needs to be + // queued; this can create a deadlock with other concurrent write + // operations + Database::instance().transaction(); query.prepare(QStringLiteral("SELECT id FROM Entries WHERE feed=:feed AND new=:new ORDER BY updated ASC;")); query.bindValue(QStringLiteral(":feed"), feedurl); query.bindValue(QStringLiteral(":new"), true); @@ -85,6 +90,7 @@ DataManager::DataManager() } } } + Database::instance().commit(); } Q_EMIT feedEntriesUpdated(feedurl);