Commit 5ddd8149 authored by Sachin Setiya's avatar Sachin Setiya

MDEV-11479 Improved wsrep_dirty_reads

     Tasks:-
         Changes in wsrep_dirty_reads variable
         1.) Global + Session scope (Current: session-only)
         2.) Can be set using command line.
         3.) Allow all commands that do not change data (besides SELECT)
         4.) Allow prepared Statements that do not change data
         5.) Works with wsrep_sync_wait enabled
parent 95422c44
...@@ -879,6 +879,8 @@ The following options may be given as the first argument: ...@@ -879,6 +879,8 @@ The following options may be given as the first argument:
DBUG options to provider library DBUG options to provider library
--wsrep-debug To enable debug level logging --wsrep-debug To enable debug level logging
--wsrep-desync To desynchronize the node from the cluster --wsrep-desync To desynchronize the node from the cluster
--wsrep-dirty-reads Allow reads even when the node is not in the primary
component.
--wsrep-drupal-282555-workaround --wsrep-drupal-282555-workaround
To use a workaround forbad autoincrement value To use a workaround forbad autoincrement value
--wsrep-forced-binlog-format=name --wsrep-forced-binlog-format=name
...@@ -1201,6 +1203,7 @@ wsrep-convert-LOCK-to-trx FALSE ...@@ -1201,6 +1203,7 @@ wsrep-convert-LOCK-to-trx FALSE
wsrep-dbug-option wsrep-dbug-option
wsrep-debug FALSE wsrep-debug FALSE
wsrep-desync FALSE wsrep-desync FALSE
wsrep-dirty-reads FALSE
wsrep-drupal-282555-workaround FALSE wsrep-drupal-282555-workaround FALSE
wsrep-forced-binlog-format NONE wsrep-forced-binlog-format NONE
wsrep-load-data-splitting TRUE wsrep-load-data-splitting TRUE
......
...@@ -3,6 +3,10 @@ INSERT INTO t1 VALUES(1); ...@@ -3,6 +3,10 @@ INSERT INTO t1 VALUES(1);
SELECT * FROM t1; SELECT * FROM t1;
i i
1 1
create user user1;
grant all privileges on *.* to user1;
create user user2;
grant all privileges on *.* to user2;
SET @@global.wsrep_cluster_address = ''; SET @@global.wsrep_cluster_address = '';
SET @@session.wsrep_dirty_reads=OFF; SET @@session.wsrep_dirty_reads=OFF;
SET SESSION wsrep_sync_wait=0; SET SESSION wsrep_sync_wait=0;
...@@ -18,8 +22,74 @@ SET @@session.wsrep_dirty_reads=ON; ...@@ -18,8 +22,74 @@ SET @@session.wsrep_dirty_reads=ON;
SELECT * FROM t1; SELECT * FROM t1;
i i
1 1
connect con1, localhost, user1,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2;
SET SESSION wsrep_sync_wait=0;
set session wsrep_dirty_reads=1;
prepare stmt_show from 'select 1';
prepare stmt_select from 'select * from t1';
prepare stmt_insert from 'insert into t1 values(1)';
set session wsrep_dirty_reads=0;
execute stmt_show;
ERROR 08S01: WSREP has not yet prepared node for application use
execute stmt_select;
ERROR 08S01: WSREP has not yet prepared node for application use
execute stmt_insert;
ERROR 08S01: WSREP has not yet prepared node for application use
SET wsrep_dirty_reads=ON;
select @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads
1
execute stmt_show;
1
1
execute stmt_select;
i
1
execute stmt_insert;
ERROR 08S01: WSREP has not yet prepared node for application use
SET @@global.wsrep_dirty_reads=ON;
connect con2, localhost, user2,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2;
select @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads
1
prepare stmt_show from 'select 1';
prepare stmt_select from 'select * from t1';
prepare stmt_insert from 'insert into t1 values(1)';
execute stmt_show;
1
1
execute stmt_select;
i
1
execute stmt_insert;
ERROR 08S01: WSREP has not yet prepared node for application use
SET SESSION wsrep_sync_wait=1;
execute stmt_show;
1
1
execute stmt_select;
i
1
execute stmt_insert;
ERROR 08S01: WSREP has not yet prepared node for application use
SET SESSION wsrep_sync_wait=7;
execute stmt_show;
1
1
execute stmt_select;
i
1
execute stmt_insert;
ERROR 08S01: WSREP has not yet prepared node for application use
connection node_2;
SET @@global.wsrep_dirty_reads=OFF;
connection node_1;
SELECT * FROM t1; SELECT * FROM t1;
i i
1 1
DROP TABLE t1; DROP TABLE t1;
drop user user1;
drop user user2;
disconnect node_2;
disconnect node_1;
# End of test # End of test
...@@ -20,6 +20,11 @@ CREATE TABLE t1(i INT) ENGINE=INNODB; ...@@ -20,6 +20,11 @@ CREATE TABLE t1(i INT) ENGINE=INNODB;
INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(1);
SELECT * FROM t1; SELECT * FROM t1;
create user user1;
grant all privileges on *.* to user1;
create user user2;
grant all privileges on *.* to user2;
SET @@global.wsrep_cluster_address = ''; SET @@global.wsrep_cluster_address = '';
SET @@session.wsrep_dirty_reads=OFF; SET @@session.wsrep_dirty_reads=OFF;
...@@ -39,6 +44,67 @@ SET @@session.wsrep_dirty_reads=ON; ...@@ -39,6 +44,67 @@ SET @@session.wsrep_dirty_reads=ON;
SELECT * FROM t1; SELECT * FROM t1;
--enable_connect_log
--connect (con1, localhost, user1,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2)
#Just test the session behavior
SET SESSION wsrep_sync_wait=0;
set session wsrep_dirty_reads=1;
#Prepared statement creation should be allowed MDEV-11479
prepare stmt_show from 'select 1';
prepare stmt_select from 'select * from t1';
prepare stmt_insert from 'insert into t1 values(1)';
set session wsrep_dirty_reads=0;
#No Preapare stmt/proceure will be allowed
--error ER_UNKNOWN_COM_ERROR
execute stmt_show;
--error ER_UNKNOWN_COM_ERROR
execute stmt_select;
--error ER_UNKNOWN_COM_ERROR
execute stmt_insert;
SET wsrep_dirty_reads=ON;
select @@session.wsrep_dirty_reads;
#Only prepare statement which does not change data should be allowed
execute stmt_show;
execute stmt_select;
--error ER_UNKNOWN_COM_ERROR
execute stmt_insert;
SET @@global.wsrep_dirty_reads=ON;
--connect (con2, localhost, user2,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2)
#Just test the session behavior
select @@session.wsrep_dirty_reads;
prepare stmt_show from 'select 1';
prepare stmt_select from 'select * from t1';
prepare stmt_insert from 'insert into t1 values(1)';
#Only prepare statement which does not change data should be allowed
execute stmt_show;
execute stmt_select;
--error ER_UNKNOWN_COM_ERROR
execute stmt_insert;
#wsrep_dirty_read should work when wsrep_sync_wait is 1 or non zero
#because we already are disconnected , So It does not make any sense
#to wait for other nodes
SET SESSION wsrep_sync_wait=1;
execute stmt_show;
execute stmt_select;
--error ER_UNKNOWN_COM_ERROR
execute stmt_insert;
SET SESSION wsrep_sync_wait=7;
execute stmt_show;
execute stmt_select;
--error ER_UNKNOWN_COM_ERROR
execute stmt_insert;
--connection node_2
SET @@global.wsrep_dirty_reads=OFF;
--disable_query_log --disable_query_log
--eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved'
--enable_query_log --enable_query_log
...@@ -48,6 +114,8 @@ SELECT * FROM t1; ...@@ -48,6 +114,8 @@ SELECT * FROM t1;
SELECT * FROM t1; SELECT * FROM t1;
# Cleanup # Cleanup
DROP TABLE t1; DROP TABLE t1;
drop user user1;
drop user user2;
--disable_query_log --disable_query_log
# Restore original auto_increment_offset values. # Restore original auto_increment_offset values.
......
...@@ -5,12 +5,13 @@ ...@@ -5,12 +5,13 @@
SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads; SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads;
# default # default
SELECT @@global.wsrep_dirty_reads; SELECT @@global.wsrep_dirty_reads;
ERROR HY000: Variable 'wsrep_dirty_reads' is a SESSION variable @@global.wsrep_dirty_reads
0
SELECT @@session.wsrep_dirty_reads; SELECT @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads @@session.wsrep_dirty_reads
0 0
# scope and valid values # valid values for session
SET @@session.wsrep_dirty_reads=OFF; SET @@session.wsrep_dirty_reads=OFF;
SELECT @@session.wsrep_dirty_reads; SELECT @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads @@session.wsrep_dirty_reads
...@@ -24,11 +25,29 @@ SELECT @@session.wsrep_dirty_reads; ...@@ -24,11 +25,29 @@ SELECT @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads @@session.wsrep_dirty_reads
0 0
# valid values for global
SET @@global.wsrep_dirty_reads=OFF;
SELECT @@global.wsrep_dirty_reads;
@@global.wsrep_dirty_reads
0
SET @@global.wsrep_dirty_reads=ON;
SELECT @@global.wsrep_dirty_reads;
@@global.wsrep_dirty_reads
1
SET @@global.wsrep_dirty_reads=default;
SELECT @@global.wsrep_dirty_reads;
@@global.wsrep_dirty_reads
0
# invalid values # invalid values
SET @@session.wsrep_dirty_reads=NULL; SET @@session.wsrep_dirty_reads=NULL;
ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL' ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL'
SET @@session.wsrep_dirty_reads='junk'; SET @@session.wsrep_dirty_reads='junk';
ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk' ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk'
SET @@global.wsrep_dirty_reads=NULL;
ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL'
SET @@global.wsrep_dirty_reads='junk';
ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk'
# restore the initial values # restore the initial values
SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved; SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved;
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads; SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads;
--echo # default --echo # default
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT @@global.wsrep_dirty_reads; SELECT @@global.wsrep_dirty_reads;
SELECT @@session.wsrep_dirty_reads; SELECT @@session.wsrep_dirty_reads;
--echo --echo
--echo # scope and valid values --echo # valid values for session
SET @@session.wsrep_dirty_reads=OFF; SET @@session.wsrep_dirty_reads=OFF;
SELECT @@session.wsrep_dirty_reads; SELECT @@session.wsrep_dirty_reads;
SET @@session.wsrep_dirty_reads=ON; SET @@session.wsrep_dirty_reads=ON;
...@@ -21,12 +21,25 @@ SELECT @@session.wsrep_dirty_reads; ...@@ -21,12 +21,25 @@ SELECT @@session.wsrep_dirty_reads;
SET @@session.wsrep_dirty_reads=default; SET @@session.wsrep_dirty_reads=default;
SELECT @@session.wsrep_dirty_reads; SELECT @@session.wsrep_dirty_reads;
--echo
--echo # valid values for global
SET @@global.wsrep_dirty_reads=OFF;
SELECT @@global.wsrep_dirty_reads;
SET @@global.wsrep_dirty_reads=ON;
SELECT @@global.wsrep_dirty_reads;
SET @@global.wsrep_dirty_reads=default;
SELECT @@global.wsrep_dirty_reads;
--echo --echo
--echo # invalid values --echo # invalid values
--error ER_WRONG_VALUE_FOR_VAR --error ER_WRONG_VALUE_FOR_VAR
SET @@session.wsrep_dirty_reads=NULL; SET @@session.wsrep_dirty_reads=NULL;
--error ER_WRONG_VALUE_FOR_VAR --error ER_WRONG_VALUE_FOR_VAR
SET @@session.wsrep_dirty_reads='junk'; SET @@session.wsrep_dirty_reads='junk';
--error ER_WRONG_VALUE_FOR_VAR
SET @@global.wsrep_dirty_reads=NULL;
--error ER_WRONG_VALUE_FOR_VAR
SET @@global.wsrep_dirty_reads='junk';
--echo --echo
--echo # restore the initial values --echo # restore the initial values
......
...@@ -2386,13 +2386,16 @@ mysql_execute_command(THD *thd) ...@@ -2386,13 +2386,16 @@ mysql_execute_command(THD *thd)
} }
/* /*
Bail out if DB snapshot has not been installed. We however, Bail out if DB snapshot has not been installed. SET and SHOW commands,
allow SET and SHOW queries. however, are always allowed.
We additionally allow all other commands that do not change data in
case wsrep_dirty_reads is enabled.
*/ */
if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
lex->sql_command != SQLCOM_SET_OPTION && lex->sql_command != SQLCOM_SET_OPTION &&
!(thd->variables.wsrep_dirty_reads && !(thd->variables.wsrep_dirty_reads &&
lex->sql_command == SQLCOM_SELECT) && !is_update_query(lex->sql_command)) &&
!wsrep_is_show_query(lex->sql_command)) !wsrep_is_show_query(lex->sql_command))
{ {
#if DIRTY_HACK #if DIRTY_HACK
......
...@@ -3966,8 +3966,9 @@ static Sys_var_mybool Sys_wsrep_restart_slave( ...@@ -3966,8 +3966,9 @@ static Sys_var_mybool Sys_wsrep_restart_slave(
GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
static Sys_var_mybool Sys_wsrep_dirty_reads( static Sys_var_mybool Sys_wsrep_dirty_reads(
"wsrep_dirty_reads", "Do not reject SELECT queries even when the node " "wsrep_dirty_reads",
"is not ready.", SESSION_ONLY(wsrep_dirty_reads), NO_CMD_LINE, "Allow reads even when the node is not in the primary component.",
SESSION_VAR(wsrep_dirty_reads), CMD_LINE(OPT_ARG),
DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG); DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG);
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
......
...@@ -65,6 +65,8 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave ...@@ -65,6 +65,8 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave
// restart will be needed // restart will be needed
my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks
my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks
// Allow reads even if the node is not in the primary component.
bool wsrep_dirty_reads = false;
/* /*
Set during the creation of first wsrep applier and rollback threads. Set during the creation of first wsrep applier and rollback threads.
...@@ -894,6 +896,8 @@ bool wsrep_must_sync_wait (THD* thd, uint mask) ...@@ -894,6 +896,8 @@ bool wsrep_must_sync_wait (THD* thd, uint mask)
{ {
return (thd->variables.wsrep_sync_wait & mask) && return (thd->variables.wsrep_sync_wait & mask) &&
thd->variables.wsrep_on && thd->variables.wsrep_on &&
!(thd->variables.wsrep_dirty_reads &&
!is_update_query(thd->lex->sql_command)) &&
!thd->in_active_multi_stmt_transaction() && !thd->in_active_multi_stmt_transaction() &&
thd->wsrep_conflict_state != REPLAYING && thd->wsrep_conflict_state != REPLAYING &&
thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED; thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
......
...@@ -80,6 +80,7 @@ extern ulong wsrep_retry_autocommit; ...@@ -80,6 +80,7 @@ extern ulong wsrep_retry_autocommit;
extern my_bool wsrep_auto_increment_control; extern my_bool wsrep_auto_increment_control;
extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_drupal_282555_workaround;
extern my_bool wsrep_incremental_data_collection; extern my_bool wsrep_incremental_data_collection;
extern bool wsrep_dirty_reads;
extern const char* wsrep_start_position; extern const char* wsrep_start_position;
extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_size;
extern ulong wsrep_max_ws_rows; extern ulong wsrep_max_ws_rows;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment