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);