Skip to content

Commit 0105bf3

Browse files
author
Nirbhay Choubey
committed
MDEV-7476: Allow SELECT to succeed even when node is not ready
Added a SESSION-only system variable "wsrep_dirty_reads" to allow SELECT queries to pass even when the node is not prepared to accept queries (wsrep_ready=OFF). Added a test case.
1 parent ab440b0 commit 0105bf3

12 files changed

+175
-5
lines changed

mysql-test/suite/sys_vars/r/sysvars_wsrep.result

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ NUMERIC_BLOCK_SIZE NULL
141141
ENUM_VALUE_LIST OFF,ON
142142
READ_ONLY NO
143143
COMMAND_LINE_ARGUMENT OPTIONAL
144+
VARIABLE_NAME WSREP_DIRTY_READS
145+
SESSION_VALUE OFF
146+
GLOBAL_VALUE NULL
147+
GLOBAL_VALUE_ORIGIN COMPILE-TIME
148+
DEFAULT_VALUE OFF
149+
VARIABLE_SCOPE SESSION ONLY
150+
VARIABLE_TYPE BOOLEAN
151+
VARIABLE_COMMENT Do not reject SELECT queries even when the node is not ready.
152+
NUMERIC_MIN_VALUE NULL
153+
NUMERIC_MAX_VALUE NULL
154+
NUMERIC_BLOCK_SIZE NULL
155+
ENUM_VALUE_LIST OFF,ON
156+
READ_ONLY NO
157+
COMMAND_LINE_ARGUMENT NULL
144158
VARIABLE_NAME WSREP_DRUPAL_282555_WORKAROUND
145159
SESSION_VALUE NULL
146160
GLOBAL_VALUE OFF
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# wsrep_dirty_reads
3+
#
4+
# save the initial value
5+
SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads;
6+
# default
7+
SELECT @@global.wsrep_dirty_reads;
8+
ERROR HY000: Variable 'wsrep_dirty_reads' is a SESSION variable
9+
SELECT @@session.wsrep_dirty_reads;
10+
@@session.wsrep_dirty_reads
11+
0
12+
13+
# scope and valid values
14+
SET @@session.wsrep_dirty_reads=OFF;
15+
SELECT @@session.wsrep_dirty_reads;
16+
@@session.wsrep_dirty_reads
17+
0
18+
SET @@session.wsrep_dirty_reads=ON;
19+
SELECT @@session.wsrep_dirty_reads;
20+
@@session.wsrep_dirty_reads
21+
1
22+
SET @@session.wsrep_dirty_reads=default;
23+
SELECT @@session.wsrep_dirty_reads;
24+
@@session.wsrep_dirty_reads
25+
0
26+
27+
# invalid values
28+
SET @@session.wsrep_dirty_reads=NULL;
29+
ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL'
30+
SET @@session.wsrep_dirty_reads='junk';
31+
ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk'
32+
33+
# restore the initial values
34+
SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved;
35+
# End of test
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--source include/have_wsrep.inc
2+
3+
--echo #
4+
--echo # wsrep_dirty_reads
5+
--echo #
6+
7+
--echo # save the initial value
8+
SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads;
9+
10+
--echo # default
11+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
12+
SELECT @@global.wsrep_dirty_reads;
13+
SELECT @@session.wsrep_dirty_reads;
14+
15+
--echo
16+
--echo # scope and valid values
17+
SET @@session.wsrep_dirty_reads=OFF;
18+
SELECT @@session.wsrep_dirty_reads;
19+
SET @@session.wsrep_dirty_reads=ON;
20+
SELECT @@session.wsrep_dirty_reads;
21+
SET @@session.wsrep_dirty_reads=default;
22+
SELECT @@session.wsrep_dirty_reads;
23+
24+
--echo
25+
--echo # invalid values
26+
--error ER_WRONG_VALUE_FOR_VAR
27+
SET @@session.wsrep_dirty_reads=NULL;
28+
--error ER_WRONG_VALUE_FOR_VAR
29+
SET @@session.wsrep_dirty_reads='junk';
30+
31+
--echo
32+
--echo # restore the initial values
33+
SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved;
34+
35+
--echo # End of test
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
CREATE TABLE t1(i INT) ENGINE=INNODB;
2+
INSERT INTO t1 VALUES(1);
3+
SELECT * FROM t1;
4+
i
5+
1
6+
SET @@global.wsrep_cluster_address = '';
7+
SET @@session.wsrep_dirty_reads=OFF;
8+
SET SESSION wsrep_sync_wait=0;
9+
SHOW STATUS LIKE 'wsrep_ready';
10+
Variable_name Value
11+
wsrep_ready OFF
12+
SHOW STATUS LIKE 'wsrep_cluster_status';
13+
Variable_name Value
14+
wsrep_cluster_status non-Primary
15+
SELECT * FROM t1;
16+
ERROR 08S01: WSREP has not yet prepared node for application use
17+
SET @@session.wsrep_dirty_reads=ON;
18+
SELECT * FROM t1;
19+
i
20+
1
21+
SELECT * FROM t1;
22+
i
23+
1
24+
DROP TABLE t1;
25+
# End of test

mysql-test/suite/wsrep/r/variables.result

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ wsrep_last_committed #
137137
#
138138
# MDEV#6206: wsrep_slave_threads subtracts from max_connections
139139
#
140-
call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'");
141140
SELECT @@global.wsrep_provider;
142141
@@global.wsrep_provider
143142
libgalera_smm.so

mysql-test/suite/wsrep/suite.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ push @::global_suppressions,
3131
qr(WSREP: last inactive check more than .* skipping check),
3232
qr(WSREP: Gap in state sequence. Need state transfer.),
3333
qr(WSREP: Failed to prepare for incremental state transfer: .*),
34+
qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.),
3435
);
3536

3637

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#
2+
# Check the handling of @@wsrep_dirty_reads
3+
#
4+
5+
--source include/galera_cluster.inc
6+
--source include/have_innodb.inc
7+
8+
--connection node_2
9+
--let $wsrep_cluster_address_saved = `SELECT @@global.wsrep_cluster_address`
10+
11+
CREATE TABLE t1(i INT) ENGINE=INNODB;
12+
INSERT INTO t1 VALUES(1);
13+
SELECT * FROM t1;
14+
15+
SET @@global.wsrep_cluster_address = '';
16+
SET @@session.wsrep_dirty_reads=OFF;
17+
18+
# Set wsrep_sync_wait to avoid ER_LOCK_WAIT_TIMEOUT (MDEV-6832).
19+
SET SESSION wsrep_sync_wait=0;
20+
21+
# Must return 'OFF'
22+
SHOW STATUS LIKE 'wsrep_ready';
23+
24+
# Must return 'Non-primary'
25+
SHOW STATUS LIKE 'wsrep_cluster_status';
26+
27+
--error ER_UNKNOWN_COM_ERROR
28+
SELECT * FROM t1;
29+
30+
SET @@session.wsrep_dirty_reads=ON;
31+
32+
SELECT * FROM t1;
33+
34+
--disable_query_log
35+
--eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved'
36+
--enable_query_log
37+
--source include/wait_until_connected_again.inc
38+
39+
--connection node_1
40+
SELECT * FROM t1;
41+
# Cleanup
42+
DROP TABLE t1;
43+
44+
--source include/galera_end.inc
45+
--echo # End of test
46+

mysql-test/suite/wsrep/t/variables.test

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ SHOW STATUS LIKE 'wsrep_last_committed';
5252
--echo #
5353
--echo # MDEV#6206: wsrep_slave_threads subtracts from max_connections
5454
--echo #
55-
call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'");
5655

5756
--replace_regex /.*libgalera_smm.*/libgalera_smm.so/
5857
SELECT @@global.wsrep_provider;

sql/sql_class.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ typedef struct system_variables
647647

648648
my_bool wsrep_on;
649649
my_bool wsrep_causal_reads;
650+
my_bool wsrep_dirty_reads;
650651
uint wsrep_sync_wait;
651652
ulong wsrep_retry_autocommit;
652653
double long_query_time_double, max_statement_time_double;

sql/sql_parse.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2607,11 +2607,13 @@ mysql_execute_command(THD *thd)
26072607
}
26082608

26092609
/*
2610-
* bail out if DB snapshot has not been installed. We however,
2611-
* allow SET and SHOW queries
2612-
*/
2610+
Bail out if DB snapshot has not been installed. We however,
2611+
allow SET and SHOW queries.
2612+
*/
26132613
if (lex->sql_command != SQLCOM_SET_OPTION &&
26142614
!wsrep_is_show_query(lex->sql_command) &&
2615+
!(thd->variables.wsrep_dirty_reads &&
2616+
lex->sql_command == SQLCOM_SELECT) &&
26152617
!wsrep_node_is_ready(thd))
26162618
goto error;
26172619
}

sql/sys_vars.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4840,6 +4840,12 @@ static Sys_var_mybool Sys_wsrep_slave_UK_checks(
48404840
static Sys_var_mybool Sys_wsrep_restart_slave(
48414841
"wsrep_restart_slave", "Should MySQL slave be restarted automatically, when node joins back to cluster",
48424842
GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
4843+
4844+
static Sys_var_mybool Sys_wsrep_dirty_reads(
4845+
"wsrep_dirty_reads", "Do not reject SELECT queries even when the node "
4846+
"is not ready.", SESSION_ONLY(wsrep_dirty_reads), NO_CMD_LINE,
4847+
DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG);
4848+
48434849
#endif /* WITH_WSREP */
48444850

48454851
static bool fix_host_cache_size(sys_var *, THD *, enum_var_type)

sql/wsrep_var.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,14 @@ bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type)
353353
*/
354354
mysql_mutex_unlock(&LOCK_global_system_variables);
355355
wsrep_stop_replication(thd);
356+
357+
/*
358+
Unlock and lock LOCK_wsrep_slave_threads to maintain lock order & avoid
359+
any potential deadlock.
360+
*/
361+
mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
356362
mysql_mutex_lock(&LOCK_global_system_variables);
363+
mysql_mutex_lock(&LOCK_wsrep_slave_threads);
357364

358365
if (wsrep_start_replication())
359366
{

0 commit comments

Comments
 (0)