Commit 0c79de24 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 25a9a3da
......@@ -3,6 +3,10 @@ INSERT INTO t1 VALUES(1);
SELECT * FROM t1;
i
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 @@session.wsrep_dirty_reads=OFF;
SET SESSION wsrep_sync_wait=0;
......@@ -18,8 +22,74 @@ SET @@session.wsrep_dirty_reads=ON;
SELECT * FROM t1;
i
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;
i
1
DROP TABLE t1;
drop user user1;
drop user user2;
disconnect node_2;
disconnect node_1;
# End of test
......@@ -17,6 +17,11 @@ CREATE TABLE t1(i INT) ENGINE=INNODB;
INSERT INTO t1 VALUES(1);
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 @@session.wsrep_dirty_reads=OFF;
......@@ -36,6 +41,67 @@ SET @@session.wsrep_dirty_reads=ON;
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
--eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved'
--enable_query_log
......@@ -45,6 +111,8 @@ SELECT * FROM t1;
SELECT * FROM t1;
# Cleanup
DROP TABLE t1;
drop user user1;
drop user user2;
# Restore original auto_increment_offset values.
--source include/auto_increment_offset_restore.inc
......
......@@ -5,12 +5,13 @@
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
@@global.wsrep_dirty_reads
0
SELECT @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads
0
# scope and valid values
# valid values for session
SET @@session.wsrep_dirty_reads=OFF;
SELECT @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads
......@@ -24,11 +25,29 @@ SELECT @@session.wsrep_dirty_reads;
@@session.wsrep_dirty_reads
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
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'
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
SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved;
......
......@@ -8,12 +8,12 @@
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
--echo # valid values for session
SET @@session.wsrep_dirty_reads=OFF;
SELECT @@session.wsrep_dirty_reads;
SET @@session.wsrep_dirty_reads=ON;
......@@ -21,12 +21,25 @@ SELECT @@session.wsrep_dirty_reads;
SET @@session.wsrep_dirty_reads=default;
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 # 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';
--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 # restore the initial values
......
......@@ -2649,13 +2649,16 @@ mysql_execute_command(THD *thd)
}
/*
Bail out if DB snapshot has not been installed. We however, allow SET,
SHOW and SELECT queries (only if wsrep_dirty_reads is set).
Bail out if DB snapshot has not been installed. SET and SHOW commands,
however, are always allowed.
We additionally allow all other commands that do not change data in
case wsrep_dirty_reads is enabled.
*/
if (lex->sql_command != SQLCOM_SET_OPTION &&
!wsrep_is_show_query(lex->sql_command) &&
!(thd->variables.wsrep_dirty_reads &&
lex->sql_command == SQLCOM_SELECT) &&
!is_update_query(lex->sql_command)) &&
!wsrep_node_is_ready(thd))
goto error;
}
......
......@@ -4976,8 +4976,9 @@ static Sys_var_mybool Sys_wsrep_restart_slave(
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,
"wsrep_dirty_reads",
"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);
static Sys_var_uint Sys_wsrep_gtid_domain_id(
......
......@@ -96,6 +96,8 @@ bool wsrep_new_cluster = false; // Bootstrap the cluster ?
bool wsrep_gtid_mode = 0;
// gtid_domain_id for galera transactions.
uint32 wsrep_gtid_domain_id = 0;
// Allow reads even if the node is not in the primary component.
bool wsrep_dirty_reads = false;
/*
* End configuration options
......@@ -958,6 +960,8 @@ bool wsrep_must_sync_wait (THD* thd, uint mask)
{
return (thd->variables.wsrep_sync_wait & mask) &&
thd->variables.wsrep_on &&
!(thd->variables.wsrep_dirty_reads &&
!is_update_query(thd->lex->sql_command)) &&
!thd->in_active_multi_stmt_transaction() &&
thd->wsrep_conflict_state != REPLAYING &&
thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
......
......@@ -89,6 +89,7 @@ extern ulong wsrep_running_threads;
extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
extern uint32 wsrep_gtid_domain_id;
extern bool wsrep_dirty_reads;
enum enum_wsrep_OSU_method {
WSREP_OSU_TOI,
......
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