Skip to content

Commit b76e94f

Browse files
committed
Transaction not immune after becoming ordered for commit
The transaction state is set to s_ordered_commit in ordered_commit(). However, this is too late for making the transaction immune for BF aborts after commit order has been established, which happens in before_commit(). Moving the state change into before_commit() would be the right thing to do, but that would require too many fixes to existing applications which are using the lib. In order to make the transaction immune for BF abort after it has been ordered to commit, introduce additional boolean flag which is set to true at the end of before_commit() and is taken into account in bf_abort().
1 parent d2f27ba commit b76e94f

File tree

3 files changed

+67
-7
lines changed

3 files changed

+67
-7
lines changed

include/wsrep/transaction.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "buffer.hpp"
3030
#include "xid.hpp"
3131

32+
#include <iosfwd>
3233
#include <vector>
3334

3435
namespace wsrep
@@ -281,6 +282,14 @@ namespace wsrep
281282
wsrep::mutable_buffer apply_error_buf_;
282283
wsrep::xid xid_;
283284
bool streaming_rollback_in_progress_;
285+
/* This flag tells that the transaction has become immutable
286+
against BF aborts. Ideally this would be deduced from transaction
287+
state, i.e. s_ordered_commit or s_committed, but the current
288+
version of wsrep-lib changes the transaction state to
289+
s_ordered_commit too late. Fixing this appears to require
290+
too many changes to application using the lib, so boolean flag
291+
must do. */
292+
bool is_bf_immutable_;
284293
};
285294

286295
static inline const char* to_c_string(enum wsrep::transaction::state state)
@@ -308,6 +317,8 @@ namespace wsrep
308317
return to_c_string(state);
309318
}
310319

320+
std::ostream& operator<<(std::ostream& os, enum wsrep::transaction::state);
321+
311322
}
312323

313324
#endif // WSREP_TRANSACTION_HPP

src/transaction.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ wsrep::transaction::transaction(
112112
, apply_error_buf_()
113113
, xid_()
114114
, streaming_rollback_in_progress_(false)
115+
, is_bf_immutable_(false)
115116
{ }
116117

117118

@@ -555,6 +556,12 @@ int wsrep::transaction::before_commit()
555556
assert(0);
556557
break;
557558
}
559+
560+
if (ret == 0 && state() == s_committing)
561+
{
562+
is_bf_immutable_ = true;
563+
}
564+
558565
debug_log_state("before_commit_leave");
559566
return ret;
560567
}
@@ -564,6 +571,7 @@ int wsrep::transaction::ordered_commit()
564571
wsrep::unique_lock<wsrep::mutex> lock(client_state_.mutex());
565572
debug_log_state("ordered_commit_enter");
566573
assert(state() == s_committing);
574+
assert(is_bf_immutable_);
567575
assert(ordered());
568576
client_service_.debug_sync("wsrep_before_commit_order_leave");
569577
int ret(provider().commit_order_leave(ws_handle_, ws_meta_,
@@ -602,6 +610,7 @@ int wsrep::transaction::after_commit()
602610
int ret(0);
603611

604612
wsrep::unique_lock<wsrep::mutex> lock(client_state_.mutex());
613+
assert(is_bf_immutable_);
605614
debug_log_state("after_commit_enter");
606615
assert(state() == s_ordered_commit);
607616

@@ -639,7 +648,7 @@ int wsrep::transaction::after_commit()
639648
}
640649
assert(ret == 0);
641650
state(lock, s_committed);
642-
651+
is_bf_immutable_ = false;
643652
debug_log_state("after_commit_leave");
644653
return ret;
645654
}
@@ -819,6 +828,7 @@ int wsrep::transaction::after_statement()
819828
state() == s_must_abort ||
820829
state() == s_cert_failed ||
821830
state() == s_must_replay);
831+
assert(not is_bf_immutable_);
822832

823833
if (state() == s_executing &&
824834
streaming_context_.fragment_size() &&
@@ -981,6 +991,12 @@ bool wsrep::transaction::bf_abort(
981991
wsrep::log::debug_level_transaction,
982992
"Transaction not active, skipping bf abort");
983993
}
994+
else if (is_bf_immutable_)
995+
{
996+
WSREP_LOG_DEBUG(client_state_.debug_log_level(),
997+
wsrep::log::debug_level_transaction,
998+
"Transaction has become immutable for BF abort");
999+
}
9841000
else
9851001
{
9861002
switch (state_at_enter)
@@ -2139,3 +2155,9 @@ void wsrep::transaction::debug_log_key_append(const wsrep::key& key) const
21392155
<< int64_t(id().get())
21402156
<< " append key:\n" << key);
21412157
}
2158+
2159+
std::ostream& wsrep::operator<<(std::ostream& os,
2160+
enum wsrep::transaction::state state)
2161+
{
2162+
return (os << to_c_string(state));
2163+
}

test/transaction_test.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,32 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(
289289
BOOST_REQUIRE(not cc.current_error());
290290
}
291291

292+
BOOST_FIXTURE_TEST_CASE(
293+
transaction_1pc_bf_after_before_commit,
294+
replicating_client_fixture_async_rm)
295+
{
296+
// Start a new transaction with ID 1
297+
cc.start_transaction(wsrep::transaction_id(1));
298+
BOOST_REQUIRE(tc.active());
299+
BOOST_REQUIRE(tc.id() == wsrep::transaction_id(1));
300+
BOOST_REQUIRE(tc.state() == wsrep::transaction::s_executing);
301+
302+
// Run before commit
303+
BOOST_REQUIRE(cc.before_commit() == 0);
304+
BOOST_REQUIRE_EQUAL(tc.state(), wsrep::transaction::s_committing);
305+
BOOST_REQUIRE(tc.certified() == true);
306+
BOOST_REQUIRE(tc.ordered() == true);
307+
308+
wsrep_test::bf_abort_ordered(cc);
309+
BOOST_REQUIRE_EQUAL(tc.state(), wsrep::transaction::s_committing);
310+
311+
// Clean up
312+
cc.ordered_commit();
313+
cc.after_commit();
314+
cc.after_statement();
315+
}
316+
317+
292318
//
293319
// Test a 1PC transaction for which prepare data fails
294320
//
@@ -1491,16 +1517,17 @@ BOOST_FIXTURE_TEST_CASE(transaction_row_streaming_cert_fail_commit,
14911517
//
14921518
// Test streaming BF abort after succesful certification
14931519
//
1494-
BOOST_FIXTURE_TEST_CASE(transaction_row_streaming_bf_abort_committing,
1495-
streaming_client_fixture_row)
1520+
BOOST_FIXTURE_TEST_CASE(
1521+
transaction_row_streaming_bf_abort_during_commit_order_enter,
1522+
streaming_client_fixture_row)
14961523
{
14971524
BOOST_REQUIRE(cc.start_transaction(wsrep::transaction_id(1)) == 0);
14981525
BOOST_REQUIRE(cc.after_row() == 0);
14991526
BOOST_REQUIRE(tc.streaming_context().fragments_certified() == 1);
1500-
BOOST_REQUIRE(cc.before_commit() == 0);
1501-
BOOST_REQUIRE(tc.state() == wsrep::transaction::s_committing);
1502-
wsrep_test::bf_abort_ordered(cc);
1503-
BOOST_REQUIRE(tc.state() == wsrep::transaction::s_must_abort);
1527+
sc.provider().commit_order_enter_result_ = wsrep::provider::error_bf_abort;
1528+
BOOST_REQUIRE(cc.before_commit());
1529+
BOOST_REQUIRE_EQUAL(tc.state(), wsrep::transaction::s_must_replay);
1530+
sc.provider().commit_order_enter_result_ = wsrep::provider::success;
15041531
BOOST_REQUIRE(cc.before_rollback() == 0);
15051532
BOOST_REQUIRE(cc.after_rollback() == 0);
15061533
BOOST_REQUIRE(tc.state() == wsrep::transaction::s_must_replay);

0 commit comments

Comments
 (0)