Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions mysql-test/suite/galera/r/MDEV-37229.result
Original file line number Diff line number Diff line change
@@ -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;
26 changes: 26 additions & 0 deletions mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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';
Expand Down
49 changes: 49 additions & 0 deletions mysql-test/suite/galera/t/MDEV-37229.test
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 10 additions & 1 deletion mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions sql/sql_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions sql/wsrep_applier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,30 @@ int wsrep_apply_events(THD* thd,
}
}

/* Statement-based replication requires InnoDB repeatable read

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some elaboration is needed in this comment:

  • As the transaction is already started in Wsrep_high_priority_service::start_transaction(), is the change of thd->tx_isolation fully effective here or does it just suppress some server level checks?
  • Is it possible that the write set contains both row and query events? In this case a row event could start a transaction with ISO_READ_COMMITTED and the following query event would be actually executed with read-committed isolation as the thd->tx_isolation is effective only when the transaction is started.
  • Should this apply only to DML or also to DDLs (which are replicated as TOI)?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a test that shows that mixed replication works for appliers, but I don't know if it's just a suppression of some server level checks or a true isolation level change. I would expect the former as InnoDB transaction is the same throughout the duration of a server transaction, and it seems that the isolation level is assigned to it only once from the beginning.
Regarding TOI, as it uses query events (statement-based replication), now it will run with 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))
Expand Down
1 change: 1 addition & 0 deletions sql/wsrep_schema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions sql/wsrep_storage_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down