diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result index 48535e53c32..fe12c2ca3ec 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result +++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result @@ -141,6 +141,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST OFF,ON READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL +VARIABLE_NAME WSREP_DIRTY_READS +SESSION_VALUE OFF +GLOBAL_VALUE NULL +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE OFF +VARIABLE_SCOPE SESSION ONLY +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Do not reject SELECT queries even when the node is not ready. +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY NO +COMMAND_LINE_ARGUMENT NULL VARIABLE_NAME WSREP_DRUPAL_282555_WORKAROUND SESSION_VALUE NULL GLOBAL_VALUE OFF diff --git a/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result new file mode 100644 index 00000000000..d2a62d6136f --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result @@ -0,0 +1,35 @@ +# +# wsrep_dirty_reads +# +# save the initial value +SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads; +# default +SELECT @@global.wsrep_dirty_reads; +ERROR HY000: Variable 'wsrep_dirty_reads' is a SESSION variable +SELECT @@session.wsrep_dirty_reads; +@@session.wsrep_dirty_reads +0 + +# scope and valid values +SET @@session.wsrep_dirty_reads=OFF; +SELECT @@session.wsrep_dirty_reads; +@@session.wsrep_dirty_reads +0 +SET @@session.wsrep_dirty_reads=ON; +SELECT @@session.wsrep_dirty_reads; +@@session.wsrep_dirty_reads +1 +SET @@session.wsrep_dirty_reads=default; +SELECT @@session.wsrep_dirty_reads; +@@session.wsrep_dirty_reads +0 + +# invalid values +SET @@session.wsrep_dirty_reads=NULL; +ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL' +SET @@session.wsrep_dirty_reads='junk'; +ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk' + +# restore the initial values +SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test new file mode 100644 index 00000000000..a47524fcfe3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test @@ -0,0 +1,35 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_dirty_reads +--echo # + +--echo # save the initial value +SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads; + +--echo # default +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@global.wsrep_dirty_reads; +SELECT @@session.wsrep_dirty_reads; + +--echo +--echo # scope and valid values +SET @@session.wsrep_dirty_reads=OFF; +SELECT @@session.wsrep_dirty_reads; +SET @@session.wsrep_dirty_reads=ON; +SELECT @@session.wsrep_dirty_reads; +SET @@session.wsrep_dirty_reads=default; +SELECT @@session.wsrep_dirty_reads; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@session.wsrep_dirty_reads=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@session.wsrep_dirty_reads='junk'; + +--echo +--echo # restore the initial values +SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved; + +--echo # End of test diff --git a/mysql-test/suite/wsrep/r/galera_var_dirty_reads.result b/mysql-test/suite/wsrep/r/galera_var_dirty_reads.result new file mode 100644 index 00000000000..6d703c8cf95 --- /dev/null +++ b/mysql-test/suite/wsrep/r/galera_var_dirty_reads.result @@ -0,0 +1,25 @@ +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; +i +1 +SET @@global.wsrep_cluster_address = ''; +SET @@session.wsrep_dirty_reads=OFF; +SET SESSION wsrep_sync_wait=0; +SHOW STATUS LIKE 'wsrep_ready'; +Variable_name Value +wsrep_ready OFF +SHOW STATUS LIKE 'wsrep_cluster_status'; +Variable_name Value +wsrep_cluster_status non-Primary +SELECT * FROM t1; +ERROR 08S01: WSREP has not yet prepared node for application use +SET @@session.wsrep_dirty_reads=ON; +SELECT * FROM t1; +i +1 +SELECT * FROM t1; +i +1 +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index 67206a8810f..73b84574056 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -137,7 +137,6 @@ wsrep_last_committed # # # MDEV#6206: wsrep_slave_threads subtracts from max_connections # -call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); SELECT @@global.wsrep_provider; @@global.wsrep_provider libgalera_smm.so diff --git a/mysql-test/suite/wsrep/suite.pm b/mysql-test/suite/wsrep/suite.pm index e22ba43e90a..3e8962d09d6 100644 --- a/mysql-test/suite/wsrep/suite.pm +++ b/mysql-test/suite/wsrep/suite.pm @@ -31,6 +31,7 @@ push @::global_suppressions, qr(WSREP: last inactive check more than .* skipping check), qr(WSREP: Gap in state sequence. Need state transfer.), qr(WSREP: Failed to prepare for incremental state transfer: .*), + qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.), ); diff --git a/mysql-test/suite/wsrep/t/galera_var_dirty_reads.test b/mysql-test/suite/wsrep/t/galera_var_dirty_reads.test new file mode 100644 index 00000000000..855f4abdbf0 --- /dev/null +++ b/mysql-test/suite/wsrep/t/galera_var_dirty_reads.test @@ -0,0 +1,46 @@ +# +# Check the handling of @@wsrep_dirty_reads +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--connection node_2 +--let $wsrep_cluster_address_saved = `SELECT @@global.wsrep_cluster_address` + +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; + +SET @@global.wsrep_cluster_address = ''; +SET @@session.wsrep_dirty_reads=OFF; + +# Set wsrep_sync_wait to avoid ER_LOCK_WAIT_TIMEOUT (MDEV-6832). +SET SESSION wsrep_sync_wait=0; + +# Must return 'OFF' +SHOW STATUS LIKE 'wsrep_ready'; + +# Must return 'Non-primary' +SHOW STATUS LIKE 'wsrep_cluster_status'; + +--error ER_UNKNOWN_COM_ERROR +SELECT * FROM t1; + +SET @@session.wsrep_dirty_reads=ON; + +SELECT * FROM t1; + +--disable_query_log +--eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' +--enable_query_log +--source include/wait_until_connected_again.inc + +--connection node_1 +SELECT * FROM t1; +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test + diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 050d40b47a0..98045e2b014 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -52,7 +52,6 @@ SHOW STATUS LIKE 'wsrep_last_committed'; --echo # --echo # MDEV#6206: wsrep_slave_threads subtracts from max_connections --echo # -call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); --replace_regex /.*libgalera_smm.*/libgalera_smm.so/ SELECT @@global.wsrep_provider; diff --git a/sql/sql_class.h b/sql/sql_class.h index 4c014fd93a0..3b2b3d841a8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -647,6 +647,7 @@ typedef struct system_variables my_bool wsrep_on; my_bool wsrep_causal_reads; + my_bool wsrep_dirty_reads; uint wsrep_sync_wait; ulong wsrep_retry_autocommit; double long_query_time_double, max_statement_time_double; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e4e5f0adfd5..daf87d7cf96 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2607,11 +2607,13 @@ mysql_execute_command(THD *thd) } /* - * bail out if DB snapshot has not been installed. We however, - * allow SET and SHOW queries - */ + Bail out if DB snapshot has not been installed. We however, + allow SET and SHOW queries. + */ if (lex->sql_command != SQLCOM_SET_OPTION && !wsrep_is_show_query(lex->sql_command) && + !(thd->variables.wsrep_dirty_reads && + lex->sql_command == SQLCOM_SELECT) && !wsrep_node_is_ready(thd)) goto error; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index a0140eb04c6..04be3f10a19 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4840,6 +4840,12 @@ static Sys_var_mybool Sys_wsrep_slave_UK_checks( static Sys_var_mybool Sys_wsrep_restart_slave( "wsrep_restart_slave", "Should MySQL slave be restarted automatically, when node joins back to cluster", GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_dirty_reads( + "wsrep_dirty_reads", "Do not reject SELECT queries even when the node " + "is not ready.", SESSION_ONLY(wsrep_dirty_reads), NO_CMD_LINE, + DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG); + #endif /* WITH_WSREP */ static bool fix_host_cache_size(sys_var *, THD *, enum_var_type) diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index c6e9b89ca55..8a4fa4cd14f 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -353,7 +353,14 @@ bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type) */ mysql_mutex_unlock(&LOCK_global_system_variables); wsrep_stop_replication(thd); + + /* + Unlock and lock LOCK_wsrep_slave_threads to maintain lock order & avoid + any potential deadlock. + */ + mysql_mutex_unlock(&LOCK_wsrep_slave_threads); mysql_mutex_lock(&LOCK_global_system_variables); + mysql_mutex_lock(&LOCK_wsrep_slave_threads); if (wsrep_start_replication()) {