diff --git a/mysql-test/suite/galera/r/MDEV-37229.result b/mysql-test/suite/galera/r/MDEV-37229.result new file mode 100644 index 0000000000000..59d908c451e6f --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-37229.result @@ -0,0 +1,53 @@ +connection node_2; +connection node_1; +connection node_2; +connection node_1; +CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; +START TRANSACTION; +INSERT INTO t1(i) VALUES(NULL); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +INSERT INTO t1(i) VALUES(NULL); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +SET GLOBAL wsrep_forced_binlog_format='ROW'; +INSERT INTO t1(i) VALUES(NULL); +INSERT INTO t1(i) VALUES(NULL); +COMMIT; +SET GLOBAL wsrep_forced_binlog_format='ROW'; +START TRANSACTION; +INSERT INTO t1(i) VALUES(NULL); +INSERT INTO t1(i) VALUES(NULL); +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; +INSERT INTO t1(i) VALUES(NULL); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +INSERT INTO t1(i) VALUES(NULL); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +COMMIT; +SELECT * FROM t1 ORDER BY i; +i +1 +3 +5 +7 +9 +11 +13 +15 +connection node_2; +SELECT * FROM t1 ORDER BY i; +i +1 +3 +5 +7 +9 +11 +13 +15 +connection node_1; +SET GLOBAL wsrep_forced_binlog_format='NONE'; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result b/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result index 10b94fdbc0142..d4b025c3eb96b 100644 --- a/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result +++ b/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result @@ -33,6 +33,28 @@ i c 3 dummy_text 5 dummy_text 7 dummy_text +insert into t1(i) values(null); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +insert into t1(i) values(null); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +insert into t1(i) values(null); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +insert into t1(i) values(null); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave +select * from t1 order by i; +i c +1 dummy_text +3 dummy_text +5 dummy_text +7 dummy_text +9 dummy_text +11 dummy_text +13 dummy_text +15 dummy_text connection node_2; show variables like 'auto_increment%'; Variable_name Value @@ -44,6 +66,10 @@ i c 3 dummy_text 5 dummy_text 7 dummy_text +9 dummy_text +11 dummy_text +13 dummy_text +15 dummy_text SET GLOBAL wsrep_forced_binlog_format='none'; connection node_1; SET GLOBAL wsrep_forced_binlog_format='none'; diff --git a/mysql-test/suite/galera/t/MDEV-37229.test b/mysql-test/suite/galera/t/MDEV-37229.test new file mode 100644 index 0000000000000..8d1fc600330de --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-37229.test @@ -0,0 +1,49 @@ +## +## Test that mixed binlog replication works at the applier side. +## + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--connection node_2 +--disable_query_log +call mtr.add_suppression("Unsafe statement written to the binary log"); +--enable_query_log + +--connection node_1 +--disable_query_log +call mtr.add_suppression("Unsafe statement written to the binary log"); +--enable_query_log + +CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; + +# Try mixed replication: statement then row. +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; +START TRANSACTION; +INSERT INTO t1(i) VALUES(NULL); +INSERT INTO t1(i) VALUES(NULL); +SET GLOBAL wsrep_forced_binlog_format='ROW'; +INSERT INTO t1(i) VALUES(NULL); +INSERT INTO t1(i) VALUES(NULL); +COMMIT; + +# Try mixed replication: row then statement. +SET GLOBAL wsrep_forced_binlog_format='ROW'; +START TRANSACTION; +INSERT INTO t1(i) VALUES(NULL); +INSERT INTO t1(i) VALUES(NULL); +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; +INSERT INTO t1(i) VALUES(NULL); +INSERT INTO t1(i) VALUES(NULL); +COMMIT; + +SELECT * FROM t1 ORDER BY i; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 8 FROM t1; +--source include/wait_condition.inc +SELECT * FROM t1 ORDER BY i; + +--connection node_1 +SET GLOBAL wsrep_forced_binlog_format='NONE'; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf index 00e5017455f2e..d176cdd845ddd 100644 --- a/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf +++ b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf @@ -5,5 +5,6 @@ auto_increment_offset=1 auto_increment_increment=2 [mysqld.2] +wsrep_slave_threads=2 auto_increment_offset=2 auto_increment_increment=2 diff --git a/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test index 81bf673808657..3998da5cca974 100644 --- a/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test +++ b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test @@ -48,8 +48,17 @@ insert into t1(i) values(null), (null), (null); select * from t1 order by i; +# Ensure both appliers have some work to perform in parallel. +# This way we can see they both have proper isolation level set. +insert into t1(i) values(null); +insert into t1(i) values(null); +insert into t1(i) values(null); +insert into t1(i) values(null); + +select * from t1 order by i; + --connection node_2 ---let $wait_condition = SELECT COUNT(*) = 4 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 8 FROM t1; --source include/wait_condition.inc show variables like 'auto_increment%'; select * from t1 order by i; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index c7fad3a9a59ef..03f89c3de9f54 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -4547,6 +4547,8 @@ my_bool post_init_callback(THD *thd, void *) thd->variables.tx_read_only= false; // Restore option_bits thd->variables.option_bits= option_bits_saved; + // Restore proper default isolation level for appliers + thd->variables.tx_isolation= ISO_READ_COMMITTED; } set_current_thd(0); return 0; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index 4eaef4fb48980..dfd2070856143 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -279,6 +279,30 @@ int wsrep_apply_events(THD* thd, } } + /* Statement-based replication requires InnoDB repeatable read + transaction isolation level or higher. + The isolation level will be reset to the default upon + transaction termination. + Although the isolation level can only be set on a newly + started server transaction, it cannot be determined until + we see the first applied binlog event. + + Even though the isolation level is changed for every next + applied event, it won't affect the overall setting for a + running transaction. + This should create an issue with the mixed replication mode + as applying query and row events should be performed with + different isolation levels, but now it doesn't surface. + */ + if (LOG_EVENT_IS_QUERY(typ)) + { + thd->tx_isolation= ISO_REPEATABLE_READ; + } + else + { + thd->tx_isolation= ISO_READ_COMMITTED; + } + if (LOG_EVENT_IS_WRITE_ROW(typ) || LOG_EVENT_IS_UPDATE_ROW(typ) || LOG_EVENT_IS_DELETE_ROW(typ)) diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index dcce91e71f0dd..b1b651928f780 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -730,6 +730,7 @@ static void wsrep_init_thd_variables(THD *thd) /* No general log */ thd->variables.option_bits|= OPTION_LOG_OFF; /* Read committed isolation to avoid gap locking */ + thd->tx_isolation= ISO_READ_COMMITTED; thd->variables.tx_isolation= ISO_READ_COMMITTED; } diff --git a/sql/wsrep_storage_service.cc b/sql/wsrep_storage_service.cc index 7e9229c65e093..72ad3949a3ac1 100644 --- a/sql/wsrep_storage_service.cc +++ b/sql/wsrep_storage_service.cc @@ -63,6 +63,7 @@ Wsrep_storage_service::Wsrep_storage_service(THD* thd) thd->variables.option_bits |= OPTION_LOG_OFF; /* Read committed isolation to avoid gap locking */ + thd->tx_isolation = ISO_READ_COMMITTED; thd->variables.tx_isolation = ISO_READ_COMMITTED; /* Keep wsrep on to enter commit ordering hooks */