Sqlite: Open Sqlite by default in exclusive locking mode

There are no extra files for the WAL in the excusive locking mode and
it can be even faster because the logging is happening on the heap.

Change-Id: I59d75dd2aa95d802ba67c8534a5cd8ab32a343df
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-05-12 12:21:58 +02:00
parent 52698bf924
commit b2cd0c32a5
9 changed files with 129 additions and 22 deletions

View File

@@ -86,3 +86,4 @@
#define SQLITE_OMIT_AUTORESET 1
#define SQLITE_OMIT_EXPLAIN 1
#define SQLITE_OMIT_TRACE 1
#define SQLITE_DEFAULT_LOCKING_MODE 1

View File

@@ -60,20 +60,21 @@ Database::Database()
{
}
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
: Database{std::move(databaseFilePath), 0ms, journalMode}
Database::Database(Utils::PathString databaseFilePath, JournalMode journalMode, LockingMode lockingMode)
: Database{std::move(databaseFilePath), 0ms, journalMode, lockingMode}
{}
Database::Database(Utils::PathString &&databaseFilePath,
Database::Database(Utils::PathString databaseFilePath,
std::chrono::milliseconds busyTimeout,
JournalMode journalMode)
JournalMode journalMode,
LockingMode lockingMode)
: m_databaseBackend(*this)
, m_busyTimeout(busyTimeout)
{
std::lock_guard lock{*this};
setJournalMode(journalMode);
open(std::move(databaseFilePath));
open(std::move(databaseFilePath), lockingMode);
#ifndef QT_NO_DEBUG
execute("PRAGMA reverse_unordered_selects=1");
@@ -87,9 +88,10 @@ void Database::activateLogging()
DatabaseBackend::activateLogging();
}
void Database::open()
void Database::open(LockingMode lockingMode)
{
m_databaseBackend.open(m_databaseFilePath, m_openMode);
m_databaseBackend.setLockingMode(lockingMode);
m_databaseBackend.setJournalMode(m_journalMode);
if (m_busyTimeout > 0ms)
m_databaseBackend.setBusyTimeout(m_busyTimeout);
@@ -99,11 +101,11 @@ void Database::open()
m_isOpen = true;
}
void Database::open(Utils::PathString &&databaseFilePath)
void Database::open(Utils::PathString &&databaseFilePath, LockingMode lockingMode)
{
m_isInitialized = QFileInfo::exists(QString(databaseFilePath));
setDatabaseFilePath(std::move(databaseFilePath));
open();
open(lockingMode);
}
void Database::close()
@@ -128,7 +130,7 @@ bool Database::isOpen() const
return m_isOpen;
}
void Database::setDatabaseFilePath(Utils::PathString &&databaseFilePath)
void Database::setDatabaseFilePath(Utils::PathString databaseFilePath)
{
m_databaseFilePath = std::move(databaseFilePath);
}
@@ -163,6 +165,11 @@ JournalMode Database::journalMode() const
return m_journalMode;
}
LockingMode Database::lockingMode() const
{
return m_databaseBackend.lockingMode();
}
void Database::setOpenMode(OpenMode openMode)
{
m_openMode = openMode;

View File

@@ -67,10 +67,13 @@ public:
using BusyHandler = DatabaseBackend::BusyHandler;
Database();
Database(Utils::PathString &&databaseFilePath, JournalMode journalMode = JournalMode::Wal);
Database(Utils::PathString &&databaseFilePath,
Database(Utils::PathString databaseFilePath,
JournalMode journalMode = JournalMode::Wal,
LockingMode lockingMode = LockingMode::Default);
Database(Utils::PathString databaseFilePath,
std::chrono::milliseconds busyTimeout,
JournalMode journalMode = JournalMode::Wal);
JournalMode journalMode = JournalMode::Wal,
LockingMode lockingMode = LockingMode::Default);
~Database();
Database(const Database &) = delete;
@@ -78,8 +81,8 @@ public:
static void activateLogging();
void open();
void open(Utils::PathString &&databaseFilePath);
void open(LockingMode lockingMode = LockingMode::Default);
void open(Utils::PathString &&databaseFilePath, LockingMode lockingMode = LockingMode::Default);
void close();
bool isInitialized() const;
@@ -87,12 +90,14 @@ public:
bool isOpen() const;
void setDatabaseFilePath(Utils::PathString &&databaseFilePath);
void setDatabaseFilePath(Utils::PathString databaseFilePath);
const Utils::PathString &databaseFilePath() const;
void setJournalMode(JournalMode journalMode);
JournalMode journalMode() const;
LockingMode lockingMode() const;
void setOpenMode(OpenMode openMode);
OpenMode openMode() const;

View File

@@ -137,7 +137,7 @@ void DatabaseBackend::setPragmaValue(Utils::SmallStringView pragmaKey, Utils::Sm
checkPragmaValue(pragmeValueInDatabase, newPragmaValue);
}
Utils::SmallString DatabaseBackend::pragmaValue(Utils::SmallStringView pragma)
Utils::SmallString DatabaseBackend::pragmaValue(Utils::SmallStringView pragma) const
{
return toValue<Utils::SmallString>("PRAGMA " + pragma);
}
@@ -152,6 +152,42 @@ JournalMode DatabaseBackend::journalMode()
return pragmaToJournalMode(pragmaValue("journal_mode"));
}
namespace {
Utils::SmallStringView lockingModeToPragma(LockingMode lockingMode)
{
switch (lockingMode) {
case LockingMode::Default:
return "";
case LockingMode::Normal:
return "normal";
case LockingMode::Exclusive:
return "exclusive";
}
return "";
}
LockingMode pragmaToLockingMode(Utils::SmallStringView pragma)
{
if (pragma == "normal")
return LockingMode::Normal;
else if (pragma == "exclusive")
return LockingMode::Exclusive;
return LockingMode::Default;
}
} // namespace
void DatabaseBackend::setLockingMode(LockingMode lockingMode)
{
if (lockingMode != LockingMode::Default)
setPragmaValue("main.locking_mode", lockingModeToPragma(lockingMode));
}
LockingMode DatabaseBackend::lockingMode() const
{
return pragmaToLockingMode(pragmaValue("main.locking_mode"));
}
int DatabaseBackend::changesCount() const
{
return sqlite3_changes(sqliteDatabaseHandle());
@@ -454,7 +490,7 @@ void DatabaseBackend::throwDatabaseIsNotOpen(const char *whatHasHappens) const
}
template<typename Type>
Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement)
Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement) const
{
try {
ReadWriteStatement<1> statement(sqlStatement, m_database);

View File

@@ -68,6 +68,9 @@ public:
void setJournalMode(JournalMode journalMode);
JournalMode journalMode();
void setLockingMode(LockingMode lockingMode);
LockingMode lockingMode() const;
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
int changesCount() const;
@@ -79,7 +82,7 @@ public:
void execute(Utils::SmallStringView sqlStatement);
template<typename Type>
Type toValue(Utils::SmallStringView sqlStatement);
Type toValue(Utils::SmallStringView sqlStatement) const;
static int openMode(OpenMode);
@@ -100,8 +103,7 @@ protected:
bool databaseIsOpen() const;
void setPragmaValue(Utils::SmallStringView pragma, Utils::SmallStringView value);
Utils::SmallString pragmaValue(Utils::SmallStringView pragma);
Utils::SmallString pragmaValue(Utils::SmallStringView pragma) const;
void checkForOpenDatabaseWhichCanBeClosed();
void checkDatabaseClosing(int resultCode);

View File

@@ -58,6 +58,8 @@ enum class JournalMode : char
Wal
};
enum class LockingMode : char { Default, Normal, Exclusive };
enum class OpenMode : char
{
ReadOnly,

View File

@@ -433,6 +433,20 @@ const char *toText(Operation operation)
return "";
}
const char *toText(LockingMode lockingMode)
{
switch (lockingMode) {
case LockingMode::Default:
return "Default";
case LockingMode::Normal:
return "Normal";
case LockingMode::Exclusive:
return "Exclusive";
}
return "";
}
} // namespace
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
@@ -455,6 +469,11 @@ std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
return out;
}
std::ostream &operator<<(std::ostream &out, LockingMode lockingMode)
{
return out << toText(lockingMode);
}
std::ostream &operator<<(std::ostream &out, Operation operation)
{
return out << toText(operation);

View File

@@ -69,11 +69,13 @@ class Value;
class ValueView;
class SessionChangeSet;
enum class Operation : char;
enum class LockingMode : char;
std::ostream &operator<<(std::ostream &out, const Value &value);
std::ostream &operator<<(std::ostream &out, const ValueView &value);
std::ostream &operator<<(std::ostream &out, Operation operation);
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset);
std::ostream &operator<<(std::ostream &out, LockingMode lockingMode);
namespace SessionChangeSetInternal {
class ConstIterator;

View File

@@ -111,6 +111,39 @@ TEST_F(SqliteDatabase, SetJournalMode)
ASSERT_THAT(database.journalMode(), JournalMode::Memory);
}
TEST_F(SqliteDatabase, LockingModeIsByDefaultExlusive)
{
ASSERT_THAT(database.lockingMode(), Sqlite::LockingMode::Exclusive);
}
TEST_F(SqliteDatabase, CreateDatabaseWithLockingModeNormal)
{
Utils::PathString path{Utils::TemporaryDirectory::masterDirectoryPath()
+ "/database_exclusive_locked.db"};
Sqlite::Database database{path, JournalMode::Wal, Sqlite::LockingMode::Normal};
ASSERT_THAT(database.lockingMode(), Sqlite::LockingMode::Normal);
}
TEST_F(SqliteDatabase, ExclusivelyLockedDatabaseIsLockedForSecondConnection)
{
Utils::PathString path{Utils::TemporaryDirectory::masterDirectoryPath()
+ "/database_exclusive_locked.db"};
Sqlite::Database database{path};
ASSERT_THROW(Sqlite::Database database2{path}, Sqlite::StatementIsBusy);
}
TEST_F(SqliteDatabase, NormalLockedDatabaseCanBeReopened)
{
Utils::PathString path{Utils::TemporaryDirectory::masterDirectoryPath()
+ "/database_exclusive_locked.db"};
Sqlite::Database database{path, JournalMode::Wal, Sqlite::LockingMode::Normal};
ASSERT_NO_THROW((Sqlite::Database{path, JournalMode::Wal, Sqlite::LockingMode::Normal}));
}
TEST_F(SqliteDatabase, SetOpenlMode)
{
database.setOpenMode(OpenMode::ReadOnly);