diff --git a/include/wsrep/client_context.hpp b/include/wsrep/client_context.hpp index 7ba67da..cf9d130 100644 --- a/include/wsrep/client_context.hpp +++ b/include/wsrep/client_context.hpp @@ -229,6 +229,12 @@ namespace wsrep return transaction_.start_transaction(wsh, meta); } + int start_replaying() + { + assert(mode_ == m_applier); + return transaction_.start_replaying(); + } + void adopt_transaction(wsrep::transaction_context& transaction) { transaction_.start_transaction(transaction.id()); diff --git a/include/wsrep/transaction_context.hpp b/include/wsrep/transaction_context.hpp index 7e6e9d5..a51331f 100644 --- a/include/wsrep/transaction_context.hpp +++ b/include/wsrep/transaction_context.hpp @@ -92,6 +92,8 @@ namespace wsrep int start_transaction(const wsrep::ws_handle& ws_handle, const wsrep::ws_meta& ws_meta); + int start_replaying(); + int append_key(const wsrep::key&); int append_data(const wsrep::const_buffer&); diff --git a/src/server_context.cpp b/src/server_context.cpp index c6573f2..7e72bfa 100644 --- a/src/server_context.cpp +++ b/src/server_context.cpp @@ -136,6 +136,11 @@ int wsrep::server_context::on_apply( assert(txc.active() == false); client_context.start_transaction(ws_handle, ws_meta); } + else + { + client_context.start_replaying(); + } + if (client_context.apply(data)) { ret = 1; diff --git a/src/transaction_context.cpp b/src/transaction_context.cpp index 0d8f097..e28b832 100644 --- a/src/transaction_context.cpp +++ b/src/transaction_context.cpp @@ -79,6 +79,17 @@ int wsrep::transaction_context::start_transaction( return 0; } +int wsrep::transaction_context::start_replaying() +{ + assert(ws_meta_.flags() & wsrep::provider::flag::commit); + assert(active()); + assert(client_context_.mode() == wsrep::client_context::m_applier); + assert(state() == s_replaying); + assert(ws_handle_.opaque()); + assert(ws_meta_.seqno().nil() == false); + certified_ = true; + return 0; +} int wsrep::transaction_context::append_key(const wsrep::key& key) { @@ -255,6 +266,7 @@ int wsrep::transaction_context::before_commit() } if (ret == 0) { + assert(certified()); assert(ordered()); lock.unlock(); enum wsrep::provider::status @@ -280,6 +292,7 @@ int wsrep::transaction_context::before_commit() } break; case wsrep::client_context::m_applier: + assert(certified()); assert(ordered()); ret = provider_.commit_order_enter(ws_handle_, ws_meta_); if (ret) @@ -593,7 +606,8 @@ void wsrep::transaction_context::state( { log_debug() << "client: " << client_context_.id().get() << " txc: " << id().get() - << " state: " << state_ << " -> " << next_state; + << " state: " << to_string(state_) + << " -> " << to_string(next_state); } assert(lock.owns_lock()); static const char allowed[n_states][n_states] = diff --git a/src/transaction_context_test.cpp b/src/transaction_context_test.cpp deleted file mode 100644 index 33b37e4..0000000 --- a/src/transaction_context_test.cpp +++ /dev/null @@ -1,1224 +0,0 @@ -// -// Copyright (C) 2018 Codership Oy -// - -#include "wsrep/transaction_context.hpp" -#include "wsrep/provider.hpp" - -#include "mock_client_context.hpp" -#include "mock_server_context.hpp" - -#include "test_utils.hpp" - -#include -#include - -namespace -{ - struct replicating_client_fixture_sync_rm - { - replicating_client_fixture_sync_rm() - : sc("s1", "s1", wsrep::server_context::rm_sync) - , 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 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 replicating_client_fixture_autocommit - { - replicating_client_fixture_autocommit() - : sc("s1", "s1", wsrep::server_context::rm_sync) - , cc(sc, wsrep::client_id(1), - wsrep::client_context::m_replicating, true) - , 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() - : sc("s1", "s1", - wsrep::server_context::rm_async) - , cc(sc, - wsrep::client_id(1), - wsrep::client_context::m_applier) - , tc(cc.transaction()) - { - BOOST_REQUIRE(cc.before_command() == 0); - BOOST_REQUIRE(cc.before_statement() == 0); - wsrep::ws_handle ws_handle(1, (void*)1); - wsrep::ws_meta ws_meta(wsrep::gtid(wsrep::id("1"), wsrep::seqno(1)), - wsrep::stid(sc.id(), 1, cc.id()), - wsrep::seqno(0), - wsrep::provider::flag::start_transaction | - wsrep::provider::flag::commit); - BOOST_REQUIRE(cc.start_transaction(ws_handle, ws_meta) == 0); - 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); - } - wsrep::mock_server_context sc; - wsrep::mock_client_context cc; - const wsrep::transaction_context& tc; - }; - - struct streaming_client_fixture_row - { - streaming_client_fixture_row() - : sc("s1", "s1", wsrep::server_context::rm_sync) - , 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); - cc.enable_streaming(wsrep::transaction_context::streaming_context::row, 1); - } - wsrep::mock_server_context sc; - wsrep::mock_client_context cc; - const wsrep::transaction_context& tc; - }; - - typedef - boost::mpl::vector - replicating_fixtures; -} - -BOOST_FIXTURE_TEST_CASE(transaction_context_append_key_data, - replicating_client_fixture_sync_rm) -{ - cc.start_transaction(1); - BOOST_REQUIRE(tc.active()); - int vals[3] = {1, 2, 3}; - wsrep::key key(wsrep::key::exclusive); - for (int i(0); i < 3; ++i) - { - key.append_key_part(&vals[i], sizeof(vals[i])); - } - BOOST_REQUIRE(cc.append_key(key) == 0); - wsrep::const_buffer data(&vals[2], sizeof(vals[2])); - BOOST_REQUIRE(cc.append_data(data) == 0); - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(cc.after_commit() == 0); - cc.after_statement(); -} -// -// Test a succesful 1PC transaction lifecycle -// -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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - // Verify that the commit can be succesfully executed in separate command - BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_success); - cc.after_command_before_result(); - cc.after_command_after_result(); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); - BOOST_REQUIRE(cc.before_command() == 0); - BOOST_REQUIRE(cc.before_statement() == 0); - // Run before commit - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); - - // Run ordered commit - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_ordered_commit); - - // Run after commit - BOOST_REQUIRE(cc.after_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -// -// Test a succesful 2PC transaction lifecycle -// -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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - // Run before prepare - BOOST_REQUIRE(cc.before_prepare() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_preparing); - - // Run after prepare - BOOST_REQUIRE(cc.after_prepare() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); - - // Run before commit - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); - - // Run ordered commit - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_ordered_commit); - - // Run after commit - BOOST_REQUIRE(cc.after_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -// -// Test a voluntary rollback -// -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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - // Run before commit - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - - // Run after commit - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -// -// Test a 1PC transaction which gets BF aborted before before_commit -// -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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - wsrep_test::bf_abort_unordered(cc); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -// -// Test a 2PC transaction which gets BF aborted before before_prepare -// -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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - wsrep_test::bf_abort_unordered(cc); - - // Run before commit - BOOST_REQUIRE(cc.before_prepare()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -// -// Test a 2PC transaction which gets BF aborted before before_prepare -// -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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - // Run before prepare - BOOST_REQUIRE(cc.before_prepare() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_preparing); - - wsrep_test::bf_abort_unordered(cc); - - // Run before commit - BOOST_REQUIRE(cc.after_prepare()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -// -// 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_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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - wsrep_test::bf_abort_provider(sc, tc, wsrep::seqno::undefined()); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_cert_failed); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -// -// Test a 1PC transaction which gets BF aborted during before_commit -// when waiting for replayers -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_bf_during_commit_wait_for_replayers, T, - replicating_fixtures, T) -{ - wsrep::mock_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.bf_abort_during_wait_ = true; - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -// -// Test a 1PC transaction for which prepare data fails -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_error_during_prepare_data, T, - replicating_fixtures, T) -{ - wsrep::mock_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.error_during_prepare_data_ = true; - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -// -// Test a 1PC transaction which gets killed by DBMS before certification -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_killed_before_certify, T, - replicating_fixtures, T) -{ - wsrep::mock_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.killed_before_certify_ = true; - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(cc.current_error() == wsrep::e_interrupted_error); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - - -// -// Test a 1PC transaction which gets BF aborted during before_commit via -// provider after the write set was ordered and certified. This must -// result replaying of transaction. -// -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::mock_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); - - wsrep_test::bf_abort_provider(sc, tc, wsrep::seqno(1)); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == true); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); - BOOST_REQUIRE(cc.replays() == 1); -} - -// -// Test a 1PC transaction which gets "warning error" from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_warning_error_from_certify, 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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - sc.provider().inject_error(wsrep::provider::error_warning); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); -} - -// -// Test a 1PC transaction which gets transaction missing from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_transaction_missing_from_certify, 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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - sc.provider().inject_error(wsrep::provider::error_transaction_missing); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); -} - -// -// Test a 1PC transaction which gets size exceeded error from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_size_exceeded_from_certify, 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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - sc.provider().inject_error(wsrep::provider::error_size_exceeded); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); -} - -// -// Test a 1PC transaction which gets connection failed error from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_connection_failed_from_certify, 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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - sc.provider().inject_error(wsrep::provider::error_connection_failed); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); -} - -// -// Test a 1PC transaction which gets not allowed error from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_no_allowed_from_certify, 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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - sc.provider().inject_error(wsrep::provider::error_not_allowed); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); -} - -// -// Test a 1PC transaction which gets fatal error from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_fatal_from_certify, T, - replicating_fixtures, T) -{ - wsrep::mock_server_context& sc(T::sc); - wsrep::mock_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); - - sc.provider().inject_error(wsrep::provider::error_fatal); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); - BOOST_REQUIRE(cc.aborts() == 1); -} - -// -// Test a 1PC transaction which gets unknown from certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_unknown_from_certify, T, - replicating_fixtures, T) -{ - wsrep::mock_server_context& sc(T::sc); - wsrep::mock_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); - - sc.provider().inject_error(wsrep::provider::error_unknown); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(tc.ordered() == false); - - sc.provider().inject_error(wsrep::provider::success); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_error_during_commit); -} - -// -// Test a 1PC transaction which gets BF aborted before grabbing lock -// after certify call -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_1pc_bf_abort_after_certify_regain_lock, T, - replicating_fixtures, T) -{ - // wsrep::mock_server_context& sc(T::sc); - wsrep::mock_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.sync_point_action_ = "wsrep_after_certification"; - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - BOOST_REQUIRE(tc.certified() == true); - BOOST_REQUIRE(tc.ordered() == true); - - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(cc.replays() == 1); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -// -// Test a 2PC transaction which gets BF aborted when trying to grab -// commit order. -// -BOOST_FIXTURE_TEST_CASE_TEMPLATE( - transaction_context_2pc_bf_during_commit_order_enter, 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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - BOOST_REQUIRE(cc.before_prepare() == 0); - BOOST_REQUIRE(cc.after_prepare() == 0); - - sc.provider().inject_error(wsrep::provider::error_bf_abort); - - // Run before commit - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - BOOST_REQUIRE(tc.certified() == true); - BOOST_REQUIRE(tc.ordered() == true); - - sc.provider().inject_error(wsrep::provider::success); - // Rollback sequence - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); - - // Cleanup after statement - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -// -// 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(); - BOOST_REQUIRE(cc.before_command() == 0); - 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_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()); - BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1)); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_executing); - - wsrep_test::bf_abort_unordered(cc); - - cc.after_statement(); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.ordered() == false); - BOOST_REQUIRE(tc.certified() == false); - BOOST_REQUIRE(cc.current_error()); -} - -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( - transaction_context_1pc_autocommit_retry_bf_aborted, - replicating_client_fixture_autocommit) -{ - - cc.start_transaction(1); - BOOST_REQUIRE(tc.active()); - wsrep_test::bf_abort_unordered(cc); - BOOST_REQUIRE(cc.before_commit()); - BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error); - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_may_retry); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - BOOST_REQUIRE(cc.state() == wsrep::client_context::s_exec); -} - -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(); - BOOST_REQUIRE(cc.state() == wsrep::client_context::s_exec); - cc.after_command_before_result(); - BOOST_REQUIRE(cc.state() == wsrep::client_context::s_result); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); - wsrep_test::bf_abort_unordered(cc); - // The result is being sent to client. We need to mark transaction - // as must_abort but not override error yet as this might cause - // a race condition resulting incorrect result returned to the DBMS client. - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); - // After the result has been sent to the DBMS client, the after result - // processing should roll back the transaction and set the error. - cc.after_command_after_result(); - BOOST_REQUIRE(cc.state() == wsrep::client_context::s_idle); - BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error); - BOOST_REQUIRE(tc.active() == true); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - 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_FIXTURE_TEST_CASE( - 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()); - 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_aborted); - 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_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) -{ - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_ordered_commit); - BOOST_REQUIRE(cc.after_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); - cc.after_statement(); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -BOOST_FIXTURE_TEST_CASE(transaction_context_2pc_applying, - applying_client_fixture) -{ - BOOST_REQUIRE(cc.before_prepare() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_preparing); - BOOST_REQUIRE(cc.after_prepare() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_ordered_commit); - BOOST_REQUIRE(cc.after_commit() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); - cc.after_statement(); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - -BOOST_FIXTURE_TEST_CASE(transaction_context_applying_rollback, - applying_client_fixture) -{ - BOOST_REQUIRE(cc.before_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborting); - BOOST_REQUIRE(cc.after_rollback() == 0); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - cc.after_statement(); - BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); - BOOST_REQUIRE(tc.active() == false); - BOOST_REQUIRE(cc.current_error() == wsrep::e_success); -} - - -/////////////////////////////////////////////////////////////////////////////// -// STREAMING REPLICATION // -/////////////////////////////////////////////////////////////////////////////// - -BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_1pc_commit, - streaming_client_fixture_row) -{ - BOOST_REQUIRE(cc.start_transaction(1) == 0); - BOOST_REQUIRE(cc.after_row() == 0); - BOOST_REQUIRE(tc.streaming_context_.fragments_certified() == 1); - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(cc.after_commit() == 0); - BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_success); - BOOST_REQUIRE(sc.provider().fragments() == 2); - BOOST_REQUIRE(sc.provider().start_fragments() == 1); - BOOST_REQUIRE(sc.provider().commit_fragments() == 1); - -} - -BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_2pc_commit, - streaming_client_fixture_row) -{ - BOOST_REQUIRE(cc.start_transaction(1) == 0); - BOOST_REQUIRE(cc.after_row() == 0); - BOOST_REQUIRE(tc.streaming_context_.fragments_certified() == 1); - BOOST_REQUIRE(cc.before_prepare() == 0); - BOOST_REQUIRE(cc.after_prepare() == 0); - BOOST_REQUIRE(cc.before_commit() == 0); - BOOST_REQUIRE(cc.ordered_commit() == 0); - BOOST_REQUIRE(cc.after_commit() == 0); - BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_success); - BOOST_REQUIRE(sc.provider().fragments() == 2); - BOOST_REQUIRE(sc.provider().start_fragments() == 1); - BOOST_REQUIRE(sc.provider().commit_fragments() == 1); - -} diff --git a/test/client_context_fixture.hpp b/test/client_context_fixture.hpp index 2d67b35..91b95e5 100644 --- a/test/client_context_fixture.hpp +++ b/test/client_context_fixture.hpp @@ -119,5 +119,46 @@ namespace wsrep::fake_client_context cc; const wsrep::transaction_context& tc; }; + + struct streaming_client_fixture_byte + { + streaming_client_fixture_byte() + : sc("s1", "s1", wsrep::server_context::rm_sync) + , 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); + cc.enable_streaming(wsrep::transaction_context::streaming_context::row, 1); + } + wsrep::fake_server_context sc; + wsrep::fake_client_context cc; + const wsrep::transaction_context& tc; + }; + + struct streaming_client_fixture_statement + { + streaming_client_fixture_statement() + : sc("s1", "s1", wsrep::server_context::rm_sync) + , 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); + cc.enable_streaming(wsrep::transaction_context::streaming_context::row, 1); + } + + wsrep::fake_server_context sc; + wsrep::fake_client_context cc; + const wsrep::transaction_context& tc; + }; } #endif // WSREP_TEST_CLIENT_CONTEXT_FIXTURE_HPP diff --git a/test/fake_client_context.cpp b/test/fake_client_context.cpp index ac00151..797a004 100644 --- a/test/fake_client_context.cpp +++ b/test/fake_client_context.cpp @@ -10,7 +10,8 @@ int wsrep::fake_client_context::apply( const wsrep::const_buffer& data __attribute__((unused))) { - assert(transaction_.state() == wsrep::transaction_context::s_executing); + assert(transaction_.state() == wsrep::transaction_context::s_executing || + transaction_.state() == wsrep::transaction_context::s_replaying); return (fail_next_applying_ ? 1 : 0); } diff --git a/test/fake_client_context.hpp b/test/fake_client_context.hpp index 1361080..828634a 100644 --- a/test/fake_client_context.hpp +++ b/test/fake_client_context.hpp @@ -56,10 +56,12 @@ namespace wsrep void will_replay(wsrep::transaction_context&) WSREP_OVERRIDE { } int replay(wsrep::transaction_context& tc) WSREP_OVERRIDE { - wsrep::unique_lock lock(mutex_); - tc.state(lock, wsrep::transaction_context::s_committing); - tc.state(lock, wsrep::transaction_context::s_ordered_commit); - tc.state(lock, wsrep::transaction_context::s_committed); + wsrep::client_applier_mode am(*this); + if (server_context().on_apply( + *this, tc.ws_handle(), tc.ws_meta(), wsrep::const_buffer())) + { + return 1; + } ++replays_; return 0; } diff --git a/test/fake_provider.hpp b/test/fake_provider.hpp index ac2c9e4..2538804 100644 --- a/test/fake_provider.hpp +++ b/test/fake_provider.hpp @@ -52,6 +52,7 @@ namespace wsrep int flags, wsrep::ws_meta& ws_meta) { + ws_handle = wsrep::ws_handle(ws_handle.transaction_id(), (void*)1); wsrep::log_info() << "provider certify: " << "client: " << client_id.get() << " flags: " << std::hex << flags diff --git a/test/transaction_context_test.cpp b/test/transaction_context_test.cpp index 5df15f4..0c728cf 100644 --- a/test/transaction_context_test.cpp +++ b/test/transaction_context_test.cpp @@ -899,7 +899,10 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_applying_rollback, // STREAMING REPLICATION // /////////////////////////////////////////////////////////////////////////////// -BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_1pc_commit, +// +// Test 1PC with row streaming with one row +// +BOOST_FIXTURE_TEST_CASE(transaction_context_row_streaming_1pc_commit, streaming_client_fixture_row) { BOOST_REQUIRE(cc.start_transaction(1) == 0); @@ -914,10 +917,12 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_1pc_commit, BOOST_REQUIRE(sc.provider().commit_fragments() == 1); } - - -BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_1pc_commit_two_statements, - streaming_client_fixture_row) +// +// Test 1PC row streaming with two separate statements +// +BOOST_FIXTURE_TEST_CASE( + transaction_context_row_streaming_1pc_commit_two_statements, + streaming_client_fixture_row) { BOOST_REQUIRE(cc.start_transaction(1) == 0); BOOST_REQUIRE(cc.after_row() == 0); @@ -933,11 +938,12 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_1pc_commit_two_statements, BOOST_REQUIRE(sc.provider().fragments() == 3); BOOST_REQUIRE(sc.provider().start_fragments() == 1); BOOST_REQUIRE(sc.provider().commit_fragments() == 1); - } - -BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_rollback, +// +// Test streaming rollback +// +BOOST_FIXTURE_TEST_CASE(transaction_context_row_streaming_rollback, streaming_client_fixture_row) { BOOST_REQUIRE(cc.start_transaction(1) == 0); @@ -951,7 +957,10 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_rollback, BOOST_REQUIRE(sc.provider().rollback_fragments() == 1); } -BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_cert_fail_non_commit, +// +// Test streaming certification failure during fragment replication +// +BOOST_FIXTURE_TEST_CASE(transaction_context_row_streaming_cert_fail_non_commit, streaming_client_fixture_row) { BOOST_REQUIRE(cc.start_transaction(1) == 0); @@ -968,3 +977,69 @@ BOOST_FIXTURE_TEST_CASE(transaction_context_streaming_cert_fail_non_commit, BOOST_REQUIRE(sc.provider().rollback_fragments() == 1); } +// +// Test streaming certification failure during commit +// +BOOST_FIXTURE_TEST_CASE(transaction_context_row_streaming_cert_fail_commit, + streaming_client_fixture_row) +{ + BOOST_REQUIRE(cc.start_transaction(1) == 0); + BOOST_REQUIRE(cc.after_row() == 0); + BOOST_REQUIRE(tc.streaming_context_.fragments_certified() == 1); + sc.provider().certify_status_ = wsrep::provider::error_certification_failed; + BOOST_REQUIRE(cc.before_commit() == 1); + BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_cert_failed); + sc.provider().certify_status_ = wsrep::provider::success; + BOOST_REQUIRE(cc.before_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); + BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_error); + BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted); + BOOST_REQUIRE(sc.provider().fragments() == 2); + BOOST_REQUIRE(sc.provider().start_fragments() == 1); + BOOST_REQUIRE(sc.provider().rollback_fragments() == 1); +} + +// +// Test streaming BF abort after succesful certification +// +BOOST_FIXTURE_TEST_CASE(transaction_context_row_streaming_bf_abort_committing, + streaming_client_fixture_row) +{ + cc.debug_log_level(1); + BOOST_REQUIRE(cc.start_transaction(1) == 0); + BOOST_REQUIRE(cc.after_row() == 0); + BOOST_REQUIRE(tc.streaming_context_.fragments_certified() == 1); + BOOST_REQUIRE(cc.before_commit() == 0); + BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committing); + wsrep_test::bf_abort_ordered(cc); + BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_abort); + BOOST_REQUIRE(cc.before_rollback() == 0); + BOOST_REQUIRE(cc.after_rollback() == 0); + BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay); + BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_success); + BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed); + BOOST_REQUIRE(sc.provider().fragments() == 2); + BOOST_REQUIRE(sc.provider().start_fragments() == 1); + BOOST_REQUIRE(sc.provider().rollback_fragments() == 1); +} + + + +BOOST_FIXTURE_TEST_CASE(transaction_context_byte_batch_streaming_1pc_commit, + streaming_client_fixture_byte) +{ + +} + +BOOST_FIXTURE_TEST_CASE(transaction_context_byte_streaming_1pc_commit, + streaming_client_fixture_byte) +{ + +} + + +BOOST_FIXTURE_TEST_CASE(transaction_context_statement_streaming_1pc_commit, + streaming_client_fixture_statement) +{ + +}