From ae93785a573cb1646760c1f3e9936b19e41c079b Mon Sep 17 00:00:00 2001 From: Teemu Ollakka Date: Thu, 31 May 2018 16:55:57 +0300 Subject: [PATCH] Allow read-only access to transaction context through client context to enforce use of client context interface for manipulating transaction context state. --- include/trrep/client_context.hpp | 23 +- include/trrep/server_context.hpp | 1 - include/trrep/transaction_context.hpp | 4 +- src/client_context.cpp | 4 +- src/client_context_test.cpp | 12 +- src/dbms_simulator.cpp | 52 ++-- src/mock_client_context.cpp | 23 +- src/mock_client_context.hpp | 8 +- src/mock_utils.cpp | 9 +- src/mock_utils.hpp | 5 +- src/server_context.cpp | 34 +-- src/server_context_test.cpp | 48 ++-- src/transaction_context.cpp | 16 +- src/transaction_context_test.cpp | 328 +++++++++++--------------- 14 files changed, 267 insertions(+), 300 deletions(-) diff --git a/include/trrep/client_context.hpp b/include/trrep/client_context.hpp index ad02915..6328349 100644 --- a/include/trrep/client_context.hpp +++ b/include/trrep/client_context.hpp @@ -189,6 +189,11 @@ namespace trrep */ virtual void after_statement(); + int start_transaction() + { + assert(state_ == s_exec); + return transaction_.start_transaction(); + } int start_transaction(const trrep::transaction_id& id) { assert(state_ == s_exec); @@ -253,6 +258,12 @@ namespace trrep assert(state_ == s_exec); return transaction_.after_rollback(); } + + int bf_abort(trrep::unique_lock& lock, + wsrep_seqno_t bf_seqno) + { + return transaction_.bf_abort(lock, bf_seqno); + } /*! * Get reference to the client mutex. * @@ -294,7 +305,7 @@ namespace trrep */ enum mode mode() const { return mode_; } - trrep::transaction_context& transaction() + const trrep::transaction_context& transaction() const { return transaction_; } @@ -343,7 +354,6 @@ namespace trrep * Friend declarations */ friend int server_context::on_apply(client_context&, - trrep::transaction_context&, const trrep::data&); friend class client_context_switch; friend class client_applier_mode; @@ -387,8 +397,7 @@ namespace trrep * * \return Zero on success, non-zero on applying failure. */ - virtual int apply(trrep::transaction_context& transaction, - const trrep::data& data) = 0; + virtual int apply(const trrep::data& data) = 0; /*! * Virtual method which will be called @@ -397,7 +406,7 @@ namespace trrep * * \return Zero on success, non-zero on failure. */ - virtual int commit(trrep::transaction_context&) = 0; + virtual int commit() = 0; /*! * Rollback the transaction. @@ -406,7 +415,7 @@ namespace trrep * * \return Zero on success, no-zero on failure. */ - virtual int rollback(trrep::transaction_context&) = 0; + virtual int rollback() = 0; /*! * Notify a implementation that the client is about @@ -482,7 +491,9 @@ namespace trrep client_id id_; enum mode mode_; enum state state_; + protected: trrep::transaction_context transaction_; + private: /*! * \todo This boolean should be converted to better read isolation * semantics. diff --git a/include/trrep/server_context.hpp b/include/trrep/server_context.hpp index e06b013..e6de1c7 100644 --- a/include/trrep/server_context.hpp +++ b/include/trrep/server_context.hpp @@ -333,7 +333,6 @@ namespace trrep * \return Zero on success, non-zero on failure. */ int on_apply(trrep::client_context& client_context, - trrep::transaction_context& transaction_context, const trrep::data& data); /*! diff --git a/include/trrep/transaction_context.hpp b/include/trrep/transaction_context.hpp index 41acfd9..48dc7a5 100644 --- a/include/trrep/transaction_context.hpp +++ b/include/trrep/transaction_context.hpp @@ -73,7 +73,7 @@ namespace trrep // Return true if the certification of the last // fragment succeeded - bool certified() { return certified_; } + bool certified() const { return certified_; } wsrep_seqno_t seqno() const { @@ -130,7 +130,7 @@ namespace trrep int after_statement(); bool bf_abort(trrep::unique_lock& lock, - const transaction_context& txc); + wsrep_seqno_t bf_seqno); uint32_t flags() const { diff --git a/src/client_context.cpp b/src/client_context.cpp index c626967..af8ccc2 100644 --- a/src/client_context.cpp +++ b/src/client_context.cpp @@ -48,7 +48,7 @@ void trrep::client_context::after_command() { override_error(trrep::e_deadlock_error); lock.unlock(); - rollback(transaction_); + rollback(); transaction_.after_statement(); lock.lock(); assert(transaction_.state() == trrep::transaction_context::s_aborted); @@ -77,7 +77,7 @@ int trrep::client_context::before_statement() { override_error(trrep::e_deadlock_error); lock.unlock(); - rollback(transaction_); + rollback(); lock.lock(); return 1; } diff --git a/src/client_context_test.cpp b/src/client_context_test.cpp index 5a5dab1..d4ed849 100644 --- a/src/client_context_test.cpp +++ b/src/client_context_test.cpp @@ -16,14 +16,14 @@ BOOST_AUTO_TEST_CASE(client_context_test_error_codes) trrep::client_id(1), trrep::client_context::m_applier, false); + const trrep::transaction_context& txc(cc.transaction()); + cc.before_command(); + cc.before_statement(); - trrep::transaction_context& tc(cc.transaction()); - BOOST_REQUIRE(tc.active() == false); - tc.start_transaction(1); - trrep_mock::bf_abort_unordered(cc, tc); + BOOST_REQUIRE(txc.active() == false); + cc.start_transaction(1); + trrep_mock::bf_abort_unordered(cc); - BOOST_REQUIRE(cc.before_command()); - BOOST_REQUIRE(cc.before_statement()); cc.after_statement(); cc.after_command(); } diff --git a/src/dbms_simulator.cpp b/src/dbms_simulator.cpp index a0339ef..46639b0 100644 --- a/src/dbms_simulator.cpp +++ b/src/dbms_simulator.cpp @@ -70,41 +70,41 @@ public: public: transaction(dbms_storage_engine& se) : se_(se) - , txc_() + , cc_() { } - bool active() const { return txc_ != nullptr; } + bool active() const { return cc_ != nullptr; } - void start(trrep::transaction_context* txc) + void start(trrep::client_context* cc) { trrep::unique_lock lock(se_.mutex_); - if (se_.transactions_.insert(txc).second == false) + if (se_.transactions_.insert(cc).second == false) { ::abort(); } - txc_ = txc; + cc_ = cc; } void commit() { - if (txc_) + if (cc_) { trrep::unique_lock lock(se_.mutex_); - se_.transactions_.erase(txc_); + se_.transactions_.erase(cc_); } - txc_ = nullptr; + cc_ = nullptr; } void abort() { - if (txc_) + if (cc_) { trrep::unique_lock lock(se_.mutex_); - se_.transactions_.erase(txc_); + se_.transactions_.erase(cc_); } - txc_ = nullptr; + cc_ = nullptr; } ~transaction() @@ -117,7 +117,7 @@ public: private: dbms_storage_engine& se_; - trrep::transaction_context* txc_; + trrep::client_context* cc_; }; void bf_abort_some(const trrep::transaction_context& txc) @@ -131,7 +131,7 @@ public: trrep::unique_lock victim_txc_lock( victim_txc->mutex()); lock.unlock(); - if (victim_txc->bf_abort(victim_txc_lock, txc)) + if (victim_txc->bf_abort(victim_txc_lock, txc.seqno())) { trrep::log() << "BF aborted " << victim_txc->id().get(); ++bf_aborts_; @@ -146,7 +146,7 @@ public: } private: trrep::default_mutex mutex_; - std::unordered_set transactions_; + std::unordered_set transactions_; size_t alg_freq_; std::atomic bf_aborts_; }; @@ -337,28 +337,28 @@ public: } private: bool do_2pc() const override { return false; } - int apply(trrep::transaction_context& txc, const trrep::data& data) override + int apply(const trrep::data& data) override { - return server_.apply_to_storage_engine(txc, data); + return server_.apply_to_storage_engine(transaction(), data); } - int commit(trrep::transaction_context& transaction_context) override + int commit() override { assert(mode() == trrep::client_context::m_applier); int ret(0); - ret = transaction_context.before_commit(); + ret = before_commit(); se_trx_.commit(); - ret = ret || transaction_context.ordered_commit(); - ret = ret || transaction_context.after_commit(); + ret = ret || ordered_commit(); + ret = ret || after_commit(); return ret; } - int rollback(trrep::transaction_context& transaction_context) override + int rollback() override { - trrep::log() << "rollback: " << transaction_context.id().get() + trrep::log() << "rollback: " << transaction().id().get() << "state: " - << trrep::to_string(transaction_context.state()); - transaction_context.before_rollback(); + << trrep::to_string(transaction().state()); + before_rollback(); se_trx_.abort(); - transaction_context.after_rollback(); + after_rollback(); return 0; } @@ -404,7 +404,7 @@ private: { err = start_transaction(server_.next_transaction_id()); assert(err == 0); - se_trx_.start(&transaction()); + se_trx_.start(this); return err; }); err = err || current_error(); diff --git a/src/mock_client_context.cpp b/src/mock_client_context.cpp index 28a1b58..d2b9f64 100644 --- a/src/mock_client_context.cpp +++ b/src/mock_client_context.cpp @@ -7,48 +7,45 @@ int trrep::mock_client_context::apply( - trrep::transaction_context& transaction_context __attribute__((unused)), const trrep::data& data __attribute__((unused))) { - assert(transaction_context.state() == trrep::transaction_context::s_executing); + assert(transaction_.state() == trrep::transaction_context::s_executing); return (fail_next_applying_ ? 1 : 0); } -int trrep::mock_client_context::commit( - trrep::transaction_context& transaction_context) +int trrep::mock_client_context::commit() { int ret(0); if (do_2pc()) { - if (transaction_context.before_prepare()) + if (transaction_.before_prepare()) { ret = 1; } - else if (transaction_context.after_prepare()) + else if (transaction_.after_prepare()) { ret = 1; } } if (ret == 0 && - (transaction_context.before_commit() || - transaction_context.ordered_commit() || - transaction_context.after_commit())) + (transaction_.before_commit() || + transaction_.ordered_commit() || + transaction_.after_commit())) { ret = 1; } return ret; } -int trrep::mock_client_context::rollback( - trrep::transaction_context& transaction_context) +int trrep::mock_client_context::rollback() { int ret(0); - if (transaction_context.before_rollback()) + if (transaction_.before_rollback()) { ret = 1; } - else if (transaction_context.after_rollback()) + else if (transaction_.after_rollback()) { ret = 1; } diff --git a/src/mock_client_context.hpp b/src/mock_client_context.hpp index 9472268..69aa567 100644 --- a/src/mock_client_context.hpp +++ b/src/mock_client_context.hpp @@ -29,12 +29,12 @@ namespace trrep { if (transaction().active()) { - (void)rollback(transaction()); + (void)rollback(); } } - int apply(trrep::transaction_context&, const trrep::data&); - int commit(trrep::transaction_context&); - int rollback(trrep::transaction_context&); + int apply(const trrep::data&); + int commit(); + int rollback(); bool do_2pc() const { return do_2pc_; } void will_replay(trrep::transaction_context&) TRREP_OVERRIDE { } int replay(trrep::transaction_context& tc) TRREP_OVERRIDE diff --git a/src/mock_utils.cpp b/src/mock_utils.cpp index 096d266..d5571b4 100644 --- a/src/mock_utils.cpp +++ b/src/mock_utils.cpp @@ -8,11 +8,11 @@ // Simple BF abort method to BF abort unordered transasctions -void trrep_mock::bf_abort_unordered(trrep::client_context& cc, - trrep::transaction_context& tc) +void trrep_mock::bf_abort_unordered(trrep::client_context& cc) { trrep::unique_lock lock(cc.mutex()); - tc.state(lock, trrep::transaction_context::s_must_abort); + assert(cc.transaction().seqno() <= 0); + cc.bf_abort(lock, 1); } // BF abort method to abort transactions via provider @@ -25,7 +25,7 @@ void trrep_mock::bf_abort_provider(trrep::mock_server_context& sc, (void)victim_seqno; } -trrep::transaction_context& trrep_mock::start_applying_transaction( +void trrep_mock::start_applying_transaction( trrep::client_context& cc, const trrep::transaction_id& id, wsrep_seqno_t seqno, @@ -42,5 +42,4 @@ trrep::transaction_context& trrep_mock::start_applying_transaction( { throw trrep::runtime_error("failed to start applying transaction"); } - return cc.transaction(); } diff --git a/src/mock_utils.hpp b/src/mock_utils.hpp index b6e66eb..1e214af 100644 --- a/src/mock_utils.hpp +++ b/src/mock_utils.hpp @@ -20,15 +20,14 @@ namespace trrep_mock { // Simple BF abort method to BF abort unordered transasctions - void bf_abort_unordered(trrep::client_context& cc, - trrep::transaction_context& tc); + void bf_abort_unordered(trrep::client_context& cc); // BF abort method to abort transactions via provider void bf_abort_provider(trrep::mock_server_context& sc, const trrep::transaction_context& tc, wsrep_seqno_t bf_seqno); - trrep::transaction_context& start_applying_transaction( + void start_applying_transaction( trrep::client_context& cc, const trrep::transaction_id& id, wsrep_seqno_t seqno, diff --git a/src/server_context.cpp b/src/server_context.cpp index 97fa9b8..81aa242 100644 --- a/src/server_context.cpp +++ b/src/server_context.cpp @@ -122,7 +122,7 @@ namespace } if (ret == WSREP_CB_SUCCESS && client_context->server_context().on_apply( - *client_context, client_context->transaction(), data)) + *client_context, data)) { ret = WSREP_CB_FAILURE; } @@ -296,29 +296,35 @@ void trrep::server_context::on_sync() int trrep::server_context::on_apply( trrep::client_context& client_context, - trrep::transaction_context& transaction_context, const trrep::data& data) { int ret(0); - if (starts_transaction(transaction_context.flags()) && - commits_transaction(transaction_context.flags())) + const trrep::transaction_context& txc(client_context.transaction()); + if (starts_transaction(txc.flags()) && + commits_transaction(txc.flags())) { - if (transaction_context.state() != trrep::transaction_context::s_replaying) + if (txc.state() != trrep::transaction_context::s_replaying) { - assert(transaction_context.active() == false); - transaction_context.start_transaction(); + client_context.before_command(); + client_context.before_statement(); + assert(txc.active() == false); + client_context.start_transaction(); } - if (client_context.apply(transaction_context, data)) + if (client_context.apply(data)) { ret = 1; } - else if (client_context.commit(transaction_context)) + else if (client_context.commit()) { ret = 1; } + if (txc.state() != trrep::transaction_context::s_replaying) + { + client_context.after_statement(); + client_context.after_command(); + } assert(ret || - transaction_context.state() == - trrep::transaction_context::s_committed); + txc.state() == trrep::transaction_context::s_committed); } else { @@ -328,11 +334,11 @@ int trrep::server_context::on_apply( if (ret) { - client_context.rollback(transaction_context); + client_context.rollback(); } - transaction_context.after_statement(); - assert(transaction_context.active() == false); + client_context.after_statement(); + assert(txc.active() == false); return ret; } diff --git a/src/server_context_test.cpp b/src/server_context_test.cpp index a29ae9b..410904d 100644 --- a/src/server_context_test.cpp +++ b/src/server_context_test.cpp @@ -16,13 +16,13 @@ BOOST_AUTO_TEST_CASE(server_context_applying_1pc) trrep::client_id(1), trrep::client_context::m_applier, false); - trrep::transaction_context& tc( - trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); + trrep_mock::start_applying_transaction( + cc, 1, 1, + WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END); char buf[1] = { 1 }; - BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 0); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); + BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 0); + const trrep::transaction_context& txc(cc.transaction()); + BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_committed); } // Test on_apply() method for 2pc @@ -34,13 +34,13 @@ BOOST_AUTO_TEST_CASE(server_context_applying_2pc) trrep::client_id(1), trrep::client_context::m_applier, true); - trrep::transaction_context& tc( - trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); + trrep_mock::start_applying_transaction( + cc, 1, 1, + WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END); char buf[1] = { 1 }; - BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 0); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); + BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 0); + const trrep::transaction_context& txc(cc.transaction()); + BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_committed); } // Test on_apply() method for 1pc transaction which @@ -54,14 +54,14 @@ BOOST_AUTO_TEST_CASE(server_context_applying_1pc_rollback) trrep::client_context::m_applier, false); cc.fail_next_applying(true); - trrep::transaction_context& tc( - trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); + trrep_mock::start_applying_transaction( + cc, 1, 1, + WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END); char buf[1] = { 1 }; - BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 1); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); + BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 1); + const trrep::transaction_context& txc(cc.transaction()); + BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_aborted); } // Test on_apply() method for 2pc transaction which @@ -75,11 +75,11 @@ BOOST_AUTO_TEST_CASE(server_context_applying_2pc_rollback) trrep::client_context::m_applier, true); cc.fail_next_applying(true); - trrep::transaction_context& tc( - trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); + trrep_mock::start_applying_transaction( + cc, 1, 1, + WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END); char buf[1] = { 1 }; - BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 1); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); + BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 1); + const trrep::transaction_context& txc(cc.transaction()); + BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_aborted); } diff --git a/src/transaction_context.cpp b/src/transaction_context.cpp index 975cf93..1be0348 100644 --- a/src/transaction_context.cpp +++ b/src/transaction_context.cpp @@ -431,7 +431,7 @@ int trrep::transaction_context::after_statement() case s_cert_failed: client_context_.override_error(trrep::e_deadlock_error); lock.unlock(); - ret = client_context_.rollback(*this); + ret = client_context_.rollback(); lock.lock(); if (state() != s_must_replay) { @@ -480,7 +480,7 @@ int trrep::transaction_context::after_statement() bool trrep::transaction_context::bf_abort( trrep::unique_lock& lock TRREP_UNUSED, - const trrep::transaction_context& txc) + wsrep_seqno_t bf_seqno) { bool ret(false); assert(lock.owns_lock()); @@ -490,10 +490,10 @@ bool trrep::transaction_context::bf_abort( { trrep::log() << "Transaction not active, skipping bf abort"; } - else if (ordered() && seqno() < txc.seqno()) + else if (ordered() && seqno() < bf_seqno) { trrep::log() << "Not allowed to BF abort transaction ordered before " - << "aborter: " << seqno() << " < " << txc.seqno(); + << "aborter: " << seqno() << " < " << bf_seqno; } else { @@ -506,11 +506,11 @@ bool trrep::transaction_context::bf_abort( { wsrep_seqno_t victim_seqno(WSREP_SEQNO_UNDEFINED); wsrep_status_t status(client_context_.provider().bf_abort( - txc.seqno(), id_.get(), &victim_seqno)); + bf_seqno, id_.get(), &victim_seqno)); switch (status) { case WSREP_OK: - trrep::log() << "Seqno " << txc.seqno() + trrep::log() << "Seqno " << bf_seqno << " succesfully BF aborted " << id_.get() << " victim_seqno " << victim_seqno; bf_abort_state_ = state(); @@ -518,7 +518,7 @@ bool trrep::transaction_context::bf_abort( ret = true; break; default: - trrep::log() << "Seqno " << txc.seqno() + trrep::log() << "Seqno " << bf_seqno << " failed to BF abort " << id_.get() << " with status " << status << " victim_seqno " << victim_seqno; @@ -588,6 +588,7 @@ void trrep::transaction_context::state( } } +#if 0 int trrep::transaction_context::certify_fragment( trrep::unique_lock& lock) { @@ -658,6 +659,7 @@ int trrep::transaction_context::certify_fragment( return ret; } +#endif int trrep::transaction_context::certify_commit( trrep::unique_lock& lock) diff --git a/src/transaction_context_test.cpp b/src/transaction_context_test.cpp index 0aaf905..1bc61e3 100644 --- a/src/transaction_context_test.cpp +++ b/src/transaction_context_test.cpp @@ -12,41 +12,82 @@ #include +namespace +{ + struct replicating_client_fixture + { + replicating_client_fixture() + : sc("s1", "s1", trrep::server_context::rm_async) + , cc(sc, trrep::client_id(1), + trrep::client_context::m_replicating) + , tc(cc.transaction()) + { + BOOST_REQUIRE(cc.before_command() == 0); + BOOST_REQUIRE(cc.before_statement() == 0); + // Verify initial state + BOOST_REQUIRE(tc.active() == false); + BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); + } + trrep::mock_server_context sc; + trrep::mock_client_context cc; + const trrep::transaction_context& tc; + }; + + struct applying_client_fixture + { + applying_client_fixture() + : sc("s1", "s1", + trrep::server_context::rm_async) + , cc(sc, + trrep::client_id(1), + trrep::client_context::m_applier) + , tc(cc.transaction()) + { + BOOST_REQUIRE(cc.before_command() == 0); + BOOST_REQUIRE(cc.before_statement() == 0); + trrep_mock::start_applying_transaction( + cc, 1, 1, + WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END); + BOOST_REQUIRE(tc.active() == false); + BOOST_REQUIRE(cc.start_transaction() == 0); + BOOST_REQUIRE(tc.active() == true); + BOOST_REQUIRE(tc.certified() == true); + BOOST_REQUIRE(tc.ordered() == true); + } + trrep::mock_server_context sc; + trrep::mock_client_context cc; + const trrep::transaction_context& tc; + }; + +} + // // Test a succesful 1PC transaction lifecycle // -BOOST_AUTO_TEST_CASE(transaction_context_1pc) +BOOST_FIXTURE_TEST_CASE(transaction_context_1pc, replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc,trrep::client_id(1), - trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); // Run before commit - BOOST_REQUIRE(tc.before_commit() == 0); + BOOST_REQUIRE(cc.before_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); // Run ordered commit - BOOST_REQUIRE(tc.ordered_commit() == 0); + BOOST_REQUIRE(cc.ordered_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_ordered_commit); // Run after commit - BOOST_REQUIRE(tc.after_commit() == 0); + BOOST_REQUIRE(cc.after_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -56,45 +97,36 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc) // // Test a succesful 2PC transaction lifecycle // -BOOST_AUTO_TEST_CASE(transaction_context_2pc) +BOOST_FIXTURE_TEST_CASE(transaction_context_2pc, replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); // Run before prepare - BOOST_REQUIRE(tc.before_prepare() == 0); + BOOST_REQUIRE(cc.before_prepare() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing); // Run after prepare - BOOST_REQUIRE(tc.after_prepare() == 0); + BOOST_REQUIRE(cc.after_prepare() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); // Run before commit - BOOST_REQUIRE(tc.before_commit() == 0); + BOOST_REQUIRE(cc.before_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); // Run ordered commit - BOOST_REQUIRE(tc.ordered_commit() == 0); + BOOST_REQUIRE(cc.ordered_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_ordered_commit); // Run after commit - BOOST_REQUIRE(tc.after_commit() == 0); + BOOST_REQUIRE(cc.after_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -104,34 +136,24 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc) // // Test a voluntary rollback // -BOOST_AUTO_TEST_CASE(transaction_context_rollback) +BOOST_FIXTURE_TEST_CASE(transaction_context_rollback, replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc,trrep::client_id(1), - trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); // Run before commit - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); // Run after commit - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -141,39 +163,31 @@ BOOST_AUTO_TEST_CASE(transaction_context_rollback) // // Test a 1PC transaction which gets BF aborted before before_commit // -BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_before_before_commit) +BOOST_FIXTURE_TEST_CASE(transaction_context_1pc_bf_before_before_commit, + replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - trrep_mock::bf_abort_unordered(cc, tc); + trrep_mock::bf_abort_unordered(cc); // Run before commit - BOOST_REQUIRE(tc.before_commit()); + BOOST_REQUIRE(cc.before_commit()); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_abort); BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.ordered() == false); // Rollback sequence - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -183,39 +197,31 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_before_before_commit) // // Test a 2PC transaction which gets BF aborted before before_prepare // -BOOST_AUTO_TEST_CASE(transaction_context_2pc_bf_before_before_prepare) +BOOST_FIXTURE_TEST_CASE(transaction_context_2pc_bf_before_before_prepare, + replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - trrep_mock::bf_abort_unordered(cc, tc); + trrep_mock::bf_abort_unordered(cc); // Run before commit - BOOST_REQUIRE(tc.before_prepare()); + BOOST_REQUIRE(cc.before_prepare()); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_abort); BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.ordered() == false); // Rollback sequence - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -225,43 +231,35 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc_bf_before_before_prepare) // // Test a 2PC transaction which gets BF aborted before before_prepare // -BOOST_AUTO_TEST_CASE(transaction_context_2pc_bf_before_after_prepare) +BOOST_FIXTURE_TEST_CASE(transaction_context_2pc_bf_before_after_prepare, + replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); // Run before prepare - BOOST_REQUIRE(tc.before_prepare() == 0); + BOOST_REQUIRE(cc.before_prepare() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing); - trrep_mock::bf_abort_unordered(cc, tc); + trrep_mock::bf_abort_unordered(cc); // Run before commit - BOOST_REQUIRE(tc.after_prepare()); + BOOST_REQUIRE(cc.after_prepare()); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_abort); BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.ordered() == false); // Rollback sequence - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -272,19 +270,12 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc_bf_before_after_prepare) // Test a 1PC transaction which gets BF aborted during before_commit via // provider before the write set was ordered and certified. // -BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_uncertified) +BOOST_FIXTURE_TEST_CASE( + transaction_context_1pc_bf_during_before_commit_uncertified, + replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); @@ -292,19 +283,19 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_uncertified trrep_mock::bf_abort_provider(sc, tc, WSREP_SEQNO_UNDEFINED); // Run before commit - BOOST_REQUIRE(tc.before_commit()); + BOOST_REQUIRE(cc.before_commit()); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_cert_failed); BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.ordered() == false); // Rollback sequence - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -314,26 +305,19 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_uncertified // // Test a transaction which gets BF aborted before after_statement. // -BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_after_statement) +BOOST_FIXTURE_TEST_CASE( + transaction_context_1pc_bf_during_before_after_statement, + replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - trrep_mock::bf_abort_unordered(cc, tc); + trrep_mock::bf_abort_unordered(cc); - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); @@ -344,19 +328,12 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_after_statement) // Test a 1PC transaction which gets BF aborted during before_commit via // provider after the write set was ordered and certified. // -BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_certified) +BOOST_FIXTURE_TEST_CASE( + transaction_context_1pc_bf_during_before_commit_certified, + replicating_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_replicating); - trrep::transaction_context& tc(cc.transaction()); - - // Verify initial state - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); - // Start a new transaction with ID 1 - tc.start_transaction(1); + cc.start_transaction(1); BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); @@ -364,49 +341,35 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_certified) trrep_mock::bf_abort_provider(sc, tc, 1); // Run before commit - BOOST_REQUIRE(tc.before_commit()); + BOOST_REQUIRE(cc.before_commit()); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_replay); BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.ordered() == true); // Rollback sequence - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_replay); - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_replay); // Cleanup after statement - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(cc.current_error() == trrep::e_success); } -BOOST_AUTO_TEST_CASE(transaction_context_1pc_applying) +BOOST_FIXTURE_TEST_CASE(transaction_context_1pc_applying, + applying_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, - trrep::client_id(1), - trrep::client_context::m_applier); - trrep::transaction_context& tc(trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); - - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.start_transaction() == 0); - BOOST_REQUIRE(tc.active() == true); - BOOST_REQUIRE(tc.certified() == true); - BOOST_REQUIRE(tc.ordered() == true); - - BOOST_REQUIRE(tc.before_commit() == 0); + BOOST_REQUIRE(cc.before_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); - BOOST_REQUIRE(tc.ordered_commit() == 0); + BOOST_REQUIRE(cc.ordered_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_ordered_commit); - BOOST_REQUIRE(tc.after_commit() == 0); + BOOST_REQUIRE(cc.after_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(cc.current_error() == trrep::e_success); @@ -419,54 +382,45 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc_applying) trrep::mock_client_context cc(sc, trrep::client_id(1), trrep::client_context::m_applier); - trrep::transaction_context& tc(trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); + + BOOST_REQUIRE(cc.before_command() == 0); + BOOST_REQUIRE(cc.before_statement() == 0); + + trrep_mock::start_applying_transaction( + cc, 1, 1, + WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END); + const trrep::transaction_context& tc(cc.transaction()); BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.start_transaction() == 0); + BOOST_REQUIRE(cc.start_transaction() == 0); BOOST_REQUIRE(tc.active() == true); BOOST_REQUIRE(tc.certified() == true); BOOST_REQUIRE(tc.ordered() == true); - BOOST_REQUIRE(tc.before_prepare() == 0); + BOOST_REQUIRE(cc.before_prepare() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing); - BOOST_REQUIRE(tc.after_prepare() == 0); + BOOST_REQUIRE(cc.after_prepare() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); - BOOST_REQUIRE(tc.before_commit() == 0); + BOOST_REQUIRE(cc.before_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); - BOOST_REQUIRE(tc.ordered_commit() == 0); + BOOST_REQUIRE(cc.ordered_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_ordered_commit); - BOOST_REQUIRE(tc.after_commit() == 0); + BOOST_REQUIRE(cc.after_commit() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(cc.current_error() == trrep::e_success); } -BOOST_AUTO_TEST_CASE(transaction_context_applying_rollback) +BOOST_FIXTURE_TEST_CASE(transaction_context_applying_rollback, + applying_client_fixture) { - trrep::mock_server_context sc("s1", "s1", - trrep::server_context::rm_sync); - trrep::mock_client_context cc(sc, - trrep::client_id(1), - trrep::client_context::m_applier); - trrep::transaction_context& tc(trrep_mock::start_applying_transaction( - cc, 1, 1, - WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); - - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.start_transaction() == 0); - BOOST_REQUIRE(tc.active() == true); - BOOST_REQUIRE(tc.certified() == true); - BOOST_REQUIRE(tc.ordered() == true); - - BOOST_REQUIRE(tc.before_rollback() == 0); + BOOST_REQUIRE(cc.before_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); - BOOST_REQUIRE(tc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); - BOOST_REQUIRE(tc.after_statement() == 0); + cc.after_statement(); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(cc.current_error() == trrep::e_success);