diff options
m--------- | extra/wolfssl/wolfssl | 0 | ||||
m--------- | libmariadb | 0 | ||||
-rw-r--r-- | mysql-test/include/master-slave.inc | 1 | ||||
-rw-r--r-- | mysql-test/include/rpl_init.inc | 16 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/parallel_backup.result | 163 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/parallel_backup_lsu_off.result | 206 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/parallel_backup_slave_binlog_off.result | 206 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/parallel_backup.test | 29 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt | 2 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/parallel_backup_lsu_off.test | 7 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test | 7 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/parallel_backup_xa.inc | 79 | ||||
-rw-r--r-- | sql/handler.cc | 4 | ||||
-rw-r--r-- | sql/log.cc | 15 | ||||
-rw-r--r-- | sql/rpl_rli.cc | 8 | ||||
-rw-r--r-- | sql/xa.cc | 71 |
17 files changed, 782 insertions, 33 deletions
diff --git a/extra/wolfssl/wolfssl b/extra/wolfssl/wolfssl -Subproject 4fbd4fd36a21efd9d1a7e17aba390e91c78693b +Subproject f1e2165c591f074feb47872a8ff712713ec411e diff --git a/libmariadb b/libmariadb -Subproject d204e83104222844251b221e9be7eb3dd9f8d63 +Subproject 7fdb3eab66384a355475704332d11cc1ab82499 diff --git a/mysql-test/include/master-slave.inc b/mysql-test/include/master-slave.inc index 9ed206b2c22..17c8dd3ed4e 100644 --- a/mysql-test/include/master-slave.inc +++ b/mysql-test/include/master-slave.inc @@ -11,6 +11,7 @@ # [--let $rpl_skip_start_slave= 1] # [--let $rpl_debug= 1] # [--let $slave_timeout= NUMBER] +# [--let $rpl_server_skip_log_bin= 1] # --source include/master-slave.inc # # Parameters: diff --git a/mysql-test/include/rpl_init.inc b/mysql-test/include/rpl_init.inc index 4ee4cccdc20..acb9104ae6f 100644 --- a/mysql-test/include/rpl_init.inc +++ b/mysql-test/include/rpl_init.inc @@ -73,6 +73,7 @@ # before CHANGE MASTER and START SLAVE. RESET MASTER and RESET # SLAVE are suppressed if $rpl_skip_reset_master_and_slave is # set. +# Also see $rpl_server_skip_log_bin. # # $rpl_skip_change_master # By default, this script issues CHANGE MASTER so that all slaves @@ -94,6 +95,10 @@ # Timeout used when waiting for the slave threads to start. # See include/wait_for_slave_param.inc # +# $rpl_server_skip_log_bin +# When $rpl_skip_reset_master_and_slave is not set +# RESET MASTER does not report ER_FLUSH_MASTER_BINLOG_CLOSED +# on any server. # # ==== Side effects ==== # @@ -161,7 +166,16 @@ while ($_rpl_server) USE test; if (!$rpl_skip_reset_master_and_slave) { - RESET MASTER; + if (!$rpl_server_skip_log_bin) + { + --error 0 + RESET MASTER; + } + if ($rpl_server_skip_log_bin) + { + --error 0,ER_FLUSH_MASTER_BINLOG_CLOSED + RESET MASTER; + } SET GLOBAL gtid_slave_pos= ""; RESET SLAVE; } diff --git a/mysql-test/suite/rpl/r/parallel_backup.result b/mysql-test/suite/rpl/r/parallel_backup.result index d87c61f2d0f..99f43972118 100644 --- a/mysql-test/suite/rpl/r/parallel_backup.result +++ b/mysql-test/suite/rpl/r/parallel_backup.result @@ -7,6 +7,8 @@ include/master-slave.inc connection master; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb; connection slave; +call mtr.add_suppression("Deadlock found when trying to get lock"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit"); include/stop_slave.inc SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads; SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; @@ -30,6 +32,167 @@ connection backup_slave; BACKUP STAGE END; connection slave; include/diff_tables.inc [master:t1,slave:t1] +# MDEV-30423: dealock XA COMMIT vs BACKUP +# +# Normal XA COMMIT +connection slave; +include/stop_slave.inc +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (4); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (3); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (4); +connection master; +XA COMMIT '1'; +include/save_master_gtid.inc +connection slave; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +# +# Normal XA ROLLBACK +connection slave; +include/stop_slave.inc +Warnings: +Note 1255 Slave already has been stopped +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (6); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (5); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (6); +connection master; +XA ROLLBACK '1'; +include/save_master_gtid.inc +connection slave; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +# +# Errored out XA COMMIT +connection slave; +include/stop_slave.inc +Warnings: +Note 1255 Slave already has been stopped +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (8); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (7); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (8); +connection master; +XA COMMIT '1'; +include/save_master_gtid.inc +connection slave; +SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; +SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; +SET @@global.innodb_lock_wait_timeout =1; +SET @@global.slave_transaction_retries=0; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/stop_slave.inc +SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; +SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +connection slave; +include/start_slave.inc +include/sync_with_master_gtid.inc +# +# Errored out XA ROLLBACK +connection slave; +include/stop_slave.inc +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (10); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (9); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (10); +connection master; +XA ROLLBACK '1'; +include/save_master_gtid.inc +connection slave; +SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; +SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; +SET @@global.innodb_lock_wait_timeout =1; +SET @@global.slave_transaction_retries=0; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/stop_slave.inc +SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; +SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +connection slave; +include/start_slave.inc +include/sync_with_master_gtid.inc connection slave; include/stop_slave.inc SET @@global.slave_parallel_threads= @old_parallel_threads; diff --git a/mysql-test/suite/rpl/r/parallel_backup_lsu_off.result b/mysql-test/suite/rpl/r/parallel_backup_lsu_off.result new file mode 100644 index 00000000000..2c3d8556c27 --- /dev/null +++ b/mysql-test/suite/rpl/r/parallel_backup_lsu_off.result @@ -0,0 +1,206 @@ +# Specialized --log-slave-updates = 0 version of parallel_backup test. +# MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +# MDEV-30423: dealock XA COMMIT vs BACKUP +include/master-slave.inc +[connection master] +# +# MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +# replication +# +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb; +connection slave; +call mtr.add_suppression("Deadlock found when trying to get lock"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit"); +include/stop_slave.inc +SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; +SET @@global.slave_parallel_threads= 2; +SET @@global.slave_parallel_mode = 'optimistic'; +connection master; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +connect aux_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,; +BEGIN; +INSERT INTO t1 VALUES (1); +connection slave; +include/start_slave.inc +connection aux_slave; +connect backup_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/diff_tables.inc [master:t1,slave:t1] +# MDEV-30423: dealock XA COMMIT vs BACKUP +# +# Normal XA COMMIT +connection slave; +include/stop_slave.inc +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (4); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (3); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (4); +connection master; +XA COMMIT '1'; +include/save_master_gtid.inc +connection slave; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +# +# Normal XA ROLLBACK +connection slave; +include/stop_slave.inc +Warnings: +Note 1255 Slave already has been stopped +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (6); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (5); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (6); +connection master; +XA ROLLBACK '1'; +include/save_master_gtid.inc +connection slave; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +# +# Errored out XA COMMIT +connection slave; +include/stop_slave.inc +Warnings: +Note 1255 Slave already has been stopped +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (8); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (7); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (8); +connection master; +XA COMMIT '1'; +include/save_master_gtid.inc +connection slave; +SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; +SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; +SET @@global.innodb_lock_wait_timeout =1; +SET @@global.slave_transaction_retries=0; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/stop_slave.inc +SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; +SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +connection slave; +include/start_slave.inc +include/sync_with_master_gtid.inc +# +# Errored out XA ROLLBACK +connection slave; +include/stop_slave.inc +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (10); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (9); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (10); +connection master; +XA ROLLBACK '1'; +include/save_master_gtid.inc +connection slave; +SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; +SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; +SET @@global.innodb_lock_wait_timeout =1; +SET @@global.slave_transaction_retries=0; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/stop_slave.inc +SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; +SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +connection slave; +include/start_slave.inc +include/sync_with_master_gtid.inc +connection slave; +include/stop_slave.inc +SET @@global.slave_parallel_threads= @old_parallel_threads; +SET @@global.slave_parallel_mode = @old_parallel_mode; +include/start_slave.inc +connection server_1; +DROP TABLE t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/parallel_backup_slave_binlog_off.result b/mysql-test/suite/rpl/r/parallel_backup_slave_binlog_off.result new file mode 100644 index 00000000000..397a8708caa --- /dev/null +++ b/mysql-test/suite/rpl/r/parallel_backup_slave_binlog_off.result @@ -0,0 +1,206 @@ +# Specialized --skip-log-bin slave version of parallel_backup test. +# MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +# MDEV-30423: dealock XA COMMIT vs BACKUP +include/master-slave.inc +[connection master] +# +# MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +# replication +# +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb; +connection slave; +call mtr.add_suppression("Deadlock found when trying to get lock"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit"); +include/stop_slave.inc +SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; +SET @@global.slave_parallel_threads= 2; +SET @@global.slave_parallel_mode = 'optimistic'; +connection master; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +connect aux_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,; +BEGIN; +INSERT INTO t1 VALUES (1); +connection slave; +include/start_slave.inc +connection aux_slave; +connect backup_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/diff_tables.inc [master:t1,slave:t1] +# MDEV-30423: dealock XA COMMIT vs BACKUP +# +# Normal XA COMMIT +connection slave; +include/stop_slave.inc +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (4); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (3); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (4); +connection master; +XA COMMIT '1'; +include/save_master_gtid.inc +connection slave; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +# +# Normal XA ROLLBACK +connection slave; +include/stop_slave.inc +Warnings: +Note 1255 Slave already has been stopped +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (6); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (5); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (6); +connection master; +XA ROLLBACK '1'; +include/save_master_gtid.inc +connection slave; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +# +# Errored out XA COMMIT +connection slave; +include/stop_slave.inc +Warnings: +Note 1255 Slave already has been stopped +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (8); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (7); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (8); +connection master; +XA COMMIT '1'; +include/save_master_gtid.inc +connection slave; +SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; +SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; +SET @@global.innodb_lock_wait_timeout =1; +SET @@global.slave_transaction_retries=0; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/stop_slave.inc +SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; +SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +connection slave; +include/start_slave.inc +include/sync_with_master_gtid.inc +# +# Errored out XA ROLLBACK +connection slave; +include/stop_slave.inc +connection master; +connection aux_slave; +BEGIN; +INSERT INTO t1 VALUES (10); +connection master; +XA START '1'; +INSERT INTO t1 VALUES (9); +XA END '1'; +XA PREPARE '1'; +connection master1; +INSERT INTO t1 VALUES (10); +connection master; +XA ROLLBACK '1'; +include/save_master_gtid.inc +connection slave; +SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; +SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; +SET @@global.innodb_lock_wait_timeout =1; +SET @@global.slave_transaction_retries=0; +include/start_slave.inc +connection aux_slave; +# Xid '1' must be in the output: +XA RECOVER; +formatID gtrid_length bqual_length data +1 1 0 1 +connection backup_slave; +BACKUP STAGE START; +BACKUP STAGE BLOCK_COMMIT; +connection aux_slave; +ROLLBACK; +connection backup_slave; +BACKUP STAGE END; +connection slave; +include/stop_slave.inc +SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; +SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +connection slave; +include/start_slave.inc +include/sync_with_master_gtid.inc +connection slave; +include/stop_slave.inc +SET @@global.slave_parallel_threads= @old_parallel_threads; +SET @@global.slave_parallel_mode = @old_parallel_mode; +include/start_slave.inc +connection server_1; +DROP TABLE t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/parallel_backup.test b/mysql-test/suite/rpl/t/parallel_backup.test index 6ed182c024b..3628d241ecb 100644 --- a/mysql-test/suite/rpl/t/parallel_backup.test +++ b/mysql-test/suite/rpl/t/parallel_backup.test @@ -12,6 +12,9 @@ CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb; --sync_slave_with_master +call mtr.add_suppression("Deadlock found when trying to get lock"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit"); + --source include/stop_slave.inc SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads; SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; @@ -61,6 +64,32 @@ BACKUP STAGE END; --let $diff_tables= master:t1,slave:t1 --source include/diff_tables.inc +# +--echo # MDEV-30423: dealock XA COMMIT vs BACKUP +# Prove XA "COMPLETE" 'xid' does not dealock similary to the normal trx case. +# The slave binlog group commit leader is blocked by a local trx like in +# the above normal trx case. +# [Notice a reuse of t1,aux_conn from above.] +# +--let $complete = COMMIT +--source parallel_backup_xa.inc +--let $complete = ROLLBACK +--source parallel_backup_xa.inc + +--let $slave_ooo_error = 1 +--let $complete = COMMIT +--source parallel_backup_xa.inc +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--let $slave_ooo_error = 1 +--let $complete = ROLLBACK +--source parallel_backup_xa.inc +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + # Clean up. --connection slave diff --git a/mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt b/mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt new file mode 100644 index 00000000000..2f2a9c436fc --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt @@ -0,0 +1,2 @@ +--log-slave-updates=0 + diff --git a/mysql-test/suite/rpl/t/parallel_backup_lsu_off.test b/mysql-test/suite/rpl/t/parallel_backup_lsu_off.test new file mode 100644 index 00000000000..8e2663077b2 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_lsu_off.test @@ -0,0 +1,7 @@ +# +--echo # Specialized --log-slave-updates = 0 version of parallel_backup test. +# +--echo # MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +--echo # MDEV-30423: dealock XA COMMIT vs BACKUP +--let $rpl_skip_reset_master_and_slave = 1 +--source parallel_backup.test diff --git a/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt new file mode 100644 index 00000000000..a02b6d05829 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt @@ -0,0 +1 @@ +--skip-log-bin
\ No newline at end of file diff --git a/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test new file mode 100644 index 00000000000..7cefbdb3ddd --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test @@ -0,0 +1,7 @@ +# +--echo # Specialized --skip-log-bin slave version of parallel_backup test. +# +--echo # MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +--echo # MDEV-30423: dealock XA COMMIT vs BACKUP +--let $rpl_server_skip_log_bin= 1 +--source parallel_backup.test diff --git a/mysql-test/suite/rpl/t/parallel_backup_xa.inc b/mysql-test/suite/rpl/t/parallel_backup_xa.inc new file mode 100644 index 00000000000..2d831199aa8 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_xa.inc @@ -0,0 +1,79 @@ +# Invoked from parallel_backup.test +# Parameters: +# $complete = COMMIT or ROLLBACK +# $slave_ooo_error = 1 means slave group commit did not succeed +# +--let $kind = Normal +if ($slave_ooo_error) +{ + --let $kind = Errored out +} +--echo # +--echo # $kind XA $complete + +--connection slave +--source include/stop_slave.inc + +--connection master +# val_0 is the first value to insert on master in prepared xa +# val_1 is the next one to insert which is the value to block on slave +--let $val_0 = `SELECT max(a)+1 FROM t1` +--let $val_1 = $val_0 +--inc $val_1 + +--connection aux_slave +BEGIN; +--eval INSERT INTO t1 VALUES ($val_1) + +--connection master +XA START '1'; +--eval INSERT INTO t1 VALUES ($val_0) +XA END '1'; +XA PREPARE '1'; +--connection master1 +--eval INSERT INTO t1 VALUES ($val_1) +--connection master +--eval XA $complete '1' +--source include/save_master_gtid.inc + +--connection slave +if ($slave_ooo_error) +{ + SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; + SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; + SET @@global.innodb_lock_wait_timeout =1; + SET @@global.slave_transaction_retries=0; +} +--source include/start_slave.inc +--connection aux_slave +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc +--echo # Xid '1' must be in the output: +XA RECOVER; +--connection backup_slave + BACKUP STAGE START; +--send BACKUP STAGE BLOCK_COMMIT +--connection aux_slave + --sleep 1 + if ($slave_ooo_error) + { + --let $wait_condition= SELECT COUNT(*) = 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" + --source include/wait_condition.inc + } + ROLLBACK; +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for backup lock" +--source include/wait_condition.inc +--connection backup_slave + --reap + BACKUP STAGE END; +--connection slave +if (!$slave_ooo_error) +{ + --source include/sync_with_master_gtid.inc +} +--source include/stop_slave.inc +if ($slave_ooo_error) +{ + SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; + SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +} diff --git a/sql/handler.cc b/sql/handler.cc index db04677e65b..d969c8c6ab8 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2165,7 +2165,7 @@ static my_bool xacommit_handlerton(THD *unused1, plugin_ref plugin, void *arg) { handlerton *hton= plugin_hton(plugin); - if (hton->recover) + if (hton->recover || (hton == binlog_hton && current_thd->rgi_slave)) { hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid); ((struct xahton_st *)arg)->result= 0; @@ -2177,7 +2177,7 @@ static my_bool xarollback_handlerton(THD *unused1, plugin_ref plugin, void *arg) { handlerton *hton= plugin_hton(plugin); - if (hton->recover) + if (hton->recover || (hton == binlog_hton && current_thd->rgi_slave)) { hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid); ((struct xahton_st *)arg)->result= 0; diff --git a/sql/log.cc b/sql/log.cc index 58e644bca4b..447176dd6c8 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1677,11 +1677,12 @@ int binlog_init(void *p) { binlog_hton->prepare= binlog_prepare; binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot; - binlog_hton->commit_by_xid= binlog_commit_by_xid; - binlog_hton->rollback_by_xid= binlog_rollback_by_xid; // recover needs to be set to make xa{commit,rollback}_handlerton effective binlog_hton->recover= binlog_xa_recover_dummy; } + binlog_hton->commit_by_xid= binlog_commit_by_xid; + binlog_hton->rollback_by_xid= binlog_rollback_by_xid; + binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN | HTON_NO_ROLLBACK; return 0; } @@ -2006,6 +2007,11 @@ static int binlog_commit_by_xid(handlerton *hton, XID *xid) int rc= 0; THD *thd= current_thd; + if (thd->is_current_stmt_binlog_disabled()) + { + return thd->wait_for_prior_commit(); + } + /* the asserted state can't be reachable with xa commit */ DBUG_ASSERT(!thd->get_stmt_da()->is_error() || thd->get_stmt_da()->sql_errno() != ER_XA_RBROLLBACK); @@ -2035,6 +2041,11 @@ static int binlog_rollback_by_xid(handlerton *hton, XID *xid) int rc= 0; THD *thd= current_thd; + if (thd->is_current_stmt_binlog_disabled()) + { + return thd->wait_for_prior_commit(); + } + if (thd->get_stmt_da()->is_error() && thd->get_stmt_da()->sql_errno() == ER_XA_RBROLLBACK) return rc; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 35d84792fcb..dbb54c7d0f0 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -2285,11 +2285,9 @@ void rpl_group_info::cleanup_context(THD *thd, bool error) if (unlikely(error)) { - /* - trans_rollback above does not rollback XA transactions - (todo/fixme consider to do so. - */ - if (thd->transaction->xid_state.is_explicit_XA()) + // leave alone any XA prepared transactions + if (thd->transaction->xid_state.is_explicit_XA() && + thd->transaction->xid_state.get_state_code() != XA_PREPARED) xa_trans_force_rollback(thd); thd->release_transactional_locks(); diff --git a/sql/xa.cc b/sql/xa.cc index e0defcb92ed..b83dcbf2085 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -600,6 +600,7 @@ bool trans_xa_commit(THD *thd) if (auto xs= xid_cache_search(thd, thd->lex->xid)) { + bool xid_deleted= false; res= xa_trans_rolled_back(xs); /* Acquire metadata lock which will ensure that COMMIT is blocked @@ -610,7 +611,7 @@ bool trans_xa_commit(THD *thd) */ MDL_request mdl_request; MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, - MDL_STATEMENT); + MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { @@ -621,25 +622,37 @@ bool trans_xa_commit(THD *thd) */ DBUG_ASSERT(thd->is_error()); - xs->acquired_to_recovered(); - DBUG_RETURN(true); + res= true; + goto _end_external_xid; } - DBUG_ASSERT(!xid_state.xid_cache_element); - - if (thd->wait_for_prior_commit()) + else { - DBUG_ASSERT(thd->is_error()); - - xs->acquired_to_recovered(); - DBUG_RETURN(true); + thd->backup_commit_lock= &mdl_request; } + DBUG_ASSERT(!xid_state.xid_cache_element); xid_state.xid_cache_element= xs; ha_commit_or_rollback_by_xid(thd->lex->xid, !res); - xid_state.xid_cache_element= 0; + if (!res && thd->is_error()) + { + // hton completion error retains xs/xid in the cache, + // unless there had been already one as reflected by `res`. + res= true; + goto _end_external_xid; + } + xid_cache_delete(thd, xs); + xid_deleted= true; + _end_external_xid: + xid_state.xid_cache_element= 0; res= res || thd->is_error(); - xid_cache_delete(thd, xs); + if (!xid_deleted) + xs->acquired_to_recovered(); + if (mdl_request.ticket) + { + thd->mdl_context.release_lock(mdl_request.ticket); + thd->backup_commit_lock= 0; + } } else my_error(ER_XAER_NOTA, MYF(0)); @@ -761,9 +774,11 @@ bool trans_xa_rollback(THD *thd) if (auto xs= xid_cache_search(thd, thd->lex->xid)) { + bool res; + bool xid_deleted= false; MDL_request mdl_request; MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, - MDL_STATEMENT); + MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { @@ -774,23 +789,33 @@ bool trans_xa_rollback(THD *thd) */ DBUG_ASSERT(thd->is_error()); - xs->acquired_to_recovered(); - DBUG_RETURN(true); + goto _end_external_xid; } - xa_trans_rolled_back(xs); - DBUG_ASSERT(!xid_state.xid_cache_element); - - if (thd->wait_for_prior_commit()) + else { - DBUG_ASSERT(thd->is_error()); - xs->acquired_to_recovered(); - DBUG_RETURN(true); + thd->backup_commit_lock= &mdl_request; } + res= xa_trans_rolled_back(xs); + DBUG_ASSERT(!xid_state.xid_cache_element); xid_state.xid_cache_element= xs; ha_commit_or_rollback_by_xid(thd->lex->xid, 0); - xid_state.xid_cache_element= 0; + if (!res && thd->is_error()) + { + goto _end_external_xid; + } xid_cache_delete(thd, xs); + xid_deleted= true; + + _end_external_xid: + xid_state.xid_cache_element= 0; + if (!xid_deleted) + xs->acquired_to_recovered(); + if (mdl_request.ticket) + { + thd->mdl_context.release_lock(mdl_request.ticket); + thd->backup_commit_lock= 0; + } } else my_error(ER_XAER_NOTA, MYF(0)); |