Re: [Maria-developers] [Commits] 27af988: MDEV-11479 Improved wsrep_dirty_reads
Hi Sachin! Comments inline: On Sun, 4 Dec 2016 at 08:36 <sachin.setiya@mariadb.com> wrote:
revision-id: 27af98805c27c8e0c41dc8c19bf80aefff4c6d3d (mariadb-galera-5.5.53-3-g27af988) parent(s): 72fd15f7c31aa3e3705ae1b005a3247a985c5bb3 author: SachinSetiya committer: SachinSetiya
NIT: To get these to display correctly you should have a space between Sachin and Setiya.
timestamp: 2016-12-04 12:05:05 +0530 message:
MDEV-11479 Improved wsrep_dirty_reads
Tasks:- Changes in wsrep_dirty_reads variable 1.) Global + Session scope (Current: session-only) 2.) Allow all commands that do not change data (besides SELECT) 3.) Allow prepared Statements that do not change data 4.) Works with wsrep_sync_wait enabled
You also seemed to have made the variable available as a command line option. Please specify that as well.
--- .../suite/galera/r/galera_var_dirty_reads.result | 29 +++++++++++++++++++--- .../suite/galera/t/galera_var_dirty_reads.test | 25 ++++++++++++++++++- .../sys_vars/r/wsrep_dirty_reads_basic.result | 19 ++++++++++++-- .../suite/sys_vars/t/wsrep_dirty_reads_basic.test | 13 ++++++++-- sql/sql_parse.cc | 18 ++++++++++---- sql/sys_vars.cc | 4 +-- sql/wsrep_mysqld.cc | 3 ++- sql/wsrep_mysqld.h | 1 + 8 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index 6a2aa1e..d009c1b 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -28,9 +28,32 @@ SELECT @@max_allowed_packet; SELECT 2+2 from DUAL; 2+2 4 -SELECT sysdate() from DUAL; -sysdate() -2016-10-28 23:13:06 +SET @@session.wsrep_dirty_reads=ON; +SELECT * FROM t1; +i +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 +select * from t1; +i +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 SELECT * FROM t1; i 1
You're not really testing the global aspect of the variable here. You're only testing the sesssion behaviour of it. Also, test with it both ON and OFF (when setting it globally). Here's a sample that tests both session and global behaviour: --enable_connect_log SELECT @@expensive_subquery_limit; SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit; create user user1; create user user2; --connect (con1, localhost, user1,,) SELECT @@expensive_subquery_limit; SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit; connection default; SELECT @@expensive_subquery_limit; SET @@global.expensive_subquery_limit=400; SELECT @@expensive_subquery_limit; --connect (con2, localhost, user1,,) SELECT @@expensive_subquery_limit; connection default; drop user user1; drop user user2; ************************************ SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 100 SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 create user user1; create user user2; connect con1, localhost, user1,,; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 100 SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 connection default; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 SET @@global.expensive_subquery_limit=400; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 connect con2, localhost, user1,,; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 400 connection default; drop user user1; drop user user2; Notice how the last connection has the default value 400 as that's the global value. For your use case, you'd also have to execute the prepared statements to see if it works (execute select_stmt).
diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index dd7bc88..44931aa 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -44,7 +44,30 @@ SET @@session.wsrep_dirty_reads=OFF; SELECT 2; SELECT @@max_allowed_packet; SELECT 2+2 from DUAL; -SELECT sysdate() from DUAL; + +#Query which does not change data should be allowed MDEV-11479 +SET @@session.wsrep_dirty_reads=ON; +SELECT * FROM t1; + +#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)'; + +#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
I don't think you're testing this correctly. See my comment on the if statement which is supposed to govern this.
+select * from t1; +execute stmt_show; +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert;
--disable_query_log --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' 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 index d2a62d6..649ac83 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result @@ -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,6 +25,20 @@ 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'
Test invalid values for global scope as well. It should not change obviously but since we're writing tests, might as well do that too.
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 index a47524f..000c4c4 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test @@ -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; @@ -22,6 +22,15 @@ 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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index eb4f714..a56d694 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2393,10 +2393,11 @@ mysql_execute_command(THD *thd) */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && - !(thd->variables.wsrep_dirty_reads && - lex->sql_command == SQLCOM_SELECT) && - !(lex->sql_command == SQLCOM_SELECT && - !all_tables) && + !(thd->variables.wsrep_dirty_reads && + (sql_command_flags[lex->sql_command] & + CF_CHANGES_DATA) == 0) &&
Put this line on one line only, the single & is confusing, or better, turn it into a small inline function, such as command_changes_data()
+ !(lex->sql_command == SQLCOM_SELECT && + !all_tables) &&
Can't tell for certain but this condition might not be necessary if you have the previous one. What happens when you have a stored procedure that inserts into a table? Does the CF_CHANGES_DATA flag filter out the query or not? ex: select function_with_side_efect(1); This seems like a good test case that I'm not sure is tested for this variable anyway. Please try it.
!wsrep_is_show_query(lex->sql_command)) { #if DIRTY_HACK @@ -2512,7 +2513,14 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; + /* + 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 + */
This here is not correct. This will not execute the select if
wsrep_dirty_reads is true and wsrep_ready is true and wsrep_sync_wait(thd) is non-zero. if (WSREP_CLIENT(thd) && thd->variables.wsrep_dirty_reads(wsrep_ready
+ if (WSREP_CLIENT(thd) && (wsrep_ready || !thd->variables.wsrep_dirty_reads) + && wsrep_sync_wait(thd)) + goto error
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index bdcedff..0d864f4 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3967,8 +3967,8 @@ static Sys_var_mybool Sys_wsrep_restart_slave(
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); + "is not ready.", SESSION_VAR(wsrep_dirty_reads),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG);
We might need a guard here since global variables can be changed from multiple places. Not 100% sure about this but that's my intuition. Need to look this up.
#endif /* WITH_WSREP */
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 48114fc..f21ff92 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -65,7 +65,8 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave // restart will be needed my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks - +bool wsrep_dirty_reads = 0; // is dirty reads allowed for + // disconnectd/non major node
Typo: disconnectd -> disconnected. I really hate how the whole file is set up with TRUE/FALSE/0 for either bool or my_bool. It's so inconsistent. I'd prefer 'true' here to complicate stuff further. :) To be "consistent" I'd make it a my_bool, but we should clean up all of this mess at one point.
/* Set during the creation of first wsrep applier and rollback threads. Since these threads are critical, abort if the thread creation fails. diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 3fb5189..9b9179a 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -85,6 +85,7 @@ extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_rows; extern const char* wsrep_notify_cmd; extern my_bool wsrep_certify_nonPK; +extern bool wsrep_dirty_reads;
Remember to update the type here too.
extern long wsrep_max_protocol_version; extern long wsrep_protocol_version; extern ulong wsrep_forced_binlog_format;
Hi Vicentiu! Please review the updated patch. On Thu, Dec 8, 2016 at 4:42 PM, Vicențiu Ciorbaru <vicentiu@mariadb.org> wrote:
Hi Sachin!
Comments inline:
On Sun, 4 Dec 2016 at 08:36 <sachin.setiya@mariadb.com> wrote:
revision-id: 27af98805c27c8e0c41dc8c19bf80aefff4c6d3d (mariadb-galera-5.5.53-3-g27af988) parent(s): 72fd15f7c31aa3e3705ae1b005a3247a985c5bb3 author: SachinSetiya committer: SachinSetiya
NIT: To get these to display correctly you should have a space between Sachin and Setiya.
Done :)
timestamp: 2016-12-04 12:05:05 +0530 message:
MDEV-11479 Improved wsrep_dirty_reads
Tasks:- Changes in wsrep_dirty_reads variable 1.) Global + Session scope (Current: session-only) 2.) Allow all commands that do not change data (besides SELECT) 3.) Allow prepared Statements that do not change data 4.) Works with wsrep_sync_wait enabled
You also seemed to have made the variable available as a command line option. Please specify that as well.
Done.
--- .../suite/galera/r/galera_var_dirty_reads.result | 29 +++++++++++++++++++--- .../suite/galera/t/galera_var_dirty_reads.test | 25 ++++++++++++++++++- .../sys_vars/r/wsrep_dirty_reads_basic.result | 19 ++++++++++++-- .../suite/sys_vars/t/wsrep_dirty_reads_basic.test | 13 ++++++++-- sql/sql_parse.cc | 18 ++++++++++---- sql/sys_vars.cc | 4 +-- sql/wsrep_mysqld.cc | 3 ++- sql/wsrep_mysqld.h | 1 + 8 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index 6a2aa1e..d009c1b 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -28,9 +28,32 @@ SELECT @@max_allowed_packet; SELECT 2+2 from DUAL; 2+2 4 -SELECT sysdate() from DUAL; -sysdate() -2016-10-28 23:13:06 +SET @@session.wsrep_dirty_reads=ON; +SELECT * FROM t1; +i +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 +select * from t1; +i +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 SELECT * FROM t1; i 1
You're not really testing the global aspect of the variable here. You're only testing the sesssion behaviour of it. Also, test with it both ON and OFF (when setting it globally). Here's a sample that tests both session and global behaviour:
--enable_connect_log
SELECT @@expensive_subquery_limit; SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit;
create user user1; create user user2; --connect (con1, localhost, user1,,) SELECT @@expensive_subquery_limit; SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit;
connection default;
SELECT @@expensive_subquery_limit; SET @@global.expensive_subquery_limit=400; SELECT @@expensive_subquery_limit;
--connect (con2, localhost, user1,,) SELECT @@expensive_subquery_limit;
connection default; drop user user1; drop user user2;
************************************
SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 100 SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 create user user1; create user user2; connect con1, localhost, user1,,; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 100 SET @@session.expensive_subquery_limit=300; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 connection default; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 SET @@global.expensive_subquery_limit=400; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 300 connect con2, localhost, user1,,; SELECT @@expensive_subquery_limit; @@expensive_subquery_limit 400 connection default; drop user user1; drop user user2;
Notice how the last connection has the default value 400 as that's the global value. For your use case, you'd also have to execute the prepared statements to see if it works (execute select_stmt).
Done.
diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index dd7bc88..44931aa 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -44,7 +44,30 @@ SET @@session.wsrep_dirty_reads=OFF; SELECT 2; SELECT @@max_allowed_packet; SELECT 2+2 from DUAL; -SELECT sysdate() from DUAL; + +#Query which does not change data should be allowed MDEV-11479 +SET @@session.wsrep_dirty_reads=ON; +SELECT * FROM t1; + +#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)'; + +#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
I don't think you're testing this correctly. See my comment on the if statement which is supposed to govern this.
+select * from t1; +execute stmt_show; +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert;
--disable_query_log --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' 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 index d2a62d6..649ac83 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result @@ -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,6 +25,20 @@ 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'
Test invalid values for global scope as well. It should not change obviously but since we're writing tests, might as well do that too.
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 index a47524f..000c4c4 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test @@ -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; @@ -22,6 +22,15 @@ 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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index eb4f714..a56d694 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2393,10 +2393,11 @@ mysql_execute_command(THD *thd) */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && - !(thd->variables.wsrep_dirty_reads && - lex->sql_command == SQLCOM_SELECT) && - !(lex->sql_command == SQLCOM_SELECT && - !all_tables) && + !(thd->variables.wsrep_dirty_reads && + (sql_command_flags[lex->sql_command] & + CF_CHANGES_DATA) == 0) &&
Put this line on one line only, the single & is confusing, or better, turn it into a small inline function, such as command_changes_data() Okay.
+ !(lex->sql_command == SQLCOM_SELECT && + !all_tables) &&
Can't tell for certain but this condition might not be necessary if you have the previous one. This is required by https://jira.mariadb.org/browse/MDEV-11016
Done. previous condition is only applied when wsrep_dirty reads is true, this is applied independent of wsrep_dirty_reads What happens when you have a stored procedure that inserts
into a table? Does the CF_CHANGES_DATA flag filter out the query or not? ex: select function_with_side_efect(1); This seems like a good test case that I'm not sure is tested for this variable anyway. Please try it. This wont work, because CREATE PROCEDURE , does changes the data. sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
!wsrep_is_show_query(lex->sql_command)) { #if DIRTY_HACK @@ -2512,7 +2513,14 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; + /* + 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 + */
This here is not correct. This will not execute the select if wsrep_dirty_reads is true and wsrep_ready is true and wsrep_sync_wait(thd) is non-zero. This is expected. If wsrep_ready is true, that means cluster is online and if wsrep_sync_wait returns some non zero value then we have to goto error. if (WSREP_CLIENT(thd) && thd->variables.wsrep_dirty_reads(wsrep_ready
+ if (WSREP_CLIENT(thd) && (wsrep_ready || !thd->variables.wsrep_dirty_reads) + && wsrep_sync_wait(thd)) + goto error
Actually original condition was
if (WSREP_CLIENT(thd)) { if (!wsrep_ready && thd->variables.wsrep_dirty_reads) ; else if(wsrep_sync_wait(thd)) goto error; } which I (with the help of wlad ) reduced it to above IF.
case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index bdcedff..0d864f4 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3967,8 +3967,8 @@ static Sys_var_mybool Sys_wsrep_restart_slave(
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); + "is not ready.", SESSION_VAR(wsrep_dirty_reads),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG);
We might need a guard here since global variables can be changed from multiple places. Not 100% sure about this but that's my intuition. Need to look this up.
I am not sure if I get this because global variables are guarded by LOCK_global_system_variables mutex. /* the define below means that there's no *second* mutex guard, LOCK_global_system_variables always guards all system variables */ #define NO_MUTEX_GUARD ((PolyLock*)0) And auto increment uses the same approach. static Sys_var_ulong Sys_auto_increment_increment( "auto_increment_increment", "Auto-increment columns are incremented by this", SESSION_VAR(auto_increment_increment), CMD_LINE(OPT_ARG), VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1), NO_MUTEX_GUARD, IN_BINLOG)
#endif /* WITH_WSREP */
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 48114fc..f21ff92 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -65,7 +65,8 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave // restart will be needed my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks - +bool wsrep_dirty_reads = 0; // is dirty reads allowed for + // disconnectd/non major node
Typo: disconnectd -> disconnected. I really hate how the whole file is set up with TRUE/FALSE/0 for either bool or my_bool. It's so inconsistent. I'd prefer 'true' here to complicate stuff further. :) To be "consistent" I'd make it a my_bool, but we should clean up all of this mess at one point.
Done, I value changed to false.
/* Set during the creation of first wsrep applier and rollback threads. Since these threads are critical, abort if the thread creation fails. diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 3fb5189..9b9179a 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -85,6 +85,7 @@ extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_rows; extern const char* wsrep_notify_cmd; extern my_bool wsrep_certify_nonPK; +extern bool wsrep_dirty_reads;
Remember to update the type here too. Done.
extern long wsrep_max_protocol_version; extern long wsrep_protocol_version; extern ulong wsrep_forced_binlog_format;
-- Regards Sachin Setiya Software Engineer at MariaDB
participants (2)
-
Sachin Setiya
-
Vicențiu Ciorbaru