Skip to content

Commit 5b4d589

Browse files
nacarvalhodahlerlend
authored andcommitted
BUG#37644518: Race condition on rpl_opt_tracker
A race condition was found on `Rpl_opt_tracker` that can make instance pointers invalid. The scenario is: 1) `Rpl_opt_tracker::worker()` calls `acquire_option_tracker_service()`; 2) Concurrently `Rpl_opt_tracker::track_replication_replica()` is called, which calls `acquire_option_tracker_service()` again and then calls `release_option_tracker_service()`. This results in one service reference lost, `m_option_tracker_handle` is overridden, and the invalidation of `m_option_tracker_service`, which will cause a server error on the next steps of `Rpl_opt_tracker::worker()`. To solve the above issue, the helper methods were refactored to use a guard that handles the service acquire/release on the methods that interact with the service. Change-Id: I433d4ef0009b33ac2319943a4defd9ec22d89a23
1 parent 5e59db6 commit 5b4d589

File tree

2 files changed

+55
-68
lines changed

2 files changed

+55
-68
lines changed

sql/rpl_opt_tracker.cc

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -95,25 +95,6 @@ Rpl_opt_tracker::~Rpl_opt_tracker() {
9595
});
9696
}
9797

98-
bool Rpl_opt_tracker::acquire_option_tracker_service() {
99-
if (srv_registry->acquire("mysql_option_tracker_option",
100-
&m_option_tracker_handle)) {
101-
return true;
102-
}
103-
m_option_tracker_service =
104-
reinterpret_cast<SERVICE_TYPE(mysql_option_tracker_option) *>(
105-
m_option_tracker_handle);
106-
return false;
107-
}
108-
109-
void Rpl_opt_tracker::release_option_tracker_service() {
110-
m_option_tracker_service = nullptr;
111-
if (nullptr != m_option_tracker_handle) {
112-
srv_registry->release(m_option_tracker_handle);
113-
m_option_tracker_handle = nullptr;
114-
}
115-
}
116-
11798
bool Rpl_opt_tracker::is_replication_replica_enabled() {
11899
bool replication_replica_enabled = false;
119100

@@ -129,31 +110,32 @@ bool Rpl_opt_tracker::is_replication_replica_enabled() {
129110
return replication_replica_enabled;
130111
}
131112

132-
void Rpl_opt_tracker::track_binary_log_internal(bool enabled) {
133-
m_option_tracker_service->set_enabled(s_f_name_binary_log.c_str(),
134-
enabled ? 1 : 0);
135-
136-
if (enabled) {
137-
++m_opt_option_tracker_usage_binary_log;
113+
void Rpl_opt_tracker::track(Tracker_service_guard &service_guard, bool enabled,
114+
const std::string &fname,
115+
unsigned long long &usage_counter) {
116+
if (service_guard.is_valid()) {
117+
service_guard->set_enabled(fname.c_str(), enabled ? 1 : 0);
118+
if (enabled) {
119+
++usage_counter;
120+
}
138121
}
139122
}
140123

141-
void Rpl_opt_tracker::track_replication_replica(bool enabled) {
142-
if (acquire_option_tracker_service()) {
143-
return;
144-
}
145-
146-
track_replication_replica_internal(enabled);
147-
release_option_tracker_service();
124+
void Rpl_opt_tracker::track_binary_log(Tracker_service_guard &service_guard,
125+
bool enabled) const {
126+
track(service_guard, enabled, s_f_name_binary_log,
127+
m_opt_option_tracker_usage_binary_log);
148128
}
149129

150-
void Rpl_opt_tracker::track_replication_replica_internal(bool enabled) {
151-
m_option_tracker_service->set_enabled(s_f_name_replication_replica.c_str(),
152-
enabled ? 1 : 0);
130+
void Rpl_opt_tracker::track_replication_replica(
131+
Tracker_service_guard &service_guard, bool enabled) const {
132+
track(service_guard, enabled, s_f_name_replication_replica,
133+
m_opt_option_tracker_usage_replication_replica);
134+
}
153135

154-
if (enabled) {
155-
++m_opt_option_tracker_usage_replication_replica;
156-
}
136+
void Rpl_opt_tracker::track_replication_replica(bool enabled) const {
137+
Tracker_service_guard service_guard(m_service_name, srv_registry);
138+
track_replication_replica(service_guard, enabled);
157139
}
158140

159141
void Rpl_opt_tracker::worker() {
@@ -172,19 +154,19 @@ void Rpl_opt_tracker::worker() {
172154
Only track features if the option tracker service is
173155
installed.
174156
*/
175-
if (!acquire_option_tracker_service()) {
157+
{
158+
Tracker_service_guard service_guard(m_service_name, srv_registry);
159+
176160
/*
177161
Binary Log
178162
*/
179-
rpl_opt_tracker->track_binary_log_internal(opt_bin_log);
163+
track_binary_log(service_guard, opt_bin_log);
180164

181165
/*
182166
Replication Replica
183167
*/
184-
rpl_opt_tracker->track_replication_replica_internal(
185-
is_replication_replica_enabled());
186-
187-
release_option_tracker_service();
168+
track_replication_replica(service_guard,
169+
is_replication_replica_enabled());
188170
}
189171

190172
mysql_mutex_lock(&LOCK_rpl_opt_tracker);

sql/rpl_opt_tracker.h

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <my_systime.h>
2828
#include <mysql/components/minimal_chassis.h>
29+
#include <mysql/components/my_service.h>
2930
#include <mysql/components/services/bits/psi_thread_bits.h>
3031
#include <mysql/components/services/mysql_option_tracker.h>
3132
#include <string>
@@ -70,19 +71,12 @@ class Rpl_opt_tracker {
7071
@param enabled true: tracks as enabled
7172
false: tracks as disabled
7273
*/
73-
void track_replication_replica(bool enabled);
74+
void track_replication_replica(bool enabled) const;
7475

7576
private:
76-
/**
77-
Tracks the Binary Log feature, including the usage data.
78-
It only updates usage data if the feature is enabled.
79-
Internal method to be used after the mysql_option_tracker_option
80-
service is acquired.
81-
82-
@param enabled true: tracks as enabled
83-
false: tracks as disabled
84-
*/
85-
void track_binary_log_internal(bool enabled);
77+
using Service_type = SERVICE_TYPE(mysql_option_tracker_option);
78+
using Tracker_service_guard = my_service<Service_type>;
79+
static constexpr auto m_service_name = "mysql_option_tracker_option";
8680

8781
/**
8882
Helper method to get Replication Replica feature status.
@@ -94,36 +88,47 @@ class Rpl_opt_tracker {
9488
static bool is_replication_replica_enabled();
9589

9690
/**
97-
Tracks the Replication Replica feature, including the usage data.
91+
Tracks a feature, including the usage data.
9892
It only updates usage data if the feature is enabled.
9993
Internal method to be used after the mysql_option_tracker_option
10094
service is acquired.
10195
96+
@param service_guard acquired service guard
10297
@param enabled true: tracks as enabled
10398
false: tracks as disabled
99+
@param fname feature name
100+
@param usage_counter feature usage counter
104101
*/
105-
void track_replication_replica_internal(bool enabled);
102+
static void track(Tracker_service_guard &service_guard, bool enabled,
103+
const std::string &fname,
104+
unsigned long long &usage_counter);
106105

107106
/**
108-
Helper method to acquire the mysql_option_tracker_option
109-
service.
107+
Tracks the Binary Log feature, including the usage data.
108+
It only updates usage data if the feature is enabled.
109+
Internal method to be used after the mysql_option_tracker_option
110+
service is acquired.
110111
111-
@return the operation status
112-
@retval false Successful
113-
@retval true Error
112+
@param service_guard acquired service guard
113+
@param enabled true: tracks as enabled
114+
false: tracks as disabled
114115
*/
115-
bool acquire_option_tracker_service();
116+
void track_binary_log(Tracker_service_guard &service_guard,
117+
bool enabled) const;
116118

117119
/**
118-
Helper method to release the mysql_option_tracker_option
119-
service.
120+
Tracks the Replication Replica feature, including the usage data.
121+
It only updates usage data if the feature is enabled.
122+
123+
@param service_guard acquired service guard
124+
@param enabled true: tracks as enabled
125+
false: tracks as disabled
120126
*/
121-
void release_option_tracker_service();
127+
void track_replication_replica(Tracker_service_guard &service_guard,
128+
bool enabled) const;
122129

123130
SERVICE_TYPE_NO_CONST(registry_registration) *
124131
m_srv_registry_registration_no_lock{nullptr};
125-
SERVICE_TYPE(mysql_option_tracker_option) * m_option_tracker_service{nullptr};
126-
my_h_service m_option_tracker_handle{nullptr};
127132

128133
my_thread_handle m_thread_id;
129134
bool m_stop_worker{false};

0 commit comments

Comments
 (0)