From 28da1261c803cfb62caf89e0885bbbe438fa0263 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 29 Mar 2018 18:33:59 +0200 Subject: [PATCH] Sqlite: Use compiled statements for transactions So we don't recompile them again and again. Change-Id: I54c95e9d81df86f4944b9e3d45a7277f93f37312 Reviewed-by: Ivan Donchevskii --- src/libs/sqlite/sqlitedatabase.cpp | 55 +++++++++++++++++++-- src/libs/sqlite/sqlitedatabase.h | 46 ++++++----------- tests/unit/unittest/sqlitedatabase-test.cpp | 35 +++++++++++++ 3 files changed, 101 insertions(+), 35 deletions(-) diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index 6fb57911396..0da9acfe314 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -27,6 +27,7 @@ #include "sqlitetable.h" #include "sqlitetransaction.h" +#include "sqlitereadwritestatement.h" #include @@ -54,11 +55,14 @@ Database::Database(Utils::PathString &&databaseFilePath, open(std::move(databaseFilePath)); } +Database::~Database() = default; + void Database::open() { m_databaseBackend.open(m_databaseFilePath, m_openMode); m_databaseBackend.setJournalMode(m_journalMode); m_databaseBackend.setBusyTimeout(m_busyTimeout); + registerTransactionStatements(); initializeTables(); m_isOpen = true; } @@ -129,12 +133,55 @@ void Database::execute(Utils::SmallStringView sqlStatement) void Database::initializeTables() { - ImmediateTransaction transaction(*this); + try { + ImmediateTransaction transaction(*this); - for (Table &table : m_sqliteTables) - table.initialize(*this); + for (Table &table : m_sqliteTables) + table.initialize(*this); - transaction.commit(); + transaction.commit(); + } catch (const StatementIsBusy &) { + initializeTables(); + } +} + +void Database::registerTransactionStatements() +{ + m_deferredBeginStatement = std::make_unique("BEGIN", *this); + m_immediateBeginStatement = std::make_unique("BEGIN IMMEDIATE", *this); + m_exclusiveBeginStatement = std::make_unique("BEGIN EXCLUSIVE", *this); + m_commitBeginStatement = std::make_unique("COMMIT", *this); + m_rollbackBeginStatement = std::make_unique("ROLLBACK", *this); +} + +void Database::deferredBegin() +{ + m_databaseMutex.lock(); + m_deferredBeginStatement->execute(); +} + +void Database::immediateBegin() +{ + m_databaseMutex.lock(); + m_immediateBeginStatement->execute(); +} + +void Database::exclusiveBegin() +{ + m_databaseMutex.lock(); + m_exclusiveBeginStatement->execute(); +} + +void Database::commit() +{ + m_commitBeginStatement->execute(); + m_databaseMutex.unlock(); +} + +void Database::rollback() +{ + m_rollbackBeginStatement->execute(); + m_databaseMutex.unlock(); } DatabaseBackend &Database::backend() diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h index 83c11860ca6..c1a82b389d7 100644 --- a/src/libs/sqlite/sqlitedatabase.h +++ b/src/libs/sqlite/sqlitedatabase.h @@ -40,6 +40,7 @@ namespace Sqlite { class ReadStatement; class WriteStatement; +class ReadWriteStatement; class SQLITE_EXPORT Database final : public TransactionInterface { @@ -54,10 +55,11 @@ public: Database(); Database(Utils::PathString &&databaseFilePath, - JournalMode journalMode=JournalMode::Wal); + JournalMode journalMode=JournalMode::Delete); Database(Utils::PathString &&databaseFilePath, std::chrono::milliseconds busyTimeout = {}, - JournalMode journalMode=JournalMode::Wal); + JournalMode journalMode=JournalMode::Delete); + ~Database(); Database(const Database &) = delete; Database &operator=(const Database &) = delete; @@ -104,44 +106,26 @@ public: return m_databaseBackend.totalChangesCount(); } - void deferredBegin() - { - m_databaseMutex.lock(); - execute("BEGIN"); - } - - void immediateBegin() - { - m_databaseMutex.lock(); - execute("BEGIN IMMEDIATE"); - } - - void exclusiveBegin() - { - m_databaseMutex.lock(); - execute("BEGIN EXCLUSIVE"); - } - - void commit() - { - execute("COMMIT"); - m_databaseMutex.unlock(); - } - - void rollback() - { - execute("ROLLBACK"); - m_databaseMutex.unlock(); - } + void deferredBegin(); + void immediateBegin(); + void exclusiveBegin(); + void commit(); + void rollback(); private: void initializeTables(); + void registerTransactionStatements(); std::mutex &databaseMutex() { return m_databaseMutex; } private: Utils::PathString m_databaseFilePath; DatabaseBackend m_databaseBackend; std::vector m_sqliteTables; + std::unique_ptr m_deferredBeginStatement; + std::unique_ptr m_immediateBeginStatement; + std::unique_ptr m_exclusiveBeginStatement; + std::unique_ptr m_commitBeginStatement; + std::unique_ptr m_rollbackBeginStatement; std::mutex m_databaseMutex; std::chrono::milliseconds m_busyTimeout; JournalMode m_journalMode = JournalMode::Wal; diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp index 73f3a427242..ca389f58fb4 100644 --- a/tests/unit/unittest/sqlitedatabase-test.cpp +++ b/tests/unit/unittest/sqlitedatabase-test.cpp @@ -140,6 +140,41 @@ TEST_F(SqliteDatabase, LastRowId) ASSERT_THAT(database.lastInsertedRowId(), 42); } +TEST_F(SqliteDatabase, DeferredBegin) +{ + ASSERT_ANY_THROW(database.deferredBegin()); + + database.commit(); +} + +TEST_F(SqliteDatabase, ImmediateBegin) +{ + ASSERT_ANY_THROW(database.immediateBegin()); + + database.commit(); +} + +TEST_F(SqliteDatabase, ExclusiveBegin) +{ + ASSERT_ANY_THROW(database.exclusiveBegin()); + + database.commit(); +} + +TEST_F(SqliteDatabase, Commit) +{ + database.deferredBegin(); + + ASSERT_ANY_THROW(database.commit()); +} + +TEST_F(SqliteDatabase, Rollback) +{ + database.deferredBegin(); + + ASSERT_ANY_THROW(database.rollback()); +} + void SqliteDatabase::SetUp() { database.setJournalMode(JournalMode::Memory);