Skip to content

Commit 6467f70

Browse files
committed
BUG#36093405: Signal 11 seen in Gtid_set::~Gtid_set
Group Replication maintains a memory structure that keeps track of transactions accepted to commit but not committed on all members yet. This structure, named certification info, is used to detect conflicts and dependencies between transactions. The certification info is cleaned periodically and on Group Replication stop. There was a race identified between these two operations, more precisely: 1) Certifier::garbage_collect() -> while (it != certification_info.end()) { if (it->second->is_subset_not_equals(stable_gtid_set)) { if (it->second->unlink() == 0) delete it->second; 2) Certifier::~Certifier() -> clear_certification_info(); -> for (Certification_info::iterator it = certification_info.begin(); it != certification_info.end(); ++it) { if (it->second->unlink() == 0) delete it->second; `clear_certification_info()` was being called without securing exclusive access to `certification_info` which could cause concurrent access to its items, more precisely `delete it->second`. To solve the above issue, `~Certifier()` (like all other callers) do secure the exclusive access to certification info. Change-Id: I28111d41adb54248d90137ee9d2c17196de045e8
1 parent a365624 commit 6467f70

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

plugin/group_replication/include/certifier.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <assert.h>
2727
#include <mysql/group_replication_priv.h>
28+
#include <atomic>
2829
#include <list>
2930
#include <map>
3031
#include <string>
@@ -423,7 +424,7 @@ class Certifier : public Certifier_interface {
423424
/**
424425
Is certifier initialized.
425426
*/
426-
bool initialized;
427+
std::atomic<bool> initialized{false};
427428

428429
/**
429430
Variable to store the sidno used for transactions which will be logged

plugin/group_replication/src/certifier.cc

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,19 @@ Certifier::Certifier()
300300
}
301301

302302
Certifier::~Certifier() {
303+
mysql_mutex_lock(&LOCK_certification_info);
304+
initialized = false;
303305
clear_certification_info();
304306
delete certification_info_sid_map;
305307

306308
delete stable_gtid_set;
307309
delete stable_sid_map;
308310
delete stable_gtid_set_lock;
309-
delete broadcast_thread;
310311
delete group_gtid_executed;
311312
delete group_gtid_extracted;
312313
delete group_gtid_sid_map;
314+
mysql_mutex_unlock(&LOCK_certification_info);
315+
delete broadcast_thread;
313316

314317
mysql_mutex_lock(&LOCK_members);
315318
clear_members();
@@ -566,6 +569,7 @@ void Certifier::add_to_group_gtid_executed_internal(rpl_sidno sidno,
566569
}
567570

568571
void Certifier::clear_certification_info() {
572+
mysql_mutex_assert_owner(&LOCK_certification_info);
569573
for (Certification_info::iterator it = certification_info.begin();
570574
it != certification_info.end(); ++it) {
571575
// We can only delete the last reference.
@@ -926,6 +930,10 @@ rpl_gno Certifier::certify(Gtid_set *snapshot_version,
926930
int Certifier::add_specified_gtid_to_group_gtid_executed(Gtid_log_event *gle) {
927931
DBUG_TRACE;
928932

933+
if (!is_initialized()) {
934+
return 1;
935+
}
936+
929937
mysql_mutex_lock(&LOCK_certification_info);
930938
rpl_sidno sidno = gle->get_sidno(group_gtid_sid_map);
931939

@@ -951,6 +959,11 @@ int Certifier::add_specified_gtid_to_group_gtid_executed(Gtid_log_event *gle) {
951959

952960
int Certifier::add_group_gtid_to_group_gtid_executed(rpl_gno gno) {
953961
DBUG_TRACE;
962+
963+
if (!is_initialized()) {
964+
return 1;
965+
}
966+
954967
mysql_mutex_lock(&LOCK_certification_info);
955968
add_to_group_gtid_executed_internal(group_gtid_sid_map_group_sidno, gno);
956969
mysql_mutex_unlock(&LOCK_certification_info);
@@ -1159,6 +1172,10 @@ int Certifier::get_group_stable_transactions_set_string(char **buffer,
11591172
DBUG_TRACE;
11601173
int error = 1;
11611174

1175+
if (!is_initialized()) {
1176+
return 1;
1177+
}
1178+
11621179
/*
11631180
Stable transactions set may not be accurate during recovery,
11641181
thence we do not externalize it on
@@ -1208,6 +1225,11 @@ bool Certifier::set_group_stable_transactions_set(Gtid_set *executed_gtid_set) {
12081225

12091226
void Certifier::garbage_collect() {
12101227
DBUG_TRACE;
1228+
1229+
if (!is_initialized()) {
1230+
return;
1231+
}
1232+
12111233
/*
12121234
This debug option works together with
12131235
`group_replication_certifier_broadcast_thread_big_period`
@@ -1484,6 +1506,11 @@ int Certifier::stable_set_handle() {
14841506

14851507
void Certifier::handle_view_change() {
14861508
DBUG_TRACE;
1509+
1510+
if (!is_initialized()) {
1511+
return;
1512+
}
1513+
14871514
mysql_mutex_lock(&LOCK_members);
14881515
clear_incoming();
14891516
clear_members();
@@ -1493,6 +1520,11 @@ void Certifier::handle_view_change() {
14931520
void Certifier::get_certification_info(
14941521
std::map<std::string, std::string> *cert_info) {
14951522
DBUG_TRACE;
1523+
1524+
if (!is_initialized()) {
1525+
return;
1526+
}
1527+
14961528
mysql_mutex_lock(&LOCK_certification_info);
14971529

14981530
for (Certification_info::iterator it = certification_info.begin();
@@ -1524,6 +1556,10 @@ void Certifier::get_certification_info(
15241556
Gtid Certifier::generate_view_change_group_gtid() {
15251557
DBUG_TRACE;
15261558

1559+
if (!is_initialized()) {
1560+
return {-1, -1};
1561+
}
1562+
15271563
mysql_mutex_lock(&LOCK_certification_info);
15281564
rpl_gno result =
15291565
get_next_available_gtid(nullptr, views_sidno_group_representation);
@@ -1544,6 +1580,10 @@ int Certifier::set_certification_info(
15441580
DBUG_TRACE;
15451581
assert(cert_info != nullptr);
15461582

1583+
if (!is_initialized()) {
1584+
return 1;
1585+
}
1586+
15471587
if (cert_info->size() == 1) {
15481588
std::map<std::string, std::string>::iterator it =
15491589
cert_info->find(CERTIFICATION_INFO_ERROR_NAME);
@@ -1674,6 +1714,10 @@ void Certifier::get_last_conflict_free_transaction(std::string *value) {
16741714
int length = 0;
16751715
char buffer[Gtid::MAX_TEXT_LENGTH + 1];
16761716

1717+
if (!is_initialized()) {
1718+
return;
1719+
}
1720+
16771721
mysql_mutex_lock(&LOCK_certification_info);
16781722
if (last_conflict_free_transaction.is_empty()) goto end;
16791723

@@ -1687,6 +1731,10 @@ void Certifier::get_last_conflict_free_transaction(std::string *value) {
16871731
void Certifier::enable_conflict_detection() {
16881732
DBUG_TRACE;
16891733

1734+
if (!is_initialized()) {
1735+
return;
1736+
}
1737+
16901738
mysql_mutex_lock(&LOCK_certification_info);
16911739
conflict_detection_enable = true;
16921740
local_member_info->enable_conflict_detection();
@@ -1697,6 +1745,10 @@ void Certifier::disable_conflict_detection() {
16971745
DBUG_TRACE;
16981746
assert(local_member_info->in_primary_mode());
16991747

1748+
if (!is_initialized()) {
1749+
return;
1750+
}
1751+
17001752
mysql_mutex_lock(&LOCK_certification_info);
17011753
conflict_detection_enable = false;
17021754
local_member_info->disable_conflict_detection();
@@ -1708,6 +1760,10 @@ void Certifier::disable_conflict_detection() {
17081760
bool Certifier::is_conflict_detection_enable() {
17091761
DBUG_TRACE;
17101762

1763+
if (!is_initialized()) {
1764+
return false;
1765+
}
1766+
17111767
mysql_mutex_lock(&LOCK_certification_info);
17121768
bool result = conflict_detection_enable;
17131769
mysql_mutex_unlock(&LOCK_certification_info);

0 commit comments

Comments
 (0)