forked from qt-creator/qt-creator
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:
1
src/libs/3rdparty/sqlite/config.h
vendored
1
src/libs/3rdparty/sqlite/config.h
vendored
@@ -86,3 +86,4 @@
|
|||||||
#define SQLITE_OMIT_AUTORESET 1
|
#define SQLITE_OMIT_AUTORESET 1
|
||||||
#define SQLITE_OMIT_EXPLAIN 1
|
#define SQLITE_OMIT_EXPLAIN 1
|
||||||
#define SQLITE_OMIT_TRACE 1
|
#define SQLITE_OMIT_TRACE 1
|
||||||
|
#define SQLITE_DEFAULT_LOCKING_MODE 1
|
||||||
|
@@ -60,20 +60,21 @@ Database::Database()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
|
Database::Database(Utils::PathString databaseFilePath, JournalMode journalMode, LockingMode lockingMode)
|
||||||
: Database{std::move(databaseFilePath), 0ms, journalMode}
|
: Database{std::move(databaseFilePath), 0ms, journalMode, lockingMode}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Database::Database(Utils::PathString &&databaseFilePath,
|
Database::Database(Utils::PathString databaseFilePath,
|
||||||
std::chrono::milliseconds busyTimeout,
|
std::chrono::milliseconds busyTimeout,
|
||||||
JournalMode journalMode)
|
JournalMode journalMode,
|
||||||
|
LockingMode lockingMode)
|
||||||
: m_databaseBackend(*this)
|
: m_databaseBackend(*this)
|
||||||
, m_busyTimeout(busyTimeout)
|
, m_busyTimeout(busyTimeout)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{*this};
|
std::lock_guard lock{*this};
|
||||||
|
|
||||||
setJournalMode(journalMode);
|
setJournalMode(journalMode);
|
||||||
open(std::move(databaseFilePath));
|
open(std::move(databaseFilePath), lockingMode);
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
execute("PRAGMA reverse_unordered_selects=1");
|
execute("PRAGMA reverse_unordered_selects=1");
|
||||||
@@ -87,9 +88,10 @@ void Database::activateLogging()
|
|||||||
DatabaseBackend::activateLogging();
|
DatabaseBackend::activateLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::open()
|
void Database::open(LockingMode lockingMode)
|
||||||
{
|
{
|
||||||
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
||||||
|
m_databaseBackend.setLockingMode(lockingMode);
|
||||||
m_databaseBackend.setJournalMode(m_journalMode);
|
m_databaseBackend.setJournalMode(m_journalMode);
|
||||||
if (m_busyTimeout > 0ms)
|
if (m_busyTimeout > 0ms)
|
||||||
m_databaseBackend.setBusyTimeout(m_busyTimeout);
|
m_databaseBackend.setBusyTimeout(m_busyTimeout);
|
||||||
@@ -99,11 +101,11 @@ void Database::open()
|
|||||||
m_isOpen = true;
|
m_isOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::open(Utils::PathString &&databaseFilePath)
|
void Database::open(Utils::PathString &&databaseFilePath, LockingMode lockingMode)
|
||||||
{
|
{
|
||||||
m_isInitialized = QFileInfo::exists(QString(databaseFilePath));
|
m_isInitialized = QFileInfo::exists(QString(databaseFilePath));
|
||||||
setDatabaseFilePath(std::move(databaseFilePath));
|
setDatabaseFilePath(std::move(databaseFilePath));
|
||||||
open();
|
open(lockingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::close()
|
void Database::close()
|
||||||
@@ -128,7 +130,7 @@ bool Database::isOpen() const
|
|||||||
return m_isOpen;
|
return m_isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::setDatabaseFilePath(Utils::PathString &&databaseFilePath)
|
void Database::setDatabaseFilePath(Utils::PathString databaseFilePath)
|
||||||
{
|
{
|
||||||
m_databaseFilePath = std::move(databaseFilePath);
|
m_databaseFilePath = std::move(databaseFilePath);
|
||||||
}
|
}
|
||||||
@@ -163,6 +165,11 @@ JournalMode Database::journalMode() const
|
|||||||
return m_journalMode;
|
return m_journalMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LockingMode Database::lockingMode() const
|
||||||
|
{
|
||||||
|
return m_databaseBackend.lockingMode();
|
||||||
|
}
|
||||||
|
|
||||||
void Database::setOpenMode(OpenMode openMode)
|
void Database::setOpenMode(OpenMode openMode)
|
||||||
{
|
{
|
||||||
m_openMode = openMode;
|
m_openMode = openMode;
|
||||||
|
@@ -67,10 +67,13 @@ public:
|
|||||||
using BusyHandler = DatabaseBackend::BusyHandler;
|
using BusyHandler = DatabaseBackend::BusyHandler;
|
||||||
|
|
||||||
Database();
|
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,
|
std::chrono::milliseconds busyTimeout,
|
||||||
JournalMode journalMode = JournalMode::Wal);
|
JournalMode journalMode = JournalMode::Wal,
|
||||||
|
LockingMode lockingMode = LockingMode::Default);
|
||||||
~Database();
|
~Database();
|
||||||
|
|
||||||
Database(const Database &) = delete;
|
Database(const Database &) = delete;
|
||||||
@@ -78,8 +81,8 @@ public:
|
|||||||
|
|
||||||
static void activateLogging();
|
static void activateLogging();
|
||||||
|
|
||||||
void open();
|
void open(LockingMode lockingMode = LockingMode::Default);
|
||||||
void open(Utils::PathString &&databaseFilePath);
|
void open(Utils::PathString &&databaseFilePath, LockingMode lockingMode = LockingMode::Default);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
bool isInitialized() const;
|
bool isInitialized() const;
|
||||||
@@ -87,12 +90,14 @@ public:
|
|||||||
|
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
|
|
||||||
void setDatabaseFilePath(Utils::PathString &&databaseFilePath);
|
void setDatabaseFilePath(Utils::PathString databaseFilePath);
|
||||||
const Utils::PathString &databaseFilePath() const;
|
const Utils::PathString &databaseFilePath() const;
|
||||||
|
|
||||||
void setJournalMode(JournalMode journalMode);
|
void setJournalMode(JournalMode journalMode);
|
||||||
JournalMode journalMode() const;
|
JournalMode journalMode() const;
|
||||||
|
|
||||||
|
LockingMode lockingMode() const;
|
||||||
|
|
||||||
void setOpenMode(OpenMode openMode);
|
void setOpenMode(OpenMode openMode);
|
||||||
OpenMode openMode() const;
|
OpenMode openMode() const;
|
||||||
|
|
||||||
|
@@ -137,7 +137,7 @@ void DatabaseBackend::setPragmaValue(Utils::SmallStringView pragmaKey, Utils::Sm
|
|||||||
checkPragmaValue(pragmeValueInDatabase, newPragmaValue);
|
checkPragmaValue(pragmeValueInDatabase, newPragmaValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::SmallString DatabaseBackend::pragmaValue(Utils::SmallStringView pragma)
|
Utils::SmallString DatabaseBackend::pragmaValue(Utils::SmallStringView pragma) const
|
||||||
{
|
{
|
||||||
return toValue<Utils::SmallString>("PRAGMA " + pragma);
|
return toValue<Utils::SmallString>("PRAGMA " + pragma);
|
||||||
}
|
}
|
||||||
@@ -152,6 +152,42 @@ JournalMode DatabaseBackend::journalMode()
|
|||||||
return pragmaToJournalMode(pragmaValue("journal_mode"));
|
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
|
int DatabaseBackend::changesCount() const
|
||||||
{
|
{
|
||||||
return sqlite3_changes(sqliteDatabaseHandle());
|
return sqlite3_changes(sqliteDatabaseHandle());
|
||||||
@@ -453,8 +489,8 @@ void DatabaseBackend::throwDatabaseIsNotOpen(const char *whatHasHappens) const
|
|||||||
throw DatabaseIsNotOpen(whatHasHappens);
|
throw DatabaseIsNotOpen(whatHasHappens);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template<typename Type>
|
||||||
Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement)
|
Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement) const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ReadWriteStatement<1> statement(sqlStatement, m_database);
|
ReadWriteStatement<1> statement(sqlStatement, m_database);
|
||||||
|
@@ -68,6 +68,9 @@ public:
|
|||||||
void setJournalMode(JournalMode journalMode);
|
void setJournalMode(JournalMode journalMode);
|
||||||
JournalMode journalMode();
|
JournalMode journalMode();
|
||||||
|
|
||||||
|
void setLockingMode(LockingMode lockingMode);
|
||||||
|
LockingMode lockingMode() const;
|
||||||
|
|
||||||
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
|
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
|
||||||
|
|
||||||
int changesCount() const;
|
int changesCount() const;
|
||||||
@@ -78,8 +81,8 @@ public:
|
|||||||
|
|
||||||
void execute(Utils::SmallStringView sqlStatement);
|
void execute(Utils::SmallStringView sqlStatement);
|
||||||
|
|
||||||
template <typename Type>
|
template<typename Type>
|
||||||
Type toValue(Utils::SmallStringView sqlStatement);
|
Type toValue(Utils::SmallStringView sqlStatement) const;
|
||||||
|
|
||||||
static int openMode(OpenMode);
|
static int openMode(OpenMode);
|
||||||
|
|
||||||
@@ -100,8 +103,7 @@ 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) const;
|
||||||
|
|
||||||
|
|
||||||
void checkForOpenDatabaseWhichCanBeClosed();
|
void checkForOpenDatabaseWhichCanBeClosed();
|
||||||
void checkDatabaseClosing(int resultCode);
|
void checkDatabaseClosing(int resultCode);
|
||||||
|
@@ -58,6 +58,8 @@ enum class JournalMode : char
|
|||||||
Wal
|
Wal
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class LockingMode : char { Default, Normal, Exclusive };
|
||||||
|
|
||||||
enum class OpenMode : char
|
enum class OpenMode : char
|
||||||
{
|
{
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
|
@@ -433,6 +433,20 @@ const char *toText(Operation operation)
|
|||||||
|
|
||||||
return "";
|
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
|
} // namespace
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
|
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
|
||||||
@@ -455,6 +469,11 @@ std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, LockingMode lockingMode)
|
||||||
|
{
|
||||||
|
return out << toText(lockingMode);
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, Operation operation)
|
std::ostream &operator<<(std::ostream &out, Operation operation)
|
||||||
{
|
{
|
||||||
return out << toText(operation);
|
return out << toText(operation);
|
||||||
|
@@ -69,11 +69,13 @@ class Value;
|
|||||||
class ValueView;
|
class ValueView;
|
||||||
class SessionChangeSet;
|
class SessionChangeSet;
|
||||||
enum class Operation : char;
|
enum class Operation : char;
|
||||||
|
enum class LockingMode : char;
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const Value &value);
|
std::ostream &operator<<(std::ostream &out, const Value &value);
|
||||||
std::ostream &operator<<(std::ostream &out, const ValueView &value);
|
std::ostream &operator<<(std::ostream &out, const ValueView &value);
|
||||||
std::ostream &operator<<(std::ostream &out, Operation operation);
|
std::ostream &operator<<(std::ostream &out, Operation operation);
|
||||||
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset);
|
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset);
|
||||||
|
std::ostream &operator<<(std::ostream &out, LockingMode lockingMode);
|
||||||
|
|
||||||
namespace SessionChangeSetInternal {
|
namespace SessionChangeSetInternal {
|
||||||
class ConstIterator;
|
class ConstIterator;
|
||||||
|
@@ -111,6 +111,39 @@ TEST_F(SqliteDatabase, SetJournalMode)
|
|||||||
ASSERT_THAT(database.journalMode(), JournalMode::Memory);
|
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)
|
TEST_F(SqliteDatabase, SetOpenlMode)
|
||||||
{
|
{
|
||||||
database.setOpenMode(OpenMode::ReadOnly);
|
database.setOpenMode(OpenMode::ReadOnly);
|
||||||
|
Reference in New Issue
Block a user