From 5055c6bcd571dedfb2f129b8b775980eb08b792c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 6 Mar 2022 17:53:23 +0000 Subject: Add helper class for working within a transaction with DB clients --- icetray/icetray/abstractDatabaseClient.cpp | 9 +++ icetray/icetray/abstractDatabaseClient.h | 6 ++ icetray/icetray/transactionalDatabaseClient.cpp | 7 +++ icetray/icetray/transactionalDatabaseClient.h | 74 +++++++++++++++++++++++++ icetray/unittests/testIceTray.cpp | 34 ++++++++++++ icetray/unittests/testIceTrayServiceI.cpp | 3 +- 6 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 icetray/icetray/transactionalDatabaseClient.cpp create mode 100644 icetray/icetray/transactionalDatabaseClient.h diff --git a/icetray/icetray/abstractDatabaseClient.cpp b/icetray/icetray/abstractDatabaseClient.cpp index c23d320..bb8a597 100644 --- a/icetray/icetray/abstractDatabaseClient.cpp +++ b/icetray/icetray/abstractDatabaseClient.cpp @@ -1,7 +1,16 @@ #include "abstractDatabaseClient.h" +#include "transactionalDatabaseClient.h" +#include #include #include +// IWYU pragma: no_include namespace IceTray { AbstractDatabaseClient::AbstractDatabaseClient(DB::ConnectionPoolPtr d) : db(std::move(d)) { } + + TransactionalDatabaseClient> + AbstractDatabaseClient::transactional() + { + return TransactionalDatabaseClient {db->get()}; + } } diff --git a/icetray/icetray/abstractDatabaseClient.h b/icetray/icetray/abstractDatabaseClient.h index 5b0807d..98a5eec 100644 --- a/icetray/icetray/abstractDatabaseClient.h +++ b/icetray/icetray/abstractDatabaseClient.h @@ -2,12 +2,16 @@ #define ICETRAY_ABSTRACTDATABASECLIENT_H #include "basicDataClient.h" +#include "transactionalDatabaseClient.h" #include #include #include #include #include // IWYU pragma: no_include "resourcePool.impl.h" +namespace DB { + class Connection; +} namespace IceTray { class SqlSource; @@ -42,6 +46,8 @@ namespace IceTray { return modify(c.get(), sql, params...); } + TransactionalDatabaseClient> transactional(); + protected: DB::ConnectionPoolPtr db; }; diff --git a/icetray/icetray/transactionalDatabaseClient.cpp b/icetray/icetray/transactionalDatabaseClient.cpp new file mode 100644 index 0000000..e0376f0 --- /dev/null +++ b/icetray/icetray/transactionalDatabaseClient.cpp @@ -0,0 +1,7 @@ +#include "transactionalDatabaseClient.h" +// IWYU pragma: no_include "resourcePool.impl.h" + +namespace IceTray { + template class TransactionalDatabaseClient; + template class TransactionalDatabaseClient>; +} diff --git a/icetray/icetray/transactionalDatabaseClient.h b/icetray/icetray/transactionalDatabaseClient.h new file mode 100644 index 0000000..c496110 --- /dev/null +++ b/icetray/icetray/transactionalDatabaseClient.h @@ -0,0 +1,74 @@ +#ifndef ICETRAY_TRANSACTIONALDATABASECLIENT_H +#define ICETRAY_TRANSACTIONALDATABASECLIENT_H + +#include "basicDataClient.h" +#include "connection.h" +#include "connection_fwd.h" +#include +#include +#include +#include +#include +#include +#include +#include +// IWYU pragma: no_include + +namespace IceTray { + class SqlSource; + + template class DLL_PUBLIC TransactionalDatabaseClient : public BasicDatabaseClient { + public: + explicit TransactionalDatabaseClient(Connection db_) : db(std::move(db_)) + { + db->beginTx(); + } + + virtual ~TransactionalDatabaseClient() + { + if (std::uncaught_exceptions()) { + try { + db->rollbackTx(); + } + catch (...) { + } + } + else { + db->commitTx(); + } + } + + SPECIAL_MEMBERS_DEFAULT_MOVE_NO_COPY(TransactionalDatabaseClient); + + using BasicDatabaseClient::fetch; + using BasicDatabaseClient::modify; + + template + inline Domain + fetch(const SqlSource & sql, const Params &... params) + { + return fetch(std::nullopt, sql, params...); + } + + template + inline Domain + fetch(const std::optional & typeIdCol, const SqlSource & sql, const Params &... params) + { + return fetch(db.get(), typeIdCol, sql, params...); + } + + template + inline auto + modify(const SqlSource & sql, const Params &... params) + { + return modify(db.get(), sql, params...); + } + + protected: + Connection db; + }; + extern template class TransactionalDatabaseClient; + extern template class TransactionalDatabaseClient>; +} + +#endif diff --git a/icetray/unittests/testIceTray.cpp b/icetray/unittests/testIceTray.cpp index b704864..4a78d03 100644 --- a/icetray/unittests/testIceTray.cpp +++ b/icetray/unittests/testIceTray.cpp @@ -1,10 +1,15 @@ #define BOOST_TEST_MODULE TestIceTray #include +#include "mockPool.h" +#include "subdir/some.sql.h" #include "testIceTrayService.h" +#include "transactionalDatabaseClient.h" +#include #include #include #include +#include #include #include #include @@ -12,7 +17,9 @@ #include #include #include +#include #include +// IWYU pragma: no_include "resourcePool.impl.h" class Service : public IceTray::DryIce, DB::PluginMock { public: @@ -73,3 +80,30 @@ BOOST_AUTO_TEST_CASE(sqlModify) BOOST_REQUIRE(db); BOOST_REQUIRE(TestIceTray::sql::testIceTrayServiceTestSql.modify(db.get())); } + +struct TxMockPool : public IceTray::MockPool { + TxMockPool() : MockPool {"icetraydb", std::string {}, Ice::createProperties()} { } +}; + +BOOST_AUTO_TEST_CASE(transactional) +{ + TxMockPool pool; + IceTray::TransactionalDatabaseClient tdbc {pool.get()}; + tdbc.fetch(TestIceTray::sql::subdir::some); + tdbc.modify(TestIceTray::sql::testIceTrayServiceTestSql, 1, 2); +} + +BOOST_AUTO_TEST_CASE(transactional_rollback) +{ + class OnlyThis : public std::exception { + }; + BOOST_CHECK_THROW( + { + TxMockPool pool; + IceTray::TransactionalDatabaseClient tdbc {pool.get()}; + tdbc.fetch(TestIceTray::sql::subdir::some); + tdbc.modify(TestIceTray::sql::testIceTrayServiceTestSql, 1, 2); + throw OnlyThis {}; + }, + OnlyThis); +} diff --git a/icetray/unittests/testIceTrayServiceI.cpp b/icetray/unittests/testIceTrayServiceI.cpp index 44ef966..7be1599 100644 --- a/icetray/unittests/testIceTrayServiceI.cpp +++ b/icetray/unittests/testIceTrayServiceI.cpp @@ -2,6 +2,7 @@ #include "basicDataClient.h" #include "icecube.h" #include "testIceTrayService.h" +#include "transactionalDatabaseClient.h" #include #include #include @@ -93,7 +94,7 @@ namespace TestIceTray { Ice::Int TestIceTrayServiceI::method3(const Ice::Current &) { - return static_cast(modify(sql::testIceTrayServiceTestSqlUpdate, 5)); + return static_cast(transactional().modify(sql::testIceTrayServiceTestSqlUpdate, 5)); } void -- cgit v1.2.3