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

Fixed streaming transaction BF abort

The streaming_rollback() was not called from transaction::bf_abort()
if a streaming transaction was BF aborted in executing state. This
was because the condition to enter streaming_rollback() checked
if the transaction state is executing. However, the transaction
state had already been changed to must_abort before.

As a fix, save the state to local variable when entering
bf_abort() and check against saved state in condition to enter
streaming_rollback().

Added unit test for the correct behavior in the case when streaming
transaction is BF aborted in executing state.

Silenced warning about failing to replicate rollback fragment.
This is pretty normal condition and may happen during shutdown/
configuration changes when SR transactions are rolled back.
This commit is contained in:
Teemu Ollakka
2019-02-19 11:08:11 +02:00
parent 0b09871ad5
commit ab0e5f5d77
2 changed files with 28 additions and 5 deletions

View File

@ -816,10 +816,11 @@ void wsrep::transaction::after_applying()
}
bool wsrep::transaction::bf_abort(
wsrep::unique_lock<wsrep::mutex>& lock WSREP_UNUSED,
wsrep::unique_lock<wsrep::mutex>& lock,
wsrep::seqno bf_seqno)
{
bool ret(false);
enum wsrep::transaction::state prev_state(state());
assert(lock.owns_lock());
if (active() == false)
@ -883,7 +884,7 @@ bool wsrep::transaction::bf_abort(
// storage engine operations and streaming rollback will be
// handled from before_rollback() call.
if (client_state_.mode() == wsrep::client_state::m_local &&
is_streaming() && state() == s_executing)
is_streaming() && prev_state == s_executing)
{
streaming_rollback(lock);
}
@ -1461,15 +1462,19 @@ void wsrep::transaction::streaming_rollback(wsrep::unique_lock<wsrep::mutex>& lo
debug_log_state("streaming_rollback enter");
assert(state_ != s_must_replay);
assert(is_streaming());
if (streaming_context_.rolled_back() == false)
{
// We must set rolled_back id before stopping streaming client
// or converting to applier. Accessing server_state requires
// releasing the client_state lock in order to avoid violating
// locking order, and this will open up a possibility for two
// threads accessing this block simultaneously.
streaming_context_.rolled_back(id_);
if (bf_aborted_in_total_order_)
{
lock.unlock();
client_state_.server_state_.stop_streaming_client(&client_state_);
lock.lock();
streaming_context_.rolled_back(id_);
}
else
{
@ -1483,11 +1488,14 @@ void wsrep::transaction::streaming_rollback(wsrep::unique_lock<wsrep::mutex>& lo
&client_state_);
lock.lock();
streaming_context_.cleanup();
// Cleanup cleans rolled_back_for from streaming context, but
// we want to preserve it to avoid executing this block
// more than once.
streaming_context_.rolled_back(id_);
enum wsrep::provider::status ret;
if ((ret = provider().rollback(id_)))
{
wsrep::log_warning()
wsrep::log_debug()
<< "Failed to replicate rollback fragment for "
<< id_ << ": " << ret;
}