1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-06-16 02:01:44 +03:00

Allow read-only access to transaction context through

client context to enforce use of client context interface
for manipulating transaction context state.
This commit is contained in:
Teemu Ollakka
2018-05-31 16:55:57 +03:00
parent 2f46758064
commit ae93785a57
14 changed files with 267 additions and 300 deletions

View File

@ -189,6 +189,11 @@ namespace trrep
*/ */
virtual void after_statement(); virtual void after_statement();
int start_transaction()
{
assert(state_ == s_exec);
return transaction_.start_transaction();
}
int start_transaction(const trrep::transaction_id& id) int start_transaction(const trrep::transaction_id& id)
{ {
assert(state_ == s_exec); assert(state_ == s_exec);
@ -253,6 +258,12 @@ namespace trrep
assert(state_ == s_exec); assert(state_ == s_exec);
return transaction_.after_rollback(); return transaction_.after_rollback();
} }
int bf_abort(trrep::unique_lock<trrep::mutex>& lock,
wsrep_seqno_t bf_seqno)
{
return transaction_.bf_abort(lock, bf_seqno);
}
/*! /*!
* Get reference to the client mutex. * Get reference to the client mutex.
* *
@ -294,7 +305,7 @@ namespace trrep
*/ */
enum mode mode() const { return mode_; } enum mode mode() const { return mode_; }
trrep::transaction_context& transaction() const trrep::transaction_context& transaction() const
{ {
return transaction_; return transaction_;
} }
@ -343,7 +354,6 @@ namespace trrep
* Friend declarations * Friend declarations
*/ */
friend int server_context::on_apply(client_context&, friend int server_context::on_apply(client_context&,
trrep::transaction_context&,
const trrep::data&); const trrep::data&);
friend class client_context_switch; friend class client_context_switch;
friend class client_applier_mode; friend class client_applier_mode;
@ -387,8 +397,7 @@ namespace trrep
* *
* \return Zero on success, non-zero on applying failure. * \return Zero on success, non-zero on applying failure.
*/ */
virtual int apply(trrep::transaction_context& transaction, virtual int apply(const trrep::data& data) = 0;
const trrep::data& data) = 0;
/*! /*!
* Virtual method which will be called * Virtual method which will be called
@ -397,7 +406,7 @@ namespace trrep
* *
* \return Zero on success, non-zero on failure. * \return Zero on success, non-zero on failure.
*/ */
virtual int commit(trrep::transaction_context&) = 0; virtual int commit() = 0;
/*! /*!
* Rollback the transaction. * Rollback the transaction.
@ -406,7 +415,7 @@ namespace trrep
* *
* \return Zero on success, no-zero on failure. * \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 * Notify a implementation that the client is about
@ -482,7 +491,9 @@ namespace trrep
client_id id_; client_id id_;
enum mode mode_; enum mode mode_;
enum state state_; enum state state_;
protected:
trrep::transaction_context transaction_; trrep::transaction_context transaction_;
private:
/*! /*!
* \todo This boolean should be converted to better read isolation * \todo This boolean should be converted to better read isolation
* semantics. * semantics.

View File

@ -333,7 +333,6 @@ namespace trrep
* \return Zero on success, non-zero on failure. * \return Zero on success, non-zero on failure.
*/ */
int on_apply(trrep::client_context& client_context, int on_apply(trrep::client_context& client_context,
trrep::transaction_context& transaction_context,
const trrep::data& data); const trrep::data& data);
/*! /*!

View File

@ -73,7 +73,7 @@ namespace trrep
// Return true if the certification of the last // Return true if the certification of the last
// fragment succeeded // fragment succeeded
bool certified() { return certified_; } bool certified() const { return certified_; }
wsrep_seqno_t seqno() const wsrep_seqno_t seqno() const
{ {
@ -130,7 +130,7 @@ namespace trrep
int after_statement(); int after_statement();
bool bf_abort(trrep::unique_lock<trrep::mutex>& lock, bool bf_abort(trrep::unique_lock<trrep::mutex>& lock,
const transaction_context& txc); wsrep_seqno_t bf_seqno);
uint32_t flags() const uint32_t flags() const
{ {

View File

@ -48,7 +48,7 @@ void trrep::client_context::after_command()
{ {
override_error(trrep::e_deadlock_error); override_error(trrep::e_deadlock_error);
lock.unlock(); lock.unlock();
rollback(transaction_); rollback();
transaction_.after_statement(); transaction_.after_statement();
lock.lock(); lock.lock();
assert(transaction_.state() == trrep::transaction_context::s_aborted); assert(transaction_.state() == trrep::transaction_context::s_aborted);
@ -77,7 +77,7 @@ int trrep::client_context::before_statement()
{ {
override_error(trrep::e_deadlock_error); override_error(trrep::e_deadlock_error);
lock.unlock(); lock.unlock();
rollback(transaction_); rollback();
lock.lock(); lock.lock();
return 1; return 1;
} }

View File

@ -16,14 +16,14 @@ BOOST_AUTO_TEST_CASE(client_context_test_error_codes)
trrep::client_id(1), trrep::client_id(1),
trrep::client_context::m_applier, trrep::client_context::m_applier,
false); false);
const trrep::transaction_context& txc(cc.transaction());
cc.before_command();
cc.before_statement();
trrep::transaction_context& tc(cc.transaction()); BOOST_REQUIRE(txc.active() == false);
BOOST_REQUIRE(tc.active() == false); cc.start_transaction(1);
tc.start_transaction(1); trrep_mock::bf_abort_unordered(cc);
trrep_mock::bf_abort_unordered(cc, tc);
BOOST_REQUIRE(cc.before_command());
BOOST_REQUIRE(cc.before_statement());
cc.after_statement(); cc.after_statement();
cc.after_command(); cc.after_command();
} }

View File

@ -70,41 +70,41 @@ public:
public: public:
transaction(dbms_storage_engine& se) transaction(dbms_storage_engine& se)
: se_(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<trrep::mutex> lock(se_.mutex_); trrep::unique_lock<trrep::mutex> lock(se_.mutex_);
if (se_.transactions_.insert(txc).second == false) if (se_.transactions_.insert(cc).second == false)
{ {
::abort(); ::abort();
} }
txc_ = txc; cc_ = cc;
} }
void commit() void commit()
{ {
if (txc_) if (cc_)
{ {
trrep::unique_lock<trrep::mutex> lock(se_.mutex_); trrep::unique_lock<trrep::mutex> lock(se_.mutex_);
se_.transactions_.erase(txc_); se_.transactions_.erase(cc_);
} }
txc_ = nullptr; cc_ = nullptr;
} }
void abort() void abort()
{ {
if (txc_) if (cc_)
{ {
trrep::unique_lock<trrep::mutex> lock(se_.mutex_); trrep::unique_lock<trrep::mutex> lock(se_.mutex_);
se_.transactions_.erase(txc_); se_.transactions_.erase(cc_);
} }
txc_ = nullptr; cc_ = nullptr;
} }
~transaction() ~transaction()
@ -117,7 +117,7 @@ public:
private: private:
dbms_storage_engine& se_; dbms_storage_engine& se_;
trrep::transaction_context* txc_; trrep::client_context* cc_;
}; };
void bf_abort_some(const trrep::transaction_context& txc) void bf_abort_some(const trrep::transaction_context& txc)
@ -131,7 +131,7 @@ public:
trrep::unique_lock<trrep::mutex> victim_txc_lock( trrep::unique_lock<trrep::mutex> victim_txc_lock(
victim_txc->mutex()); victim_txc->mutex());
lock.unlock(); 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(); trrep::log() << "BF aborted " << victim_txc->id().get();
++bf_aborts_; ++bf_aborts_;
@ -146,7 +146,7 @@ public:
} }
private: private:
trrep::default_mutex mutex_; trrep::default_mutex mutex_;
std::unordered_set<trrep::transaction_context*> transactions_; std::unordered_set<trrep::client_context*> transactions_;
size_t alg_freq_; size_t alg_freq_;
std::atomic<long long> bf_aborts_; std::atomic<long long> bf_aborts_;
}; };
@ -337,28 +337,28 @@ public:
} }
private: private:
bool do_2pc() const override { return false; } 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); assert(mode() == trrep::client_context::m_applier);
int ret(0); int ret(0);
ret = transaction_context.before_commit(); ret = before_commit();
se_trx_.commit(); se_trx_.commit();
ret = ret || transaction_context.ordered_commit(); ret = ret || ordered_commit();
ret = ret || transaction_context.after_commit(); ret = ret || after_commit();
return ret; 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: " << "state: "
<< trrep::to_string(transaction_context.state()); << trrep::to_string(transaction().state());
transaction_context.before_rollback(); before_rollback();
se_trx_.abort(); se_trx_.abort();
transaction_context.after_rollback(); after_rollback();
return 0; return 0;
} }
@ -404,7 +404,7 @@ private:
{ {
err = start_transaction(server_.next_transaction_id()); err = start_transaction(server_.next_transaction_id());
assert(err == 0); assert(err == 0);
se_trx_.start(&transaction()); se_trx_.start(this);
return err; return err;
}); });
err = err || current_error(); err = err || current_error();

View File

@ -7,48 +7,45 @@
int trrep::mock_client_context::apply( int trrep::mock_client_context::apply(
trrep::transaction_context& transaction_context __attribute__((unused)),
const trrep::data& data __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); return (fail_next_applying_ ? 1 : 0);
} }
int trrep::mock_client_context::commit( int trrep::mock_client_context::commit()
trrep::transaction_context& transaction_context)
{ {
int ret(0); int ret(0);
if (do_2pc()) if (do_2pc())
{ {
if (transaction_context.before_prepare()) if (transaction_.before_prepare())
{ {
ret = 1; ret = 1;
} }
else if (transaction_context.after_prepare()) else if (transaction_.after_prepare())
{ {
ret = 1; ret = 1;
} }
} }
if (ret == 0 && if (ret == 0 &&
(transaction_context.before_commit() || (transaction_.before_commit() ||
transaction_context.ordered_commit() || transaction_.ordered_commit() ||
transaction_context.after_commit())) transaction_.after_commit()))
{ {
ret = 1; ret = 1;
} }
return ret; return ret;
} }
int trrep::mock_client_context::rollback( int trrep::mock_client_context::rollback()
trrep::transaction_context& transaction_context)
{ {
int ret(0); int ret(0);
if (transaction_context.before_rollback()) if (transaction_.before_rollback())
{ {
ret = 1; ret = 1;
} }
else if (transaction_context.after_rollback()) else if (transaction_.after_rollback())
{ {
ret = 1; ret = 1;
} }

View File

@ -29,12 +29,12 @@ namespace trrep
{ {
if (transaction().active()) if (transaction().active())
{ {
(void)rollback(transaction()); (void)rollback();
} }
} }
int apply(trrep::transaction_context&, const trrep::data&); int apply(const trrep::data&);
int commit(trrep::transaction_context&); int commit();
int rollback(trrep::transaction_context&); int rollback();
bool do_2pc() const { return do_2pc_; } bool do_2pc() const { return do_2pc_; }
void will_replay(trrep::transaction_context&) TRREP_OVERRIDE { } void will_replay(trrep::transaction_context&) TRREP_OVERRIDE { }
int replay(trrep::transaction_context& tc) TRREP_OVERRIDE int replay(trrep::transaction_context& tc) TRREP_OVERRIDE

View File

@ -8,11 +8,11 @@
// Simple BF abort method to BF abort unordered transasctions // Simple BF abort method to BF abort unordered transasctions
void trrep_mock::bf_abort_unordered(trrep::client_context& cc, void trrep_mock::bf_abort_unordered(trrep::client_context& cc)
trrep::transaction_context& tc)
{ {
trrep::unique_lock<trrep::mutex> lock(cc.mutex()); trrep::unique_lock<trrep::mutex> 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 // 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; (void)victim_seqno;
} }
trrep::transaction_context& trrep_mock::start_applying_transaction( void trrep_mock::start_applying_transaction(
trrep::client_context& cc, trrep::client_context& cc,
const trrep::transaction_id& id, const trrep::transaction_id& id,
wsrep_seqno_t seqno, 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"); throw trrep::runtime_error("failed to start applying transaction");
} }
return cc.transaction();
} }

View File

@ -20,15 +20,14 @@ namespace trrep_mock
{ {
// Simple BF abort method to BF abort unordered transasctions // Simple BF abort method to BF abort unordered transasctions
void bf_abort_unordered(trrep::client_context& cc, void bf_abort_unordered(trrep::client_context& cc);
trrep::transaction_context& tc);
// BF abort method to abort transactions via provider // BF abort method to abort transactions via provider
void bf_abort_provider(trrep::mock_server_context& sc, void bf_abort_provider(trrep::mock_server_context& sc,
const trrep::transaction_context& tc, const trrep::transaction_context& tc,
wsrep_seqno_t bf_seqno); wsrep_seqno_t bf_seqno);
trrep::transaction_context& start_applying_transaction( void start_applying_transaction(
trrep::client_context& cc, trrep::client_context& cc,
const trrep::transaction_id& id, const trrep::transaction_id& id,
wsrep_seqno_t seqno, wsrep_seqno_t seqno,

View File

@ -122,7 +122,7 @@ namespace
} }
if (ret == WSREP_CB_SUCCESS && if (ret == WSREP_CB_SUCCESS &&
client_context->server_context().on_apply( client_context->server_context().on_apply(
*client_context, client_context->transaction(), data)) *client_context, data))
{ {
ret = WSREP_CB_FAILURE; ret = WSREP_CB_FAILURE;
} }
@ -296,29 +296,35 @@ void trrep::server_context::on_sync()
int trrep::server_context::on_apply( int trrep::server_context::on_apply(
trrep::client_context& client_context, trrep::client_context& client_context,
trrep::transaction_context& transaction_context,
const trrep::data& data) const trrep::data& data)
{ {
int ret(0); int ret(0);
if (starts_transaction(transaction_context.flags()) && const trrep::transaction_context& txc(client_context.transaction());
commits_transaction(transaction_context.flags())) 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); client_context.before_command();
transaction_context.start_transaction(); 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; ret = 1;
} }
else if (client_context.commit(transaction_context)) else if (client_context.commit())
{ {
ret = 1; ret = 1;
} }
if (txc.state() != trrep::transaction_context::s_replaying)
{
client_context.after_statement();
client_context.after_command();
}
assert(ret || assert(ret ||
transaction_context.state() == txc.state() == trrep::transaction_context::s_committed);
trrep::transaction_context::s_committed);
} }
else else
{ {
@ -328,11 +334,11 @@ int trrep::server_context::on_apply(
if (ret) if (ret)
{ {
client_context.rollback(transaction_context); client_context.rollback();
} }
transaction_context.after_statement(); client_context.after_statement();
assert(transaction_context.active() == false); assert(txc.active() == false);
return ret; return ret;
} }

View File

@ -16,13 +16,13 @@ BOOST_AUTO_TEST_CASE(server_context_applying_1pc)
trrep::client_id(1), trrep::client_id(1),
trrep::client_context::m_applier, trrep::client_context::m_applier,
false); false);
trrep::transaction_context& tc(
trrep_mock::start_applying_transaction( trrep_mock::start_applying_transaction(
cc, 1, 1, cc, 1, 1,
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END);
char buf[1] = { 1 }; char buf[1] = { 1 };
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 0); BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); const trrep::transaction_context& txc(cc.transaction());
BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_committed);
} }
// Test on_apply() method for 2pc // Test on_apply() method for 2pc
@ -34,13 +34,13 @@ BOOST_AUTO_TEST_CASE(server_context_applying_2pc)
trrep::client_id(1), trrep::client_id(1),
trrep::client_context::m_applier, trrep::client_context::m_applier,
true); true);
trrep::transaction_context& tc(
trrep_mock::start_applying_transaction( trrep_mock::start_applying_transaction(
cc, 1, 1, cc, 1, 1,
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END);
char buf[1] = { 1 }; char buf[1] = { 1 };
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 0); BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed); const trrep::transaction_context& txc(cc.transaction());
BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_committed);
} }
// Test on_apply() method for 1pc transaction which // 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, trrep::client_context::m_applier,
false); false);
cc.fail_next_applying(true); cc.fail_next_applying(true);
trrep::transaction_context& tc(
trrep_mock::start_applying_transaction( trrep_mock::start_applying_transaction(
cc, 1, 1, cc, 1, 1,
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END);
char buf[1] = { 1 }; char buf[1] = { 1 };
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 1); BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 1);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); const trrep::transaction_context& txc(cc.transaction());
BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_aborted);
} }
// Test on_apply() method for 2pc transaction which // 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, trrep::client_context::m_applier,
true); true);
cc.fail_next_applying(true); cc.fail_next_applying(true);
trrep::transaction_context& tc(
trrep_mock::start_applying_transaction( trrep_mock::start_applying_transaction(
cc, 1, 1, cc, 1, 1,
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END);
char buf[1] = { 1 }; char buf[1] = { 1 };
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 1); BOOST_REQUIRE(sc.on_apply(cc, trrep::data(buf, 1)) == 1);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); const trrep::transaction_context& txc(cc.transaction());
BOOST_REQUIRE(txc.state() == trrep::transaction_context::s_aborted);
} }

View File

@ -431,7 +431,7 @@ int trrep::transaction_context::after_statement()
case s_cert_failed: case s_cert_failed:
client_context_.override_error(trrep::e_deadlock_error); client_context_.override_error(trrep::e_deadlock_error);
lock.unlock(); lock.unlock();
ret = client_context_.rollback(*this); ret = client_context_.rollback();
lock.lock(); lock.lock();
if (state() != s_must_replay) if (state() != s_must_replay)
{ {
@ -480,7 +480,7 @@ int trrep::transaction_context::after_statement()
bool trrep::transaction_context::bf_abort( bool trrep::transaction_context::bf_abort(
trrep::unique_lock<trrep::mutex>& lock TRREP_UNUSED, trrep::unique_lock<trrep::mutex>& lock TRREP_UNUSED,
const trrep::transaction_context& txc) wsrep_seqno_t bf_seqno)
{ {
bool ret(false); bool ret(false);
assert(lock.owns_lock()); assert(lock.owns_lock());
@ -490,10 +490,10 @@ bool trrep::transaction_context::bf_abort(
{ {
trrep::log() << "Transaction not active, skipping 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 " trrep::log() << "Not allowed to BF abort transaction ordered before "
<< "aborter: " << seqno() << " < " << txc.seqno(); << "aborter: " << seqno() << " < " << bf_seqno;
} }
else else
{ {
@ -506,11 +506,11 @@ bool trrep::transaction_context::bf_abort(
{ {
wsrep_seqno_t victim_seqno(WSREP_SEQNO_UNDEFINED); wsrep_seqno_t victim_seqno(WSREP_SEQNO_UNDEFINED);
wsrep_status_t status(client_context_.provider().bf_abort( wsrep_status_t status(client_context_.provider().bf_abort(
txc.seqno(), id_.get(), &victim_seqno)); bf_seqno, id_.get(), &victim_seqno));
switch (status) switch (status)
{ {
case WSREP_OK: case WSREP_OK:
trrep::log() << "Seqno " << txc.seqno() trrep::log() << "Seqno " << bf_seqno
<< " succesfully BF aborted " << id_.get() << " succesfully BF aborted " << id_.get()
<< " victim_seqno " << victim_seqno; << " victim_seqno " << victim_seqno;
bf_abort_state_ = state(); bf_abort_state_ = state();
@ -518,7 +518,7 @@ bool trrep::transaction_context::bf_abort(
ret = true; ret = true;
break; break;
default: default:
trrep::log() << "Seqno " << txc.seqno() trrep::log() << "Seqno " << bf_seqno
<< " failed to BF abort " << id_.get() << " failed to BF abort " << id_.get()
<< " with status " << status << " with status " << status
<< " victim_seqno " << victim_seqno; << " victim_seqno " << victim_seqno;
@ -588,6 +588,7 @@ void trrep::transaction_context::state(
} }
} }
#if 0
int trrep::transaction_context::certify_fragment( int trrep::transaction_context::certify_fragment(
trrep::unique_lock<trrep::mutex>& lock) trrep::unique_lock<trrep::mutex>& lock)
{ {
@ -658,6 +659,7 @@ int trrep::transaction_context::certify_fragment(
return ret; return ret;
} }
#endif
int trrep::transaction_context::certify_commit( int trrep::transaction_context::certify_commit(
trrep::unique_lock<trrep::mutex>& lock) trrep::unique_lock<trrep::mutex>& lock)

View File

@ -12,41 +12,82 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
// namespace
// Test a succesful 1PC transaction lifecycle
//
BOOST_AUTO_TEST_CASE(transaction_context_1pc)
{ {
trrep::mock_server_context sc("s1", "s1", struct replicating_client_fixture
trrep::server_context::rm_sync); {
trrep::mock_client_context cc(sc,trrep::client_id(1), replicating_client_fixture()
trrep::client_context::m_replicating); : sc("s1", "s1", trrep::server_context::rm_async)
trrep::transaction_context& tc(cc.transaction()); , 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 // Verify initial state
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); 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_FIXTURE_TEST_CASE(transaction_context_1pc, replicating_client_fixture)
{
// Start a new transaction with ID 1 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
// Run before commit // Run before commit
BOOST_REQUIRE(tc.before_commit() == 0); BOOST_REQUIRE(cc.before_commit() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing);
// Run ordered commit // 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); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_ordered_commit);
// Run after 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); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
@ -56,45 +97,36 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc)
// //
// Test a succesful 2PC transaction lifecycle // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
// Run before prepare // Run before prepare
BOOST_REQUIRE(tc.before_prepare() == 0); BOOST_REQUIRE(cc.before_prepare() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing);
// Run after prepare // Run after prepare
BOOST_REQUIRE(tc.after_prepare() == 0); BOOST_REQUIRE(cc.after_prepare() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing);
// Run before commit // Run before commit
BOOST_REQUIRE(tc.before_commit() == 0); BOOST_REQUIRE(cc.before_commit() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committing);
// Run ordered commit // 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); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_ordered_commit);
// Run after 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); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
@ -104,34 +136,24 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc)
// //
// Test a voluntary rollback // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
// Run before commit // Run before commit
BOOST_REQUIRE(tc.before_rollback() == 0); BOOST_REQUIRE(cc.before_rollback() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborting);
// Run after commit // Run after commit
BOOST_REQUIRE(tc.after_rollback() == 0); BOOST_REQUIRE(cc.after_rollback() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == 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 // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); 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 // 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.state() == trrep::transaction_context::s_must_abort);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
// Rollback sequence // 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.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.state() == trrep::transaction_context::s_aborted);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == 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 // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); 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 // 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.state() == trrep::transaction_context::s_must_abort);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
// Rollback sequence // 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.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.state() == trrep::transaction_context::s_aborted);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == 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 // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
// Run before prepare // Run before prepare
BOOST_REQUIRE(tc.before_prepare() == 0); BOOST_REQUIRE(cc.before_prepare() == 0);
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing); 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 // 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.state() == trrep::transaction_context::s_must_abort);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
// Rollback sequence // 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.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.state() == trrep::transaction_context::s_aborted);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == 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 // Test a 1PC transaction which gets BF aborted during before_commit via
// provider before the write set was ordered and certified. // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); 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); trrep_mock::bf_abort_provider(sc, tc, WSREP_SEQNO_UNDEFINED);
// Run before commit // 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.state() == trrep::transaction_context::s_cert_failed);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
// Rollback sequence // 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.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.state() == trrep::transaction_context::s_aborted);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == 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. // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); 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.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == 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 // Test a 1PC transaction which gets BF aborted during before_commit via
// provider after the write set was ordered and certified. // 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 // Start a new transaction with ID 1
tc.start_transaction(1); cc.start_transaction(1);
BOOST_REQUIRE(tc.active()); BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1)); BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing); 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); trrep_mock::bf_abort_provider(sc, tc, 1);
// Run before commit // 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.state() == trrep::transaction_context::s_must_replay);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
BOOST_REQUIRE(tc.ordered() == true); BOOST_REQUIRE(tc.ordered() == true);
// Rollback sequence // 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.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); BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_must_replay);
// Cleanup after statement // Cleanup after statement
BOOST_REQUIRE(tc.after_statement() == 0); cc.after_statement();
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.ordered() == false); BOOST_REQUIRE(tc.ordered() == false);
BOOST_REQUIRE(tc.certified() == false); BOOST_REQUIRE(tc.certified() == false);
BOOST_REQUIRE(cc.current_error() == trrep::e_success); 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", BOOST_REQUIRE(cc.before_commit() == 0);
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(tc.state() == trrep::transaction_context::s_committing); 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.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.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.state() == trrep::transaction_context::s_committed);
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(cc.current_error() == trrep::e_success); 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::mock_client_context cc(sc,
trrep::client_id(1), trrep::client_id(1),
trrep::client_context::m_applier); trrep::client_context::m_applier);
trrep::transaction_context& tc(trrep_mock::start_applying_transaction(
BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0);
trrep_mock::start_applying_transaction(
cc, 1, 1, cc, 1, 1,
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END)); WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END);
const trrep::transaction_context& tc(cc.transaction());
BOOST_REQUIRE(tc.active() == false); 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.active() == true);
BOOST_REQUIRE(tc.certified() == true); BOOST_REQUIRE(tc.certified() == true);
BOOST_REQUIRE(tc.ordered() == 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.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.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.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.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.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.state() == trrep::transaction_context::s_committed);
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(cc.current_error() == trrep::e_success); 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", BOOST_REQUIRE(cc.before_rollback() == 0);
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(tc.state() == trrep::transaction_context::s_aborting); 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.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.state() == trrep::transaction_context::s_aborted);
BOOST_REQUIRE(tc.active() == false); BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(cc.current_error() == trrep::e_success); BOOST_REQUIRE(cc.current_error() == trrep::e_success);