forked from qt-creator/qt-creator
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:
@@ -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);
|
||||||
m_databaseBackend.setBusyTimeout(m_busyTimeout);
|
if (m_busyTimeout > 0ms)
|
||||||
|
m_databaseBackend.setBusyTimeout(m_busyTimeout);
|
||||||
|
else
|
||||||
|
m_databaseBackend.registerBusyHandler();
|
||||||
registerTransactionStatements();
|
registerTransactionStatements();
|
||||||
initializeTables();
|
initializeTables();
|
||||||
m_isOpen = true;
|
m_isOpen = true;
|
||||||
|
@@ -55,13 +55,13 @@ 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,
|
JournalMode journalMode = JournalMode::Wal);
|
||||||
std::chrono::milliseconds busyTimeout = 1000ms,
|
|
||||||
JournalMode journalMode=JournalMode::Wal);
|
|
||||||
~Database();
|
~Database();
|
||||||
|
|
||||||
Database(const Database &) = delete;
|
Database(const Database &) = delete;
|
||||||
@@ -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:
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user