diff --git a/src/libs/database/CMakeLists.txt b/src/libs/database/CMakeLists.txt
index 29b07d8b..e282a328 100644
--- a/src/libs/database/CMakeLists.txt
+++ b/src/libs/database/CMakeLists.txt
@@ -11,6 +11,7 @@ add_library(lmsdatabase STATIC
impl/Listen.cpp
impl/MediaLibrary.cpp
impl/Migration.cpp
+ impl/Object.cpp
impl/PlayListFile.cpp
impl/PlayQueue.cpp
impl/TrackArtistLink.cpp
@@ -31,6 +32,7 @@ add_library(lmsdatabase STATIC
impl/TrackEmbeddedImage.cpp
impl/TrackEmbeddedImageLink.cpp
impl/TrackLyrics.cpp
+ impl/Transaction.cpp
impl/Types.cpp
impl/UIState.cpp
impl/User.cpp
diff --git a/src/libs/database/impl/Object.cpp b/src/libs/database/impl/Object.cpp
new file mode 100644
index 00000000..18e56f77
--- /dev/null
+++ b/src/libs/database/impl/Object.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include "database/Object.hpp"
+
+#include "TransactionChecker.hpp"
+
+namespace lms::db
+{
+ void ObjectPtrBase::checkWriteTransaction(Wt::Dbo::Session& session)
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::checkWriteTransaction(session);
+#endif
+ }
+} // namespace lms::db
diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp
index 4d7475be..64f4e19f 100644
--- a/src/libs/database/impl/Session.cpp
+++ b/src/libs/database/impl/Session.cpp
@@ -48,12 +48,12 @@
#include "database/TrackFeatures.hpp"
#include "database/TrackList.hpp"
#include "database/TrackLyrics.hpp"
-#include "database/TransactionChecker.hpp"
#include "database/UIState.hpp"
#include "database/User.hpp"
#include "Db.hpp"
#include "Migration.hpp"
+#include "TransactionChecker.hpp"
#include "Utils.hpp"
#include "traits/EnumSetTraits.hpp"
#include "traits/ImageHashTypeTraits.hpp"
@@ -62,40 +62,6 @@
namespace lms::db
{
- WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
- : _lock{ mutex }
- , _transaction{ session }
- {
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::pushWriteTransaction(_transaction.session());
-#endif
- }
-
- WriteTransaction::~WriteTransaction()
- {
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::popWriteTransaction(_transaction.session());
-#endif
-
- core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "Commit" };
- _transaction.commit();
- }
-
- ReadTransaction::ReadTransaction(Wt::Dbo::Session& session)
- : _transaction{ session }
- {
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::pushReadTransaction(_transaction.session());
-#endif
- }
-
- ReadTransaction::~ReadTransaction()
- {
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::popReadTransaction(_transaction.session());
-#endif
- }
-
Session::Session(IDb& db)
: _db{ db }
{
@@ -148,6 +114,19 @@ namespace lms::db
return ReadTransaction{ _session };
}
+ void Session::checkWriteTransaction() const
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::checkWriteTransaction(_session);
+#endif
+ }
+ void Session::checkReadTransaction() const
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::checkReadTransaction(_session);
+#endif
+ }
+
void Session::execute(std::string_view statement)
{
utils::executeCommand(_session, std::string{ statement });
diff --git a/src/libs/database/impl/Transaction.cpp b/src/libs/database/impl/Transaction.cpp
new file mode 100644
index 00000000..af6b5373
--- /dev/null
+++ b/src/libs/database/impl/Transaction.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include "database/Transaction.hpp"
+
+#include "core/RecursiveSharedMutex.hpp"
+
+#include "TransactionChecker.hpp"
+
+namespace lms::db
+{
+ WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
+ : _lock{ mutex }
+ , _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" }
+ , _transaction{ session }
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::pushWriteTransaction(_transaction.session());
+#endif
+ }
+
+ WriteTransaction::~WriteTransaction()
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::popWriteTransaction(_transaction.session());
+#endif
+
+ core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "Commit" };
+ _transaction.commit();
+ }
+
+ ReadTransaction::ReadTransaction(Wt::Dbo::Session& session)
+ : _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" }
+ , _transaction{ session }
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::pushReadTransaction(_transaction.session());
+#endif
+ }
+
+ ReadTransaction::~ReadTransaction()
+ {
+#if LMS_CHECK_TRANSACTION_ACCESSES
+ TransactionChecker::popReadTransaction(_transaction.session());
+#endif
+ }
+} // namespace lms::db
diff --git a/src/libs/database/impl/TransactionChecker.cpp b/src/libs/database/impl/TransactionChecker.cpp
index 003e84bf..89d1f45c 100644
--- a/src/libs/database/impl/TransactionChecker.cpp
+++ b/src/libs/database/impl/TransactionChecker.cpp
@@ -17,7 +17,7 @@
* along with LMS. If not, see .
*/
-#include "database/TransactionChecker.hpp"
+#include "TransactionChecker.hpp"
static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build");
@@ -32,39 +32,39 @@ namespace lms::db
struct StackEntry
{
TransactionChecker::TransactionType type;
- Wt::Dbo::Session* session{};
+ const Wt::Dbo::Session* session{};
};
static thread_local std::vector transactionStack;
} // namespace
- void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session)
+ void TransactionChecker::pushWriteTransaction(const Wt::Dbo::Session& session)
{
pushTransaction(TransactionType::Write, session);
}
- void TransactionChecker::pushReadTransaction(Wt::Dbo::Session& session)
+ void TransactionChecker::pushReadTransaction(const Wt::Dbo::Session& session)
{
pushTransaction(TransactionType::Read, session);
}
- void TransactionChecker::popWriteTransaction(Wt::Dbo::Session& session)
+ void TransactionChecker::popWriteTransaction(const Wt::Dbo::Session& session)
{
popTransaction(TransactionType::Write, session);
}
- void TransactionChecker::popReadTransaction(Wt::Dbo::Session& session)
+ void TransactionChecker::popReadTransaction(const Wt::Dbo::Session& session)
{
popTransaction(TransactionType::Read, session);
}
- void TransactionChecker::pushTransaction(TransactionType type, Wt::Dbo::Session& session)
+ void TransactionChecker::pushTransaction(TransactionType type, const Wt::Dbo::Session& session)
{
assert(transactionStack.empty() || transactionStack.back().session == &session);
transactionStack.push_back(StackEntry{ type, &session });
}
- void TransactionChecker::popTransaction(TransactionType type, Wt::Dbo::Session& session)
+ void TransactionChecker::popTransaction(TransactionType type, const Wt::Dbo::Session& session)
{
assert(!transactionStack.empty());
assert(transactionStack.back().type == type);
@@ -72,25 +72,25 @@ namespace lms::db
transactionStack.pop_back();
}
- void TransactionChecker::checkWriteTransaction(Wt::Dbo::Session& session)
+ void TransactionChecker::checkWriteTransaction(const Wt::Dbo::Session& session)
{
assert(!transactionStack.empty());
assert(transactionStack.back().type == TransactionType::Write);
assert(transactionStack.back().session == &session);
}
- void TransactionChecker::checkWriteTransaction(Session& session)
+ void TransactionChecker::checkWriteTransaction(const Session& session)
{
checkWriteTransaction(*session.getDboSession());
}
- void TransactionChecker::checkReadTransaction(Wt::Dbo::Session& session)
+ void TransactionChecker::checkReadTransaction(const Wt::Dbo::Session& session)
{
assert(!transactionStack.empty());
assert(transactionStack.back().session == &session);
}
- void TransactionChecker::checkReadTransaction(Session& session)
+ void TransactionChecker::checkReadTransaction(const Session& session)
{
checkReadTransaction(*session.getDboSession());
}
diff --git a/src/libs/database/include/database/TransactionChecker.hpp b/src/libs/database/impl/TransactionChecker.hpp
similarity index 58%
rename from src/libs/database/include/database/TransactionChecker.hpp
rename to src/libs/database/impl/TransactionChecker.hpp
index fffeedb7..1076f33d 100644
--- a/src/libs/database/include/database/TransactionChecker.hpp
+++ b/src/libs/database/impl/TransactionChecker.hpp
@@ -26,8 +26,11 @@
#endif
#if LMS_CHECK_TRANSACTION_ACCESSES
- #include
- #include
+
+namespace Wt::Dbo
+{
+ class Session;
+}
namespace lms::db
{
@@ -42,20 +45,20 @@ namespace lms::db
Write,
};
- static void pushWriteTransaction(Wt::Dbo::Session& session);
- static void pushReadTransaction(Wt::Dbo::Session& session);
+ static void pushWriteTransaction(const Wt::Dbo::Session& session);
+ static void pushReadTransaction(const Wt::Dbo::Session& session);
- static void popWriteTransaction(Wt::Dbo::Session& session);
- static void popReadTransaction(Wt::Dbo::Session& session);
+ static void popWriteTransaction(const Wt::Dbo::Session& session);
+ static void popReadTransaction(const Wt::Dbo::Session& session);
- static void checkWriteTransaction(Wt::Dbo::Session& session);
- static void checkWriteTransaction(Session& session);
- static void checkReadTransaction(Wt::Dbo::Session& session);
- static void checkReadTransaction(Session& session);
+ static void checkWriteTransaction(const Wt::Dbo::Session& session);
+ static void checkWriteTransaction(const Session& session);
+ static void checkReadTransaction(const Wt::Dbo::Session& session);
+ static void checkReadTransaction(const Session& session);
private:
- static void pushTransaction(TransactionType type, Wt::Dbo::Session& session);
- static void popTransaction(TransactionType type, Wt::Dbo::Session& session);
+ static void pushTransaction(TransactionType type, const Wt::Dbo::Session& session);
+ static void popTransaction(TransactionType type, const Wt::Dbo::Session& session);
};
} // namespace lms::db
diff --git a/src/libs/database/include/database/MediaLibrary.hpp b/src/libs/database/include/database/MediaLibrary.hpp
index 0649674e..d26b0336 100644
--- a/src/libs/database/include/database/MediaLibrary.hpp
+++ b/src/libs/database/include/database/MediaLibrary.hpp
@@ -20,6 +20,7 @@
#pragma once
#include
+#include
#include
#include
diff --git a/src/libs/database/include/database/Object.hpp b/src/libs/database/include/database/Object.hpp
index 6ea23173..90456b0b 100644
--- a/src/libs/database/include/database/Object.hpp
+++ b/src/libs/database/include/database/Object.hpp
@@ -20,15 +20,19 @@
#pragma once
#include
-#include
#include "database/IdType.hpp"
-#include "database/TransactionChecker.hpp"
namespace lms::db
{
+ class ObjectPtrBase
+ {
+ protected:
+ static void checkWriteTransaction(Wt::Dbo::Session& session);
+ };
+
template
- class ObjectPtr
+ class ObjectPtr : public ObjectPtrBase
{
public:
ObjectPtr() = default;
@@ -45,18 +49,13 @@ namespace lms::db
auto modify()
{
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::checkWriteTransaction(*_obj.session());
-#endif
+ checkWriteTransaction(*_obj.session());
return _obj.modify();
}
void remove()
{
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::checkWriteTransaction(*_obj.session());
-#endif
-
+ checkWriteTransaction(*_obj.session());
_obj.remove();
}
diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp
index 82586461..c07f43c5 100644
--- a/src/libs/database/include/database/Session.hpp
+++ b/src/libs/database/include/database/Session.hpp
@@ -19,52 +19,17 @@
#pragma once
-#include
-#include
+#include
#include
#include
+#include
#include
-#include "core/ITraceLogger.hpp"
-#include "core/RecursiveSharedMutex.hpp"
-#include "database/TransactionChecker.hpp"
+#include "database/Transaction.hpp"
namespace lms::db
{
- class WriteTransaction
- {
- public:
- ~WriteTransaction();
-
- private:
- friend class Session;
- WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session);
-
- WriteTransaction(const WriteTransaction&) = delete;
- WriteTransaction& operator=(const WriteTransaction&) = delete;
-
- const std::unique_lock _lock;
- const core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" }; // before actual transaction
- Wt::Dbo::Transaction _transaction;
- };
-
- class ReadTransaction
- {
- public:
- ~ReadTransaction();
-
- private:
- friend class Session;
- ReadTransaction(Wt::Dbo::Session& session);
-
- ReadTransaction(const ReadTransaction&) = delete;
- ReadTransaction& operator=(const ReadTransaction&) = delete;
-
- const core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" }; // before actual transaction
- Wt::Dbo::Transaction _transaction;
- };
-
class IDb;
class Session
{
@@ -77,18 +42,8 @@ namespace lms::db
[[nodiscard]] WriteTransaction createWriteTransaction();
[[nodiscard]] ReadTransaction createReadTransaction();
- void checkWriteTransaction()
- {
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::checkWriteTransaction(_session);
-#endif
- }
- void checkReadTransaction()
- {
-#if LMS_CHECK_TRANSACTION_ACCESSES
- TransactionChecker::checkReadTransaction(_session);
-#endif
- }
+ void checkWriteTransaction() const;
+ void checkReadTransaction() const;
void execute(std::string_view statement);
@@ -107,14 +62,10 @@ namespace lms::db
void refreshTracingLoggerStats();
// returning a ptr here to ease further wrapping using operator->
- Wt::Dbo::Session* getDboSession()
- {
- return &_session;
- }
- IDb& getDb()
- {
- return _db;
- }
+ Wt::Dbo::Session* getDboSession() { return &_session; }
+ const Wt::Dbo::Session* getDboSession() const { return &_session; }
+
+ IDb& getDb() { return _db; }
template
typename Object::pointer create(Args&&... args)
diff --git a/src/libs/database/include/database/Transaction.hpp b/src/libs/database/include/database/Transaction.hpp
new file mode 100644
index 00000000..095e628d
--- /dev/null
+++ b/src/libs/database/include/database/Transaction.hpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include
+
+#include
+
+#include "core/ITraceLogger.hpp"
+
+namespace lms::core
+{
+ class RecursiveSharedMutex;
+}
+
+namespace lms::db
+{
+ class WriteTransaction
+ {
+ public:
+ ~WriteTransaction();
+
+ private:
+ friend class Session;
+ WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session);
+
+ WriteTransaction(const WriteTransaction&) = delete;
+ WriteTransaction& operator=(const WriteTransaction&) = delete;
+
+ const std::unique_lock _lock;
+ const core::tracing::ScopedTrace _trace; // before actual transaction
+ Wt::Dbo::Transaction _transaction;
+ };
+
+ class ReadTransaction
+ {
+ public:
+ ~ReadTransaction();
+
+ private:
+ friend class Session;
+ ReadTransaction(Wt::Dbo::Session& session);
+
+ ReadTransaction(const ReadTransaction&) = delete;
+ ReadTransaction& operator=(const ReadTransaction&) = delete;
+
+ const core::tracing::ScopedTrace _trace; // before actual transaction
+ Wt::Dbo::Transaction _transaction;
+ };
+} // namespace lms::db
\ No newline at end of file