Sqlite: Add busy handler

A busy handler is much more flexible than a timeout. In most cases we can
remove the busy exception handling code.

Change-Id: I59666ccfbd380a341412e3d25e6716b07097bf3c
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-03-16 11:48:12 +01:00
parent a6cfbf82ac
commit baab71c073
4 changed files with 48 additions and 25 deletions

View File

@@ -61,7 +61,7 @@ Database::Database()
} }
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode) Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
: Database(std::move(databaseFilePath), 1000ms, journalMode) : Database{std::move(databaseFilePath), 0ms, journalMode}
{} {}
Database::Database(Utils::PathString &&databaseFilePath, Database::Database(Utils::PathString &&databaseFilePath,
@@ -89,7 +89,10 @@ void Database::open()
{ {
m_databaseBackend.open(m_databaseFilePath, m_openMode); m_databaseBackend.open(m_databaseFilePath, m_openMode);
m_databaseBackend.setJournalMode(m_journalMode); m_databaseBackend.setJournalMode(m_journalMode);
if (m_busyTimeout > 0ms)
m_databaseBackend.setBusyTimeout(m_busyTimeout); m_databaseBackend.setBusyTimeout(m_busyTimeout);
else
m_databaseBackend.registerBusyHandler();
registerTransactionStatements(); registerTransactionStatements();
initializeTables(); initializeTables();
m_isOpen = true; m_isOpen = true;

View File

@@ -55,12 +55,12 @@ public:
using MutexType = std::mutex; using MutexType = std::mutex;
using ReadStatement = Sqlite::ReadStatement; using ReadStatement = Sqlite::ReadStatement;
using WriteStatement = Sqlite::WriteStatement; using WriteStatement = Sqlite::WriteStatement;
using BusyHandler = DatabaseBackend::BusyHandler;
Database(); Database();
Database(Utils::PathString &&databaseFilePath, JournalMode journalMode = JournalMode::Wal);
Database(Utils::PathString &&databaseFilePath, Database(Utils::PathString &&databaseFilePath,
JournalMode journalMode); std::chrono::milliseconds busyTimeout,
Database(Utils::PathString &&databaseFilePath,
std::chrono::milliseconds busyTimeout = 1000ms,
JournalMode journalMode = JournalMode::Wal); JournalMode journalMode = JournalMode::Wal);
~Database(); ~Database();
@@ -132,6 +132,11 @@ public:
void setAttachedTables(const Utils::SmallStringVector &tables) override; void setAttachedTables(const Utils::SmallStringVector &tables) override;
void applyAndUpdateSessions() override; void applyAndUpdateSessions() override;
void setBusyHandler(BusyHandler busyHandler)
{
m_databaseBackend.setBusyHandler(std::move(busyHandler));
}
SessionChangeSets changeSets() const; SessionChangeSets changeSets() const;
private: private:

View File

@@ -37,15 +37,24 @@
#include "sqlite3.h" #include "sqlite3.h"
#include <chrono>
#include <thread>
extern "C" { extern "C" {
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
} }
namespace Sqlite { namespace Sqlite {
using namespace std::literals;
DatabaseBackend::DatabaseBackend(Database &database) DatabaseBackend::DatabaseBackend(Database &database)
: m_database(database) : m_database(database)
, m_databaseHandle(nullptr) , m_databaseHandle(nullptr)
, m_busyHandler([](int) {
std::this_thread::sleep_for(10ms);
return true;
})
{ {
} }
@@ -197,28 +206,24 @@ void DatabaseBackend::closeWithoutException()
} }
} }
namespace {
int busyHandlerCallback(void *userData, int counter)
{
auto &&busyHandler = *static_cast<DatabaseBackend::BusyHandler *>(userData);
return busyHandler(counter);
}
} // namespace
void DatabaseBackend::registerBusyHandler() void DatabaseBackend::registerBusyHandler()
{ {
int resultCode = sqlite3_busy_handler(sqliteDatabaseHandle(), &busyHandlerCallback, nullptr); int resultCode = sqlite3_busy_handler(sqliteDatabaseHandle(), &busyHandlerCallback, &m_busyHandler);
checkIfBusyTimeoutWasSet(resultCode); checkIfBusyTimeoutWasSet(resultCode);
} }
void DatabaseBackend::registerRankingFunction()
{
}
int DatabaseBackend::busyHandlerCallback(void *, int counter)
{
Q_UNUSED(counter)
#ifdef QT_DEBUG
//qWarning() << "Busy handler invoked" << counter << "times!";
#endif
QThread::msleep(10);
return true;
}
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed() void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
{ {
if (m_databaseHandle == nullptr) if (m_databaseHandle == nullptr)
@@ -416,6 +421,12 @@ void DatabaseBackend::resetUpdateHook()
sqlite3_update_hook(m_databaseHandle, nullptr, nullptr); sqlite3_update_hook(m_databaseHandle, nullptr, nullptr);
} }
void DatabaseBackend::setBusyHandler(DatabaseBackend::BusyHandler &&busyHandler)
{
m_busyHandler = std::move(busyHandler);
registerBusyHandler();
}
void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens) void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens)
{ {
throw Exception(whatHasHappens); throw Exception(whatHasHappens);

View File

@@ -41,6 +41,8 @@ class Database;
class SQLITE_EXPORT DatabaseBackend class SQLITE_EXPORT DatabaseBackend
{ {
public: public:
using BusyHandler = std::function<bool(int count)>;
DatabaseBackend(Database &database); DatabaseBackend(Database &database);
~DatabaseBackend(); ~DatabaseBackend();
@@ -90,15 +92,16 @@ public:
void (*callback)(void *object, int, char const *database, char const *, long long rowId)); void (*callback)(void *object, int, char const *database, char const *, long long rowId));
void resetUpdateHook(); void resetUpdateHook();
void setBusyHandler(BusyHandler &&busyHandler);
void registerBusyHandler();
protected: protected:
bool databaseIsOpen() const; bool databaseIsOpen() const;
void setPragmaValue(Utils::SmallStringView pragma, Utils::SmallStringView value); void setPragmaValue(Utils::SmallStringView pragma, Utils::SmallStringView value);
Utils::SmallString pragmaValue(Utils::SmallStringView pragma); Utils::SmallString pragmaValue(Utils::SmallStringView pragma);
void registerBusyHandler();
void registerRankingFunction();
static int busyHandlerCallback(void*, int counter);
void checkForOpenDatabaseWhichCanBeClosed(); void checkForOpenDatabaseWhichCanBeClosed();
void checkDatabaseClosing(int resultCode); void checkDatabaseClosing(int resultCode);
@@ -126,6 +129,7 @@ protected:
private: private:
Database &m_database; Database &m_database;
sqlite3 *m_databaseHandle; sqlite3 *m_databaseHandle;
BusyHandler m_busyHandler;
}; };
} // namespace Sqlite } // namespace Sqlite