mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-04-19 21:02:17 +03:00
Tests and fixes for replaying.
This commit is contained in:
parent
ca6286d8b2
commit
0b6e49474f
@ -388,7 +388,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void will_replay(wsrep::transaction_context&) override { }
|
void will_replay(wsrep::transaction_context&) override { }
|
||||||
int replay(wsrep::transaction_context& txc) override
|
enum wsrep::provider::status
|
||||||
|
replay(wsrep::transaction_context& txc) override
|
||||||
{
|
{
|
||||||
// wsrep::log() << "replay: " << txc.id().get();
|
// wsrep::log() << "replay: " << txc.id().get();
|
||||||
wsrep::client_applier_mode applier_mode(*this);
|
wsrep::client_applier_mode applier_mode(*this);
|
||||||
@ -490,6 +491,11 @@ private:
|
|||||||
if (err == 0) se_trx_.commit();
|
if (err == 0) se_trx_.commit();
|
||||||
err = err || ordered_commit();
|
err = err || ordered_commit();
|
||||||
err = err || after_commit();
|
err = err || after_commit();
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
rollback();
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -223,10 +223,10 @@ namespace wsrep
|
|||||||
return transaction_.start_transaction(wsh, meta);
|
return transaction_.start_transaction(wsh, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_replaying()
|
int start_replaying(const wsrep::ws_meta& ws_meta)
|
||||||
{
|
{
|
||||||
assert(mode_ == m_applier);
|
assert(mode_ == m_applier);
|
||||||
return transaction_.start_replaying();
|
return transaction_.start_replaying(ws_meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void adopt_transaction(wsrep::transaction_context& transaction)
|
void adopt_transaction(wsrep::transaction_context& transaction)
|
||||||
@ -483,7 +483,8 @@ namespace wsrep
|
|||||||
/*!
|
/*!
|
||||||
* Replay the transaction.
|
* Replay the transaction.
|
||||||
*/
|
*/
|
||||||
virtual int replay(wsrep::transaction_context& tc) = 0;
|
virtual enum wsrep::provider::status
|
||||||
|
replay(wsrep::transaction_context& tc) = 0;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -243,7 +243,8 @@ namespace wsrep
|
|||||||
*
|
*
|
||||||
* @return Zero in case of success, non-zero on failure.
|
* @return Zero in case of success, non-zero on failure.
|
||||||
*/
|
*/
|
||||||
virtual int replay(wsrep::ws_handle& ws_handle, void* applier_ctx) = 0;
|
virtual enum status replay(
|
||||||
|
wsrep::ws_handle& ws_handle, void* applier_ctx) = 0;
|
||||||
|
|
||||||
virtual int sst_sent(const wsrep::gtid&, int) = 0;
|
virtual int sst_sent(const wsrep::gtid&, int) = 0;
|
||||||
virtual int sst_received(const wsrep::gtid&, int) = 0;
|
virtual int sst_received(const wsrep::gtid&, int) = 0;
|
||||||
|
@ -85,7 +85,7 @@ namespace wsrep
|
|||||||
int start_transaction(const wsrep::ws_handle& ws_handle,
|
int start_transaction(const wsrep::ws_handle& ws_handle,
|
||||||
const wsrep::ws_meta& ws_meta);
|
const wsrep::ws_meta& ws_meta);
|
||||||
|
|
||||||
int start_replaying();
|
int start_replaying(const wsrep::ws_meta&);
|
||||||
|
|
||||||
int append_key(const wsrep::key&);
|
int append_key(const wsrep::key&);
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ int wsrep::server_context::on_apply(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client_context.start_replaying();
|
client_context.start_replaying(ws_meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_context.apply(data))
|
if (client_context.apply(data))
|
||||||
@ -251,7 +251,7 @@ int wsrep::server_context::on_apply(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = client_context.start_replaying() ||
|
ret = client_context.start_replaying(ws_meta) ||
|
||||||
client_context.apply(wsrep::const_buffer()) ||
|
client_context.apply(wsrep::const_buffer()) ||
|
||||||
client_context.commit();
|
client_context.commit();
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,9 @@ int wsrep::transaction_context::start_transaction(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wsrep::transaction_context::start_replaying()
|
int wsrep::transaction_context::start_replaying(const wsrep::ws_meta& ws_meta)
|
||||||
{
|
{
|
||||||
|
ws_meta_ = ws_meta;
|
||||||
assert(ws_meta_.flags() & wsrep::provider::flag::commit);
|
assert(ws_meta_.flags() & wsrep::provider::flag::commit);
|
||||||
assert(active());
|
assert(active());
|
||||||
assert(client_context_.mode() == wsrep::client_context::m_applier);
|
assert(client_context_.mode() == wsrep::client_context::m_applier);
|
||||||
@ -506,12 +507,32 @@ int wsrep::transaction_context::after_statement()
|
|||||||
// Continue to replay if rollback() changed the state to s_must_replay
|
// Continue to replay if rollback() changed the state to s_must_replay
|
||||||
// Fall through
|
// Fall through
|
||||||
case s_must_replay:
|
case s_must_replay:
|
||||||
|
{
|
||||||
state(lock, s_replaying);
|
state(lock, s_replaying);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
ret = client_context_.replay(*this);
|
enum wsrep::provider::status replay_ret(client_context_.replay(*this));
|
||||||
|
switch (replay_ret)
|
||||||
|
{
|
||||||
|
case wsrep::provider::success:
|
||||||
|
break;
|
||||||
|
case wsrep::provider::error_certification_failed:
|
||||||
|
client_context_.override_error(
|
||||||
|
wsrep::e_deadlock_error);
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
client_context_.abort();
|
||||||
|
break;
|
||||||
|
}
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
wsrep::log_info() << "Replay ret " << replay_ret;
|
||||||
|
state(lock, s_aborted);
|
||||||
|
}
|
||||||
provider_.release(ws_handle_);
|
provider_.release(ws_handle_);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case s_aborted:
|
case s_aborted:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -650,7 +671,7 @@ void wsrep::transaction_context::state(
|
|||||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, /* ab */
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, /* ab */
|
||||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* ad */
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* ad */
|
||||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* mr */
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* mr */
|
||||||
{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0} /* re */
|
{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0} /* re */
|
||||||
};
|
};
|
||||||
if (allowed[state_][next_state])
|
if (allowed[state_][next_state])
|
||||||
{
|
{
|
||||||
@ -852,7 +873,6 @@ int wsrep::transaction_context::certify_commit(
|
|||||||
// yet known. Therefore the transaction must roll back
|
// yet known. Therefore the transaction must roll back
|
||||||
// and go through replay either to replay and commit the whole
|
// and go through replay either to replay and commit the whole
|
||||||
// transaction or to determine failed certification status.
|
// transaction or to determine failed certification status.
|
||||||
assert(ordered());
|
|
||||||
client_context_.will_replay(*this);
|
client_context_.will_replay(*this);
|
||||||
if (state() != s_must_abort)
|
if (state() != s_must_abort)
|
||||||
{
|
{
|
||||||
|
@ -548,11 +548,13 @@ int wsrep::wsrep_provider_v26::release(wsrep::ws_handle& ws_handle)
|
|||||||
return (wsrep_->release(wsrep_, mwsh.native()) != WSREP_OK);
|
return (wsrep_->release(wsrep_, mwsh.native()) != WSREP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wsrep::wsrep_provider_v26::replay(wsrep::ws_handle& ws_handle,
|
enum wsrep::provider::status
|
||||||
void* applier_ctx)
|
wsrep::wsrep_provider_v26::replay(wsrep::ws_handle& ws_handle,
|
||||||
|
void* applier_ctx)
|
||||||
{
|
{
|
||||||
mutable_ws_handle mwsh(ws_handle);
|
mutable_ws_handle mwsh(ws_handle);
|
||||||
return (wsrep_->replay_trx(wsrep_, mwsh.native(), applier_ctx) != WSREP_OK);
|
return map_return_value(
|
||||||
|
wsrep_->replay_trx(wsrep_, mwsh.native(), applier_ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
int wsrep::wsrep_provider_v26::sst_sent(const wsrep::gtid& gtid, int err)
|
int wsrep::wsrep_provider_v26::sst_sent(const wsrep::gtid& gtid, int err)
|
||||||
|
@ -41,7 +41,7 @@ namespace wsrep
|
|||||||
int commit_order_leave(const wsrep::ws_handle&,
|
int commit_order_leave(const wsrep::ws_handle&,
|
||||||
const wsrep::ws_meta&);
|
const wsrep::ws_meta&);
|
||||||
int release(wsrep::ws_handle&);
|
int release(wsrep::ws_handle&);
|
||||||
int replay(wsrep::ws_handle&, void*);
|
enum wsrep::provider::status replay(wsrep::ws_handle&, void*);
|
||||||
int sst_sent(const wsrep::gtid&,int);
|
int sst_sent(const wsrep::gtid&,int);
|
||||||
int sst_received(const wsrep::gtid& gtid, int);
|
int sst_received(const wsrep::gtid& gtid, int);
|
||||||
|
|
||||||
|
@ -55,9 +55,11 @@ namespace wsrep
|
|||||||
void remove_fragments(const wsrep::transaction_context& )
|
void remove_fragments(const wsrep::transaction_context& )
|
||||||
WSREP_OVERRIDE { }
|
WSREP_OVERRIDE { }
|
||||||
void will_replay(wsrep::transaction_context&) WSREP_OVERRIDE { }
|
void will_replay(wsrep::transaction_context&) WSREP_OVERRIDE { }
|
||||||
int replay(wsrep::transaction_context& tc) WSREP_OVERRIDE
|
enum wsrep::provider::status
|
||||||
|
replay(wsrep::transaction_context& tc) WSREP_OVERRIDE
|
||||||
{
|
{
|
||||||
int ret(provider().replay(tc.ws_handle(), this));
|
enum wsrep::provider::status ret(
|
||||||
|
provider().replay(tc.ws_handle(), this));
|
||||||
++replays_;
|
++replays_;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ namespace wsrep
|
|||||||
, commit_order_enter_result_()
|
, commit_order_enter_result_()
|
||||||
, commit_order_leave_result_()
|
, commit_order_leave_result_()
|
||||||
, release_result_()
|
, release_result_()
|
||||||
|
, replay_result_()
|
||||||
, group_id_("1")
|
, group_id_("1")
|
||||||
, server_id_("1")
|
, server_id_("1")
|
||||||
, group_seqno_(0)
|
, group_seqno_(0)
|
||||||
@ -138,14 +139,43 @@ namespace wsrep
|
|||||||
int release(wsrep::ws_handle&)
|
int release(wsrep::ws_handle&)
|
||||||
{ return release_result_; }
|
{ return release_result_; }
|
||||||
|
|
||||||
int replay(wsrep::ws_handle&, void* ctx)
|
enum wsrep::provider::status replay(wsrep::ws_handle&, void* ctx)
|
||||||
{
|
{
|
||||||
wsrep::mock_client_context& cc(
|
wsrep::mock_client_context& cc(
|
||||||
*static_cast<wsrep::mock_client_context*>(ctx));
|
*static_cast<wsrep::mock_client_context*>(ctx));
|
||||||
wsrep::client_applier_mode applier_mode(cc);
|
wsrep::client_applier_mode applier_mode(cc);
|
||||||
const wsrep::transaction_context& tc(cc.transaction());
|
const wsrep::transaction_context& tc(cc.transaction());
|
||||||
return server_context_.on_apply(cc, tc.ws_handle(), tc.ws_meta(),
|
wsrep::ws_meta ws_meta;
|
||||||
wsrep::const_buffer());
|
if (replay_result_ == wsrep::provider::success)
|
||||||
|
{
|
||||||
|
// If the ws_meta was not assigned yet, the certify
|
||||||
|
// returned early due to BF abort.
|
||||||
|
if (tc.ws_meta().seqno().nil())
|
||||||
|
{
|
||||||
|
++group_seqno_;
|
||||||
|
ws_meta = wsrep::ws_meta(
|
||||||
|
wsrep::gtid(group_id_, wsrep::seqno(group_seqno_)),
|
||||||
|
wsrep::stid(server_id_, tc.id(), cc.id()),
|
||||||
|
wsrep::seqno(group_seqno_ - 1),
|
||||||
|
wsrep::provider::flag::start_transaction |
|
||||||
|
wsrep::provider::flag::commit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ws_meta = tc.ws_meta();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return replay_result_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server_context_.on_apply(cc, tc.ws_handle(), ws_meta,
|
||||||
|
wsrep::const_buffer()))
|
||||||
|
{
|
||||||
|
return wsrep::provider::error_fatal;
|
||||||
|
}
|
||||||
|
return wsrep::provider::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sst_sent(const wsrep::gtid&, int) { return 0; }
|
int sst_sent(const wsrep::gtid&, int) { return 0; }
|
||||||
@ -183,6 +213,7 @@ namespace wsrep
|
|||||||
enum wsrep::provider::status commit_order_enter_result_;
|
enum wsrep::provider::status commit_order_enter_result_;
|
||||||
enum wsrep::provider::status commit_order_leave_result_;
|
enum wsrep::provider::status commit_order_leave_result_;
|
||||||
enum wsrep::provider::status release_result_;
|
enum wsrep::provider::status release_result_;
|
||||||
|
enum wsrep::provider::status replay_result_;
|
||||||
|
|
||||||
size_t start_fragments() const { return start_fragments_; }
|
size_t start_fragments() const { return start_fragments_; }
|
||||||
size_t fragments() const { return fragments_; }
|
size_t fragments() const { return fragments_; }
|
||||||
|
@ -307,6 +307,45 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(
|
|||||||
BOOST_REQUIRE(cc.current_error());
|
BOOST_REQUIRE(cc.current_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Test a transaction which gets BF aborted inside provider before
|
||||||
|
// certification result is known. Replaying will be successful
|
||||||
|
//
|
||||||
|
BOOST_FIXTURE_TEST_CASE(
|
||||||
|
transaction_context_bf_before_cert_result_replay_success,
|
||||||
|
replicating_client_fixture_sync_rm)
|
||||||
|
{
|
||||||
|
BOOST_REQUIRE(cc.start_transaction(1) == 0);
|
||||||
|
sc.provider().certify_result_ = wsrep::provider::error_bf_abort;
|
||||||
|
sc.provider().replay_result_ = wsrep::provider::success;
|
||||||
|
|
||||||
|
BOOST_REQUIRE(cc.before_commit());
|
||||||
|
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay);
|
||||||
|
BOOST_REQUIRE(cc.after_statement() == 0);
|
||||||
|
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_committed);
|
||||||
|
BOOST_REQUIRE(cc.current_error() == wsrep::e_success);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Test a transaction which gets BF aborted inside provider before
|
||||||
|
// certification result is known. Replaying will fail because of
|
||||||
|
// certification failure.
|
||||||
|
//
|
||||||
|
BOOST_FIXTURE_TEST_CASE(
|
||||||
|
transaction_context_bf_before_cert_result_replay_cert_fail,
|
||||||
|
replicating_client_fixture_sync_rm)
|
||||||
|
{
|
||||||
|
BOOST_REQUIRE(cc.start_transaction(1) == 0);
|
||||||
|
sc.provider().certify_result_ = wsrep::provider::error_bf_abort;
|
||||||
|
sc.provider().replay_result_ = wsrep::provider::error_certification_failed;
|
||||||
|
|
||||||
|
BOOST_REQUIRE(cc.before_commit());
|
||||||
|
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_must_replay);
|
||||||
|
BOOST_REQUIRE(cc.after_statement() == wsrep::client_context::asr_error);
|
||||||
|
BOOST_REQUIRE(tc.state() == wsrep::transaction_context::s_aborted);
|
||||||
|
BOOST_REQUIRE(cc.current_error() == wsrep::e_deadlock_error);
|
||||||
|
BOOST_REQUIRE(tc.active() == false);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Test a 1PC transaction which gets BF aborted during before_commit via
|
// Test a 1PC transaction which gets BF aborted during before_commit via
|
||||||
|
Loading…
x
Reference in New Issue
Block a user