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:
parent
95422c445d
commit
5ddd8149e4
@ -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
|
|||||||
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);
|
|||||||
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;
|
|||||||
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;
|
|||||||
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;
|
|||||||
|
|
||||||
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;
|
|||||||
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 @@
|
|||||||
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;
|
|||||||
@@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 @@
|
|||||||
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;
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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(
|
|||||||
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
|
|||||||
// 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)
|
|||||||
{
|
{
|
||||||
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;
|
|||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user