1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-07-28 20:02:00 +03:00

* Run transaction context unit tests for both sync and async rm

* Unit test case for BF abort before before_statement() and
  after after_statement()
* Cleaned up empty client_context_test.cpp
This commit is contained in:
Teemu Ollakka
2018-06-11 14:54:37 +03:00
parent 58ea925dc3
commit 459ada6b3b
5 changed files with 210 additions and 78 deletions

View File

@ -16,7 +16,6 @@ target_link_libraries(wsrep-lib wsrep_api_v26 pthread dl)
add_executable(wsrep-lib_test
mock_client_context.cpp
test_utils.cpp
client_context_test.cpp
server_context_test.cpp
transaction_context_test.cpp
wsrep-lib_test.cpp

View File

@ -44,18 +44,37 @@ int wsrep::client_context::before_command()
state(lock, s_exec);
assert(transaction_.active() == false ||
(transaction_.state() == wsrep::transaction_context::s_executing ||
transaction_.state() == wsrep::transaction_context::s_aborted));
transaction_.state() == wsrep::transaction_context::s_aborted ||
(transaction_.state() == wsrep::transaction_context::s_must_abort &&
server_context_.rollback_mode() == wsrep::server_context::rm_async)));
// Transaction was rolled back either just before sending result
// to the client, or after client_context become idle.
// Clean up the transaction and return error.
if (transaction_.active() &&
transaction_.state() == wsrep::transaction_context::s_aborted)
if (transaction_.active())
{
override_error(wsrep::e_deadlock_error);
lock.unlock();
(void)transaction_.after_statement();
lock.lock();
if (transaction_.state() == wsrep::transaction_context::s_must_abort)
{
assert(server_context_.rollback_mode() ==
wsrep::server_context::rm_async);
override_error(wsrep::e_deadlock_error);
lock.unlock();
rollback();
(void)transaction_.after_statement();
lock.lock();
assert(transaction_.state() ==
wsrep::transaction_context::s_aborted);
assert(transaction_.active() == false);
assert(current_error() != wsrep::e_success);
}
else if (transaction_.state() == wsrep::transaction_context::s_aborted)
{
// Transaction was rolled back either just before sending result
// to the client, or after client_context become idle.
// Clean up the transaction and return error.
override_error(wsrep::e_deadlock_error);
lock.unlock();
(void)transaction_.after_statement();
lock.lock();
assert(transaction_.active() == false);
}
return 1;
}
return 0;
@ -118,10 +137,7 @@ int wsrep::client_context::before_statement()
if (transaction_.active() &&
transaction_.state() == wsrep::transaction_context::s_must_abort)
{
override_error(wsrep::e_deadlock_error);
lock.unlock();
rollback();
lock.lock();
// Rollback and cleanup will happen in after_command_before_result()
return 1;
}
return 0;
@ -176,7 +192,7 @@ void wsrep::client_context::state(
{
std::ostringstream os;
os << "client_context: Unallowed state transition: "
<< state_ << " -> " << state << "\n";
<< state_ << " -> " << state;
throw wsrep::runtime_error(os.str());
}
}

View File

@ -1,30 +0,0 @@
//
// Copyright (C) 2018 Codership Oy <info@codership.com>
//
#include "mock_client_context.hpp"
#include "mock_server_context.hpp"
#include "test_utils.hpp"
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(client_context_test_error_codes)
{
wsrep::mock_server_context sc("s1", "s1", wsrep::server_context::rm_async);
wsrep::mock_client_context cc(sc,
wsrep::client_id(1),
wsrep::client_context::m_applier,
false);
const wsrep::transaction_context& txc(cc.transaction());
cc.before_command();
cc.before_statement();
BOOST_REQUIRE(txc.active() == false);
cc.start_transaction(1);
wsrep_test::bf_abort_unordered(cc);
cc.after_statement();
cc.after_command_before_result();
cc.after_command_after_result();
}

View File

@ -394,6 +394,7 @@ private:
int client_command(Func f)
{
int err(before_command());
// If err != 0, transaction was BF aborted while client idle
if (err == 0)
{
err = before_statement();
@ -404,6 +405,12 @@ private:
after_statement();
}
after_command_before_result();
if (current_error())
{
assert(transaction_.state() ==
wsrep::transaction_context::s_aborted);
err = 1;
}
after_command_after_result();
return err;
}
@ -419,7 +426,6 @@ private:
se_trx_.start(this);
return err;
});
err = err || current_error();
err = err || client_command(
[&]()
{
@ -438,7 +444,6 @@ private:
os.str().size()));
return err;
});
err = err || current_error();
err = err || client_command(
[&]()
{
@ -455,9 +460,9 @@ private:
return err;
});
assert((current_error() &&
transaction().state() == wsrep::transaction_context::s_aborted) ||
transaction().state() == wsrep::transaction_context::s_committed);
assert(err ||
transaction().state() == wsrep::transaction_context::s_aborted ||
transaction().state() == wsrep::transaction_context::s_committed);
assert(se_trx_.active() == false);
assert(transaction().active() == false);
switch (transaction().state())

View File

@ -11,12 +11,13 @@
#include "test_utils.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/mpl/vector.hpp>
namespace
{
struct replicating_client_fixture
struct replicating_client_fixture_sync_rm
{
replicating_client_fixture()
replicating_client_fixture_sync_rm()
: sc("s1", "s1", wsrep::server_context::rm_sync)
, cc(sc, wsrep::client_id(1),
wsrep::client_context::m_replicating)
@ -33,6 +34,25 @@ namespace
const wsrep::transaction_context& tc;
};
struct replicating_client_fixture_async_rm
{
replicating_client_fixture_async_rm()
: sc("s1", "s1", wsrep::server_context::rm_async)
, cc(sc, wsrep::client_id(1),
wsrep::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() == wsrep::transaction_context::s_executing);
}
wsrep::mock_server_context sc;
wsrep::mock_client_context cc;
const wsrep::transaction_context& tc;
};
struct applying_client_fixture
{
applying_client_fixture()
@ -63,15 +83,22 @@ namespace
const wsrep::transaction_context& tc;
};
typedef
boost::mpl::vector<replicating_client_fixture_sync_rm,
replicating_client_fixture_async_rm>
replicating_fixtures;
}
//
// Test a succesful 1PC transaction lifecycle
//
BOOST_FIXTURE_TEST_CASE(transaction_context_1pc, replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(transaction_context_1pc, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -101,8 +128,11 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_1pc, replicating_client_fixture)
//
// Test a succesful 2PC transaction lifecycle
//
BOOST_FIXTURE_TEST_CASE(transaction_context_2pc, replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(transaction_context_2pc, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -140,8 +170,12 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_2pc, replicating_client_fixture)
//
// Test a voluntary rollback
//
BOOST_FIXTURE_TEST_CASE(transaction_context_rollback, replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(transaction_context_rollback, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -167,9 +201,13 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_rollback, replicating_client_fixture
//
// Test a 1PC transaction which gets BF aborted before before_commit
//
BOOST_FIXTURE_TEST_CASE(transaction_context_1pc_bf_before_before_commit,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_before_before_commit, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -201,9 +239,13 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_1pc_bf_before_before_commit,
//
// Test a 2PC transaction which gets BF aborted before before_prepare
//
BOOST_FIXTURE_TEST_CASE(transaction_context_2pc_bf_before_before_prepare,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_2pc_bf_before_before_prepare, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -235,9 +277,13 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_2pc_bf_before_before_prepare,
//
// Test a 2PC transaction which gets BF aborted before before_prepare
//
BOOST_FIXTURE_TEST_CASE(transaction_context_2pc_bf_before_after_prepare,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_2pc_bf_before_after_prepare, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -274,10 +320,14 @@ BOOST_FIXTURE_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_FIXTURE_TEST_CASE(
transaction_context_1pc_bf_during_before_commit_uncertified,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_during_before_commit_uncertified, T,
replicating_fixtures, T)
{
wsrep::mock_server_context& sc(T::sc);
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -306,13 +356,48 @@ BOOST_FIXTURE_TEST_CASE(
BOOST_REQUIRE(cc.current_error());
}
//
// Test a transaction which gets BF aborted before before_statement.
//
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_before_before_statement, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1));
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing);
cc.after_statement();
cc.after_command_before_result();
cc.after_command_after_result();
cc.before_command();
BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing);
wsrep_test::bf_abort_unordered(cc);
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort);
BOOST_REQUIRE(cc.before_statement() == 1);
BOOST_REQUIRE(tc.active());
cc.after_command_before_result();
BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error);
cc.after_command_after_result();
BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted);
}
//
// Test a transaction which gets BF aborted before after_statement.
//
BOOST_FIXTURE_TEST_CASE(
transaction_context_1pc_bf_during_before_after_statement,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_before_after_statement, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -332,10 +417,14 @@ BOOST_FIXTURE_TEST_CASE(
// Test a 1PC transaction which gets BF aborted during before_commit via
// provider after the write set was ordered and certified.
//
BOOST_FIXTURE_TEST_CASE(
transaction_context_1pc_bf_during_before_commit_certified,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_during_before_commit_certified, T,
replicating_fixtures, T)
{
wsrep::mock_server_context& sc(T::sc);
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
// Start a new transaction with ID 1
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -364,10 +453,38 @@ BOOST_FIXTURE_TEST_CASE(
BOOST_REQUIRE(cc.current_error() == wsrep::e_success);
}
BOOST_FIXTURE_TEST_CASE(
transaction_context_1pc_bf_abort_after_after_command_before_result,
replicating_client_fixture)
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_abort_after_after_statement, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
cc.after_statement();
BOOST_REQUIRE(cc.state() == wsrep::client_context::s_exec);
wsrep_test::bf_abort_unordered(cc);
BOOST_REQUIRE(cc.current_error() == wsrep::e_success);
BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort);
cc.after_command_before_result();
BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error);
BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted);
cc.after_command_after_result();
BOOST_REQUIRE(cc.current_error() == wsrep::e_success);
BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted);
}
BOOST_FIXTURE_TEST_CASE_TEMPLATE(
transaction_context_1pc_bf_abort_after_after_command_before_result, T,
replicating_fixtures, T)
{
wsrep::client_context& cc(T::cc);
const wsrep::transaction_context& tc(T::tc);
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
cc.after_statement();
@ -398,8 +515,8 @@ BOOST_FIXTURE_TEST_CASE(
}
BOOST_FIXTURE_TEST_CASE(
transaction_context_1pc_bf_abort_after_after_command_after_result,
replicating_client_fixture)
transaction_context_1pc_bf_abort_after_after_command_after_result_sync_rm,
replicating_client_fixture_sync_rm)
{
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
@ -422,6 +539,31 @@ BOOST_FIXTURE_TEST_CASE(
BOOST_REQUIRE(tc.active() == false);
}
BOOST_FIXTURE_TEST_CASE(
transaction_context_1pc_bf_abort_after_after_command_after_result_async_rm,
replicating_client_fixture_async_rm)
{
cc.start_transaction(1);
BOOST_REQUIRE(tc.active());
cc.after_statement();
BOOST_REQUIRE(cc.state() == wsrep::client_context::s_exec);
cc.after_command_before_result();
BOOST_REQUIRE(cc.state() == wsrep::client_context::s_result);
cc.after_command_after_result();
BOOST_REQUIRE(cc.state() == wsrep::client_context::s_idle);
wsrep_test::bf_abort_unordered(cc);
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort);
BOOST_REQUIRE(tc.active());
BOOST_REQUIRE(cc.before_command() == 1);
BOOST_REQUIRE(tc.active() == false);
BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error);
cc.after_command_before_result();
BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error);
cc.after_command_after_result();
BOOST_REQUIRE(cc.current_error() == wsrep::e_success);
BOOST_REQUIRE(tc.active() == false);
}
BOOST_FIXTURE_TEST_CASE(transaction_context_1pc_applying,
applying_client_fixture)
{