Skip to content

Commit 957e42e

Browse files
abhinav04sharmainikep
authored andcommitted
Setting read only during shutdown
Summary: Setting read only = 1 during shutdown after attempting to kill all connections but before shutting down plugins. This way we can be sure that no writes are being processed when semi-sync/raft plugins are shutdown. Reviewed By: hermanlee Differential Revision: D27539886
1 parent 6a004a6 commit 957e42e

File tree

8 files changed

+120
-2
lines changed

8 files changed

+120
-2
lines changed

mysql-test/r/mysqld--help-notwin.result

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,10 @@ The following options may be given as the first argument:
23072307
characteristics (isolation level, read only/read write,
23082308
snapshot - but not any work done / data modified within
23092309
the transaction).
2310+
--set-read-only-on-shutdown
2311+
Set read_only and super_read_only in shutdown path after
2312+
trying to kill connections but before shutting down
2313+
plugins
23102314
--sha256-password-proxy-users
23112315
If set to FALSE (the default), then the sha256_password
23122316
authentication plugin will not signal for authenticated
@@ -3410,6 +3414,7 @@ session-track-schema TRUE
34103414
session-track-state-change FALSE
34113415
session-track-system-variables time_zone,autocommit,character_set_client,character_set_results,character_set_connection
34123416
session-track-transaction-info OFF
3417+
set-read-only-on-shutdown FALSE
34133418
sha256-password-proxy-users FALSE
34143419
show-create-table-verbosity FALSE
34153420
show-gipk-in-create-table-and-information-schema TRUE
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
SET GLOBAL set_read_only_on_shutdown = 1;
2+
SET GLOBAL DEBUG = "+d,after_shutdown_read_only";
3+
CREATE TABLE t1 (pk INT, PRIMARY KEY (pk)) ENGINE = INNODB;
4+
"Start the sql client and run shutdown sql command"
5+
"Reached the point just after setting read_only in the shutdown path"
6+
SET DEBUG_SYNC = "now wait_for signal.reached";
7+
"Try to execute a write"
8+
select @@global.read_only, @@global.super_read_only;
9+
@@global.read_only @@global.super_read_only
10+
1 1
11+
INSERT INTO t1 VALUES(1);
12+
ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement
13+
"Continuing the shutdown"
14+
SET GLOBAL DEBUG = "-d,after_shutdown_read_only";
15+
SET DEBUG_SYNC = "now signal signal.done";
16+
"Starting the server again"
17+
"Table contents (should be empty)"
18+
SELECT * FROM t1;
19+
pk
20+
DROP TABLE t1;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Default value of set_read_only_on_shutdown is 0
2+
SELECT @@global.set_read_only_on_shutdown;
3+
@@global.set_read_only_on_shutdown
4+
0
5+
SELECT @@session.set_read_only_on_shutdown;
6+
ERROR HY000: Variable 'set_read_only_on_shutdown' is a GLOBAL variable
7+
Expected error 'Variable is a GLOBAL variable'
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- source include/load_sysvars.inc
2+
3+
####
4+
# Verify default value 0
5+
####
6+
--echo Default value of set_read_only_on_shutdown is 0
7+
SELECT @@global.set_read_only_on_shutdown;
8+
9+
####
10+
# Verify that this is not a session variable #
11+
####
12+
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
13+
SELECT @@session.set_read_only_on_shutdown;
14+
--echo Expected error 'Variable is a GLOBAL variable'
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
source include/have_debug_sync.inc;
2+
3+
SET GLOBAL set_read_only_on_shutdown = 1;
4+
SET GLOBAL DEBUG = "+d,after_shutdown_read_only";
5+
6+
CREATE TABLE t1 (pk INT, PRIMARY KEY (pk)) ENGINE = INNODB;
7+
8+
echo "Start the sql client and run shutdown sql command";
9+
exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
10+
exec $MYSQL -e "shutdown;" 2>&1;
11+
12+
echo "Reached the point just after setting read_only in the shutdown path";
13+
SET DEBUG_SYNC = "now wait_for signal.reached";
14+
15+
echo "Try to execute a write";
16+
select @@global.read_only, @@global.super_read_only;
17+
error 1290;
18+
INSERT INTO t1 VALUES(1);
19+
20+
echo "Continuing the shutdown";
21+
SET GLOBAL DEBUG = "-d,after_shutdown_read_only";
22+
SET DEBUG_SYNC = "now signal signal.done";
23+
source include/wait_until_disconnected.inc;
24+
25+
echo "Starting the server again";
26+
exec echo "restart:" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
27+
enable_reconnect;
28+
source include/wait_until_connected_again.inc;
29+
30+
echo "Table contents (should be empty)";
31+
SELECT * FROM t1;
32+
33+
DROP TABLE t1;

sql/mysqld.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,9 @@ uint default_password_lifetime = 0;
13381338
bool password_require_current = false;
13391339
std::atomic<bool> partial_revokes;
13401340
bool opt_partial_revokes; // Initialized through Sys_var
1341+
bool set_read_only_on_shutdown = false;
1342+
extern bool fix_read_only(sys_var *self, THD *thd, enum_var_type type);
1343+
extern bool fix_super_read_only(sys_var *self, THD *thd, enum_var_type type);
13411344

13421345
mysql_mutex_t LOCK_default_password_lifetime;
13431346
mysql_mutex_t LOCK_mandatory_roles;
@@ -2621,6 +2624,35 @@ static void close_connections(void) {
26212624

26222625
(void)RUN_HOOK(server_state, before_server_shutdown, (nullptr));
26232626

2627+
// case: block all writes by setting read_only=1 and super_read_only=1
2628+
if (set_read_only_on_shutdown) {
2629+
THD *thd = new THD;
2630+
thd->thread_stack = reinterpret_cast<char *>(&(thd));
2631+
thd->store_globals();
2632+
2633+
// NO_LINT_DEBUG
2634+
sql_print_information("Setting read_only=1 during shutdown");
2635+
mysql_mutex_lock(&LOCK_global_system_variables);
2636+
read_only = super_read_only = true;
2637+
if (fix_read_only(nullptr, thd, OPT_GLOBAL) ||
2638+
fix_super_read_only(nullptr, thd, OPT_GLOBAL))
2639+
// NO_LINT_DEBUG
2640+
sql_print_error("Setting read_only=1 failed during shutdown");
2641+
else
2642+
// NO_LINT_DEBUG
2643+
sql_print_information("Successfully set read_only=1 during shutdown");
2644+
mysql_mutex_unlock(&LOCK_global_system_variables);
2645+
2646+
DBUG_EXECUTE_IF("after_shutdown_read_only", {
2647+
const char act[] = "now signal signal.reached wait_for signal.done";
2648+
assert(opt_debug_sync_timeout > 0);
2649+
assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
2650+
});
2651+
2652+
thd->restore_globals();
2653+
delete thd;
2654+
}
2655+
26242656
Per_thread_connection_handler::kill_blocked_pthreads();
26252657

26262658
uint dump_thread_count = 0;

sql/mysqld.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ extern uint net_compression_level;
478478
extern long zstd_net_compression_level;
479479
extern long lz4f_net_compression_level;
480480
extern bool enable_blind_replace;
481+
extern bool set_read_only_on_shutdown;
481482

482483
/* SHOW STATS var: Name of current timer */
483484
extern const char *timer_in_use;

sql/sys_vars.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4081,7 +4081,7 @@ static void event_scheduler_restart(THD *thd) {
40814081
}
40824082
}
40834083

4084-
static bool fix_read_only(sys_var *self, THD *thd, enum_var_type) {
4084+
bool fix_read_only(sys_var *self, THD *thd, enum_var_type) {
40854085
bool result = true;
40864086
bool new_read_only = read_only; // make a copy before releasing a mutex
40874087
DBUG_TRACE;
@@ -4174,7 +4174,7 @@ static bool fix_read_only(sys_var *self, THD *thd, enum_var_type) {
41744174
return result;
41754175
}
41764176

4177-
static bool fix_super_read_only(sys_var *, THD *thd, enum_var_type type) {
4177+
bool fix_super_read_only(sys_var *, THD *thd, enum_var_type type) {
41784178
DBUG_TRACE;
41794179

41804180
/* return if no changes: */
@@ -9530,3 +9530,9 @@ static Sys_var_enum Sys_sql_duplicate_executions_control(
95309530
GLOBAL_VAR(sql_duplicate_executions_control), CMD_LINE(OPT_ARG),
95319531
control_level_values, DEFAULT(CONTROL_LEVEL_OFF), NO_MUTEX_GUARD,
95329532
NOT_IN_BINLOG, ON_CHECK(NULL), ON_UPDATE(NULL));
9533+
9534+
static Sys_var_bool Sys_set_read_only_on_shutdown(
9535+
"set_read_only_on_shutdown",
9536+
"Set read_only and super_read_only in shutdown path after trying to "
9537+
"kill connections but before shutting down plugins",
9538+
GLOBAL_VAR(set_read_only_on_shutdown), CMD_LINE(OPT_ARG), DEFAULT(false));

0 commit comments

Comments
 (0)