mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
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
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user