Skip to content

Commit 10c38d6

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 44b1a31 commit 10c38d6

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
@@ -2293,6 +2293,10 @@ The following options may be given as the first argument:
22932293
characteristics (isolation level, read only/read write,
22942294
snapshot - but not any work done / data modified within
22952295
the transaction).
2296+
--set-read-only-on-shutdown
2297+
Set read_only and super_read_only in shutdown path after
2298+
trying to kill connections but before shutting down
2299+
plugins
22962300
--sha256-password-proxy-users
22972301
If set to FALSE (the default), then the sha256_password
22982302
authentication plugin will not signal for authenticated
@@ -3390,6 +3394,7 @@ session-track-schema TRUE
33903394
session-track-state-change FALSE
33913395
session-track-system-variables time_zone,autocommit,character_set_client,character_set_results,character_set_connection
33923396
session-track-transaction-info OFF
3397+
set-read-only-on-shutdown FALSE
33933398
sha256-password-proxy-users FALSE
33943399
show-create-table-verbosity FALSE
33953400
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
@@ -1335,6 +1335,9 @@ uint default_password_lifetime = 0;
13351335
bool password_require_current = false;
13361336
std::atomic<bool> partial_revokes;
13371337
bool opt_partial_revokes; // Initialized through Sys_var
1338+
bool set_read_only_on_shutdown = false;
1339+
extern bool fix_read_only(sys_var *self, THD *thd, enum_var_type type);
1340+
extern bool fix_super_read_only(sys_var *self, THD *thd, enum_var_type type);
13381341

13391342
mysql_mutex_t LOCK_default_password_lifetime;
13401343
mysql_mutex_t LOCK_mandatory_roles;
@@ -2587,6 +2590,35 @@ static void close_connections(void) {
25872590

25882591
(void)RUN_HOOK(server_state, before_server_shutdown, (nullptr));
25892592

2593+
// case: block all writes by setting read_only=1 and super_read_only=1
2594+
if (set_read_only_on_shutdown) {
2595+
THD *thd = new THD;
2596+
thd->thread_stack = reinterpret_cast<char *>(&(thd));
2597+
thd->store_globals();
2598+
2599+
// NO_LINT_DEBUG
2600+
sql_print_information("Setting read_only=1 during shutdown");
2601+
mysql_mutex_lock(&LOCK_global_system_variables);
2602+
read_only = super_read_only = true;
2603+
if (fix_read_only(nullptr, thd, OPT_GLOBAL) ||
2604+
fix_super_read_only(nullptr, thd, OPT_GLOBAL))
2605+
// NO_LINT_DEBUG
2606+
sql_print_error("Setting read_only=1 failed during shutdown");
2607+
else
2608+
// NO_LINT_DEBUG
2609+
sql_print_information("Successfully set read_only=1 during shutdown");
2610+
mysql_mutex_unlock(&LOCK_global_system_variables);
2611+
2612+
DBUG_EXECUTE_IF("after_shutdown_read_only", {
2613+
const char act[] = "now signal signal.reached wait_for signal.done";
2614+
assert(opt_debug_sync_timeout > 0);
2615+
assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
2616+
});
2617+
2618+
thd->restore_globals();
2619+
delete thd;
2620+
}
2621+
25902622
Per_thread_connection_handler::kill_blocked_pthreads();
25912623

25922624
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
@@ -4046,7 +4046,7 @@ static void event_scheduler_restart(THD *thd) {
40464046
}
40474047
}
40484048

4049-
static bool fix_read_only(sys_var *self, THD *thd, enum_var_type) {
4049+
bool fix_read_only(sys_var *self, THD *thd, enum_var_type) {
40504050
bool result = true;
40514051
bool new_read_only = read_only; // make a copy before releasing a mutex
40524052
DBUG_TRACE;
@@ -4139,7 +4139,7 @@ static bool fix_read_only(sys_var *self, THD *thd, enum_var_type) {
41394139
return result;
41404140
}
41414141

4142-
static bool fix_super_read_only(sys_var *, THD *thd, enum_var_type type) {
4142+
bool fix_super_read_only(sys_var *, THD *thd, enum_var_type type) {
41434143
DBUG_TRACE;
41444144

41454145
/* return if no changes: */
@@ -9511,3 +9511,9 @@ static Sys_var_enum Sys_sql_duplicate_executions_control(
95119511
GLOBAL_VAR(sql_duplicate_executions_control), CMD_LINE(OPT_ARG),
95129512
control_level_values, DEFAULT(CONTROL_LEVEL_OFF), NO_MUTEX_GUARD,
95139513
NOT_IN_BINLOG, ON_CHECK(NULL), ON_UPDATE(NULL));
9514+
9515+
static Sys_var_bool Sys_set_read_only_on_shutdown(
9516+
"set_read_only_on_shutdown",
9517+
"Set read_only and super_read_only in shutdown path after trying to "
9518+
"kill connections but before shutting down plugins",
9519+
GLOBAL_VAR(set_read_only_on_shutdown), CMD_LINE(OPT_ARG), DEFAULT(false));

0 commit comments

Comments
 (0)