summaryrefslogtreecommitdiff
path: root/mysql-test/suite
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2023-01-31 09:31:42 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2023-01-31 09:31:42 +0100
commitc3a5cf2b5bb0c0e1623a0ddc8e3d49557f35e800 (patch)
tree0e47046f09c1ad4a4223e45d7ac2c41406272b92 /mysql-test/suite
parent81196469bbc6b8424c97a378e5fc5b16d40b43b5 (diff)
parentf8a85af8ca1c937b8d4f847477bd282f80251cde (diff)
downloadmariadb-git-c3a5cf2b5bb0c0e1623a0ddc8e3d49557f35e800.tar.gz
Merge branch '10.5' into 10.6
Diffstat (limited to 'mysql-test/suite')
-rw-r--r--mysql-test/suite/binlog/r/innodb_rc_insert_before_delete.result53
-rw-r--r--mysql-test/suite/binlog/t/innodb_rc_insert_before_delete.test92
-rw-r--r--mysql-test/suite/encryption/r/tempfiles_encrypted.result40
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test5
-rw-r--r--mysql-test/suite/mariabackup/incremental_drop_db.result30
-rw-r--r--mysql-test/suite/mariabackup/incremental_drop_db.test68
-rw-r--r--mysql-test/suite/plugins/r/server_audit.result7
-rw-r--r--mysql-test/suite/plugins/t/server_audit.test5
-rw-r--r--mysql-test/suite/rpl/include/create_or_drop_sync_func.inc75
-rw-r--r--mysql-test/suite/rpl/r/parallel_backup.result163
-rw-r--r--mysql-test/suite/rpl/r/parallel_backup_lsu_off.result207
-rw-r--r--mysql-test/suite/rpl/r/parallel_backup_slave_binlog_off.result207
-rw-r--r--mysql-test/suite/rpl/r/rpl_delayed_parallel_slave_sbm.result60
-rw-r--r--mysql-test/suite/rpl/r/rpl_parallel_analyze.result76
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup.test29
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt2
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup_lsu_off.test7
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt1
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test7
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup_xa.inc79
-rw-r--r--mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm-slave.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm.test133
-rw-r--r--mysql-test/suite/rpl/t/rpl_parallel_analyze.test84
23 files changed, 1426 insertions, 5 deletions
diff --git a/mysql-test/suite/binlog/r/innodb_rc_insert_before_delete.result b/mysql-test/suite/binlog/r/innodb_rc_insert_before_delete.result
new file mode 100644
index 00000000000..d4bd5ee07bf
--- /dev/null
+++ b/mysql-test/suite/binlog/r/innodb_rc_insert_before_delete.result
@@ -0,0 +1,53 @@
+RESET MASTER;
+connect pause_purge,localhost,root;
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+connection default;
+CREATE TABLE t (pk int PRIMARY KEY, sk INT UNIQUE) ENGINE=InnoDB;
+INSERT INTO t VALUES (10, 100);
+connect con1,localhost,root;
+BEGIN;
+SELECT * FROM t WHERE sk = 100 FOR UPDATE;
+pk sk
+10 100
+connect con2,localhost,root;
+SET DEBUG_SYNC="lock_wait_start SIGNAL insert_wait_started";
+INSERT INTO t VALUES (5, 100) # trx 1;
+connect con3,localhost,root;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SET DEBUG_SYNC="now WAIT_FOR insert_wait_started";
+SET DEBUG_SYNC="lock_wait_start SIGNAL delete_started_waiting";
+BEGIN;
+UPDATE t SET sk = 200 WHERE sk = 100; # trx 2;
+connection con1;
+SET DEBUG_SYNC="now WAIT_FOR delete_started_waiting";
+DELETE FROM t WHERE sk=100;
+COMMIT;
+disconnect con1;
+connection con2;
+disconnect con2;
+connection con3;
+must be logged in ROW format as the only event of trx 2 (con3)
+INSERT INTO t VALUES (11, 101);
+COMMIT;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; DELETE FROM t WHERE sk=100
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (5, 100) # trx 1
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Annotate_rows # # INSERT INTO t VALUES (11, 101)
+master-bin.000001 # Table_map # # table_id: # (test.t)
+master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000001 # Xid # # COMMIT /* XID */
+disconnect con3;
+connection default;
+SELECT * FROM t;
+pk sk
+5 100
+11 101
+disconnect pause_purge;
+SET DEBUG_SYNC="RESET";
+DROP TABLE t;
diff --git a/mysql-test/suite/binlog/t/innodb_rc_insert_before_delete.test b/mysql-test/suite/binlog/t/innodb_rc_insert_before_delete.test
new file mode 100644
index 00000000000..228d9778f56
--- /dev/null
+++ b/mysql-test/suite/binlog/t/innodb_rc_insert_before_delete.test
@@ -0,0 +1,92 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_mixed.inc
+--source include/count_sessions.inc
+
+RESET MASTER;
+
+# MDEV-30010 merely adds is a Read-Committed version MDEV-30225 test
+# solely to prove the RC isolation yields ROW binlog format as it is
+# supposed to:
+# https://mariadb.com/kb/en/unsafe-statements-for-statement-based-replication/#isolation-levels.
+# The original MDEV-30225 test is adapted to the RC to create
+# a similar safisticated scenario which does not lead to any deadlock though.
+
+--connect (pause_purge,localhost,root)
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+
+--connection default
+CREATE TABLE t (pk int PRIMARY KEY, sk INT UNIQUE) ENGINE=InnoDB;
+INSERT INTO t VALUES (10, 100);
+
+--connect (con1,localhost,root)
+BEGIN; # trx 0
+SELECT * FROM t WHERE sk = 100 FOR UPDATE;
+
+--connect (con2,localhost,root)
+SET DEBUG_SYNC="lock_wait_start SIGNAL insert_wait_started";
+# trx 1 is locked on try to read the record in secondary index during duplicates
+# check. It's the first in waiting queue, that's why it will be woken up firstly
+# when trx 0 commits.
+--send INSERT INTO t VALUES (5, 100) # trx 1
+
+--connect (con3,localhost,root)
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SET DEBUG_SYNC="now WAIT_FOR insert_wait_started";
+SET DEBUG_SYNC="lock_wait_start SIGNAL delete_started_waiting";
+# trx 2 can delete (5, 100) on master, but not on slave, as on slave trx 1
+# can insert (5, 100) after trx 2 positioned it's cursor. Trx 2 lock is placed
+# in waiting queue after trx 1 lock, but its persistent cursor position was
+# stored on (100, 10) record in secondary index before suspending. After trx 1
+# is committed, trx 2 will restore persistent cursor position on (100, 10). As
+# (100, 5) secondary index record was inserted before (100, 10) in logical
+# order, and (100, 10) record is delete-marked, trx 2 just continues scanning.
+#
+# Note. There can be several records with the same key in unique secondary
+# index, but only one of them must be non-delete-marked. That's why when we do
+# point query, cursor position is set in the first record in logical order, and
+# then records are iterated until either non-delete-marked record is found or
+# all records with the same unique fields are iterated.
+
+# to prepare showing interesting binlog events
+--let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1)
+--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1)
+BEGIN;
+--send UPDATE t SET sk = 200 WHERE sk = 100; # trx 2
+
+--connection con1
+SET DEBUG_SYNC="now WAIT_FOR delete_started_waiting";
+DELETE FROM t WHERE sk=100; # trx 0
+COMMIT;
+--disconnect con1
+
+--connection con2
+--reap
+--disconnect con2
+
+--connection con3
+--error 0
+--reap
+if (`SELECT ROW_COUNT() > 0`)
+{
+ --echo unexpected effective UPDATE
+ --die
+}
+--echo must be logged in ROW format as the only event of trx 2 (con3)
+INSERT INTO t VALUES (11, 101);
+COMMIT;
+--source include/show_binlog_events.inc
+--disconnect con3
+
+--connection default
+# If the bug is not fixed, we will see the row inserted by trx 1 here. This can
+# cause duplicate key error on slave, when some other trx tries in insert row
+# with the same secondary key, as was inserted by trx 1, and not deleted by trx
+# 2.
+SELECT * FROM t;
+
+--disconnect pause_purge
+SET DEBUG_SYNC="RESET";
+DROP TABLE t;
+--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result
index 2b91cd638e2..8582d5dc713 100644
--- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result
+++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result
@@ -4345,6 +4345,46 @@ pk a bit_or
DROP TABLE t2;
DROP TABLE t1;
#
+# MDEV-15178: Filesort::make_sortorder: Assertion `pos->field != __null |
+#
+CREATE TABLE t1 (i1 int, a int);
+INSERT INTO t1 VALUES (1, 1), (2, 2),(3, 3);
+CREATE TABLE t2 (i2 int);
+INSERT INTO t2 VALUES (1),(2),(5),(1),(7),(4),(3);
+SELECT
+a,
+RANK() OVER (ORDER BY SUM(DISTINCT i1))
+FROM
+t1, t2 WHERE t2.i2 = t1.i1
+GROUP BY
+a;
+a RANK() OVER (ORDER BY SUM(DISTINCT i1))
+1 1
+2 2
+3 3
+DROP TABLE t1, t2;
+#
+# MDEV-17014: Crash server using ROW_NUMBER() OVER (PARTITION ..)
+#
+CREATE TABLE t1 (UID BIGINT);
+CREATE TABLE t2 (UID BIGINT);
+CREATE TABLE t3 (UID BIGINT);
+insert into t1 VALUES (1),(2);
+insert into t2 VALUES (1),(2);
+insert into t3 VALUES (1),(2);
+SELECT
+ROW_NUMBER() OVER (PARTITION BY GROUP_CONCAT(TT1.UID))
+FROM t1 TT1,
+t2 TT2,
+t3 TT3
+WHERE TT3.UID = TT1.UID AND TT2.UID = TT3.UID
+GROUP BY TT1.UID
+;
+ROW_NUMBER() OVER (PARTITION BY GROUP_CONCAT(TT1.UID))
+1
+1
+DROP TABLE t1, t2, t3;
+#
# End of 10.3 tests
#
#
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test
index 8f0f0ed65ea..214d5166781 100644
--- a/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test
+++ b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test
@@ -205,8 +205,3 @@ CALL mtr.add_suppression("conflict state 7 after post commit");
# Warning happens when the cluster is started for the first time
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
-
---connection node_2
-call mtr.add_suppression("Error in Log_event::read_log_event():.*");
-CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
-
diff --git a/mysql-test/suite/mariabackup/incremental_drop_db.result b/mysql-test/suite/mariabackup/incremental_drop_db.result
new file mode 100644
index 00000000000..3a6c89f8de0
--- /dev/null
+++ b/mysql-test/suite/mariabackup/incremental_drop_db.result
@@ -0,0 +1,30 @@
+call mtr.add_suppression("InnoDB: New log files created");
+#
+# Start of 10.3 tests
+#
+#
+# MDEV-23335 MariaBackup Incremental Does Not Reflect Dropped/Created Databases
+#
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+CREATE TABLE db1.t1 (a INT) ENGINE=MyISAM;
+CREATE TABLE db1.t2 (a INT) ENGINE=InnoDB;
+# Create base backup
+DROP DATABASE db1;
+# Create incremental backup
+# Remove incremental_dir/db2/db.opt file to make incremental_dir/db2/ empty
+# Prepare base backup, apply incremental one
+# shutdown server
+# remove datadir
+# xtrabackup move back
+# restart
+# Expect no 'db1' in the output, because it was really dropped.
+# Expect 'db2' in the ouput, because it was not dropped!
+# (its incremental directory was emptied only)
+SHOW DATABASES LIKE 'db%';
+Database (db%)
+db2
+DROP DATABASE db2;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/suite/mariabackup/incremental_drop_db.test b/mysql-test/suite/mariabackup/incremental_drop_db.test
new file mode 100644
index 00000000000..de270435e9d
--- /dev/null
+++ b/mysql-test/suite/mariabackup/incremental_drop_db.test
@@ -0,0 +1,68 @@
+--source include/have_innodb.inc
+call mtr.add_suppression("InnoDB: New log files created");
+
+--echo #
+--echo # Start of 10.3 tests
+--echo #
+
+--echo #
+--echo # MDEV-23335 MariaBackup Incremental Does Not Reflect Dropped/Created Databases
+--echo #
+
+--let $datadir=`SELECT @@datadir`
+--let $basedir=$MYSQLTEST_VARDIR/tmp/backup
+--let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1
+
+# Create two databases:
+# - db1 is dropped normally below
+# - db2 is used to cover a corner case: its db.opt file is removed
+
+# Incremental backup contains:
+# - no directory for db1
+# - an empty directory for db2 (after we remove db2/db.opt)
+
+
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+
+# Add some tables to db1
+CREATE TABLE db1.t1 (a INT) ENGINE=MyISAM;
+CREATE TABLE db1.t2 (a INT) ENGINE=InnoDB;
+
+--echo # Create base backup
+--disable_result_log
+--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir
+--enable_result_log
+
+DROP DATABASE db1;
+
+--echo # Create incremental backup
+--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir
+
+--echo # Remove incremental_dir/db2/db.opt file to make incremental_dir/db2/ empty
+--remove_file $incremental_dir/db2/db.opt
+
+
+--echo # Prepare base backup, apply incremental one
+--disable_result_log
+--exec $XTRABACKUP --prepare --target-dir=$basedir
+--exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir
+--enable_result_log
+
+--let $targetdir=$basedir
+--source include/restart_and_restore.inc
+--enable_result_log
+
+--echo # Expect no 'db1' in the output, because it was really dropped.
+--echo # Expect 'db2' in the ouput, because it was not dropped!
+--echo # (its incremental directory was emptied only)
+
+SHOW DATABASES LIKE 'db%';
+DROP DATABASE db2;
+
+--rmdir $basedir
+--rmdir $incremental_dir
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result
index 9768040aa94..fc9d98f5d0a 100644
--- a/mysql-test/suite/plugins/r/server_audit.result
+++ b/mysql-test/suite/plugins/r/server_audit.result
@@ -521,3 +521,10 @@ TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show status like \'server_audit_
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show variables like \'server_audit%\'',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,plugin,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'uninstall plugin server_audit',0
+#
+# MDEV-27631 Assertion `global_status_var.global_memory_used == 0' failed in mysqld_exit
+#
+install plugin server_audit soname 'server_audit';
+uninstall plugin server_audit;
+Warnings:
+Warning 1620 Plugin is busy and will be uninstalled on shutdown
diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test
index d8f8b9d0165..5048ccc2446 100644
--- a/mysql-test/suite/plugins/t/server_audit.test
+++ b/mysql-test/suite/plugins/t/server_audit.test
@@ -235,3 +235,8 @@ uninstall plugin server_audit;
cat_file $MYSQLD_DATADIR/server_audit.log;
remove_file $MYSQLD_DATADIR/server_audit.log;
+--echo #
+--echo # MDEV-27631 Assertion `global_status_var.global_memory_used == 0' failed in mysqld_exit
+--echo #
+install plugin server_audit soname 'server_audit';
+uninstall plugin server_audit;
diff --git a/mysql-test/suite/rpl/include/create_or_drop_sync_func.inc b/mysql-test/suite/rpl/include/create_or_drop_sync_func.inc
new file mode 100644
index 00000000000..74cde5de1db
--- /dev/null
+++ b/mysql-test/suite/rpl/include/create_or_drop_sync_func.inc
@@ -0,0 +1,75 @@
+# Creates or drops a stored function as a part of debug-sync based
+# synchronization mechanism between replication servers.
+#
+# Parameters:
+# $create_or_drop= [create]
+# $server_master = [master]
+# $server_slave = [slave]
+if (!$create_or_drop)
+{
+ --let $create_or_drop=create
+}
+
+if (`select strcmp('$create_or_drop', 'create') = 0`)
+{
+ if (!$server_master)
+ {
+ --let $server_master=master
+ }
+ if (!$server_slave)
+ {
+ --let $server_slave=slave
+ }
+
+ --connection $server_master
+ # Use a stored function to inject a debug_sync into the appropriate THD.
+ # The function does nothing on the master, and on the slave it injects the
+ # desired debug_sync action(s).
+ SET sql_log_bin=0;
+ --delimiter ||
+ CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+ RETURNS INT DETERMINISTIC
+ BEGIN
+ RETURN x;
+ END
+ ||
+ --delimiter ;
+ SET sql_log_bin=1;
+
+ --connection $server_slave
+
+ SET sql_log_bin=0;
+ --delimiter ||
+ CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+ RETURNS INT DETERMINISTIC
+ BEGIN
+ IF d1 != '' THEN
+ SET debug_sync = d1;
+ END IF;
+ IF d2 != '' THEN
+ SET debug_sync = d2;
+ END IF;
+ RETURN x;
+ END
+ ||
+ --delimiter ;
+SET sql_log_bin=1;
+}
+
+if (`select strcmp('$create_or_drop', 'drop') = 0`)
+{
+ if (!$server_slave)
+ {
+ --let $server_slave=slave=
+ }
+ if (!$server_master)
+ {
+ --let $server_master=master
+ }
+ --connection $server_slave
+ SET DEBUG_SYNC='RESET';
+
+ --connection $server_master
+ SET DEBUG_SYNC='RESET';
+ DROP FUNCTION foo;
+}
diff --git a/mysql-test/suite/rpl/r/parallel_backup.result b/mysql-test/suite/rpl/r/parallel_backup.result
index 9d394a220d5..7cf72ed15e4 100644
--- a/mysql-test/suite/rpl/r/parallel_backup.result
+++ b/mysql-test/suite/rpl/r/parallel_backup.result
@@ -8,6 +8,8 @@ connection master;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
INSERT INTO t1 VALUES(100);
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;
@@ -31,6 +33,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 (102);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (101);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (102);
+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 (104);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (103);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (104);
+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 (106);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (105);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (106);
+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 (108);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (107);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (108);
+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..b89cb154f24
--- /dev/null
+++ b/mysql-test/suite/rpl/r/parallel_backup_lsu_off.result
@@ -0,0 +1,207 @@
+# 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;
+INSERT INTO t1 VALUES(100);
+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 (102);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (101);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (102);
+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 (104);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (103);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (104);
+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 (106);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (105);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (106);
+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 (108);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (107);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (108);
+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..111bc7fb76f
--- /dev/null
+++ b/mysql-test/suite/rpl/r/parallel_backup_slave_binlog_off.result
@@ -0,0 +1,207 @@
+# 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;
+INSERT INTO t1 VALUES(100);
+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 (102);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (101);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (102);
+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 (104);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (103);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (104);
+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 (106);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (105);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (106);
+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 (108);
+connection master;
+XA START '1';
+INSERT INTO t1 VALUES (107);
+XA END '1';
+XA PREPARE '1';
+connection master1;
+INSERT INTO t1 VALUES (108);
+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/rpl_delayed_parallel_slave_sbm.result b/mysql-test/suite/rpl/r/rpl_delayed_parallel_slave_sbm.result
new file mode 100644
index 00000000000..f783b1e0783
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_delayed_parallel_slave_sbm.result
@@ -0,0 +1,60 @@
+include/master-slave.inc
+[connection master]
+connection slave;
+include/stop_slave.inc
+change master to master_delay=3, master_use_gtid=Slave_Pos;
+set @@GLOBAL.slave_parallel_threads=2;
+include/start_slave.inc
+connection master;
+create table t1 (a int);
+include/sync_slave_sql_with_master.inc
+#
+# Pt 1) Ensure SBM is updated immediately upon arrival of the next event
+# Lock t1 on slave so the first received transaction does not complete/commit
+connection slave;
+LOCK TABLES t1 WRITE;
+connection master;
+# Sleep 2 to allow a buffer between events for SBM check
+insert into t1 values (0);
+include/save_master_gtid.inc
+connection slave;
+# Waiting for transaction to arrive on slave and begin SQL Delay..
+# Validating SBM is updated on event arrival..
+# ..done
+connection slave;
+UNLOCK TABLES;
+include/sync_with_master_gtid.inc
+#
+# Pt 2) If the SQL thread has not entered an idle state, ensure
+# following events do not update SBM
+# Stop slave IO thread so it receives both events together on restart
+connection slave;
+include/stop_slave_io.inc
+connection master;
+# Sleep 2 to allow a buffer between events for SBM check
+insert into t1 values (1);
+# Sleep 3 to create gap between events
+insert into t1 values (2);
+connection slave;
+LOCK TABLES t1 WRITE;
+START SLAVE IO_THREAD;
+# Wait for first transaction to complete SQL delay and begin execution..
+# Validate SBM calculation doesn't use the second transaction because SQL thread shouldn't have gone idle..
+# ..and that SBM wasn't calculated using prior committed transactions
+# ..done
+connection slave;
+UNLOCK TABLES;
+#
+# Cleanup
+# Reset master_delay
+include/stop_slave.inc
+CHANGE MASTER TO master_delay=0;
+set @@GLOBAL.slave_parallel_threads=4;
+include/start_slave.inc
+connection master;
+DROP TABLE t1;
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+include/rpl_end.inc
+# End of rpl_delayed_parallel_slave_sbm.test
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_analyze.result b/mysql-test/suite/rpl/r/rpl_parallel_analyze.result
new file mode 100644
index 00000000000..c0a2abbc1ee
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_analyze.result
@@ -0,0 +1,76 @@
+include/master-slave.inc
+[connection master]
+# Initialize
+connection slave;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+# Setup data
+connection master;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE ta (a int);
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+connection master;
+SET sql_log_bin=0;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection slave;
+SET sql_log_bin=0;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+IF d1 != '' THEN
+SET debug_sync = d1;
+END IF;
+IF d2 != '' THEN
+SET debug_sync = d2;
+END IF;
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+include/stop_slave.inc
+SET @old_parallel_threads =@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode =@@GLOBAL.slave_parallel_mode;
+SET @old_gtid_strict_mode =@@GLOBAL.gtid_strict_mode;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode=conservative;
+SET GLOBAL gtid_strict_mode=ON;
+include/start_slave.inc
+connection master;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format=statement;
+INSERT INTO t1 VALUES (foo(1, 'rpl_parallel_after_mark_start_commit WAIT_FOR sig_go', ''));
+ANALYZE TABLE ta;
+Table Op Msg_type Msg_text
+test.ta analyze status Engine-independent statistics collected
+test.ta analyze status Table is already up to date
+include/save_master_gtid.inc
+connection slave;
+SELECT info FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit";
+info
+ANALYZE TABLE ta
+set @@debug_sync="now signal sig_go";
+include/sync_with_master_gtid.inc
+# Cleanup
+connection master;
+DROP TABLE t1,ta;
+connection slave;
+SET DEBUG_SYNC='RESET';
+connection master;
+SET DEBUG_SYNC='RESET';
+DROP FUNCTION foo;
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads;
+SET @@GLOBAL.slave_parallel_mode =@old_parallel_mode;
+SET @@GLOBAL.gtid_strict_mode =@old_gtid_strict_mode;
+include/start_slave.inc
+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 964e2a30309..4f5ffa9f291 100644
--- a/mysql-test/suite/rpl/t/parallel_backup.test
+++ b/mysql-test/suite/rpl/t/parallel_backup.test
@@ -15,6 +15,9 @@ CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
INSERT INTO t1 VALUES(100);
--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;
@@ -64,6 +67,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/mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm-slave.opt b/mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm-slave.opt
new file mode 100644
index 00000000000..9eea6a54b68
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm-slave.opt
@@ -0,0 +1 @@
+--slave-parallel-threads=4
diff --git a/mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm.test b/mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm.test
new file mode 100644
index 00000000000..4bcb7ad9e3f
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_delayed_parallel_slave_sbm.test
@@ -0,0 +1,133 @@
+#
+# This test ensures that after a delayed parallel slave has idled, i.e.
+# executed everything in its relay log, the next event group that the SQL
+# thread reads from the relay log will immediately be used in the
+# Seconds_Behind_Master. In particular, it ensures that the calculation for
+# Seconds_Behind_Master is based on the timestamp of the new transaction,
+# rather than the last committed transaction.
+#
+# References:
+# MDEV-29639: Seconds_Behind_Master is incorrect for Delayed, Parallel
+# Replicas
+#
+
+--source include/master-slave.inc
+
+--connection slave
+--source include/stop_slave.inc
+--let $master_delay= 3
+--eval change master to master_delay=$master_delay, master_use_gtid=Slave_Pos
+--let $old_slave_threads= `SELECT @@GLOBAL.slave_parallel_threads`
+set @@GLOBAL.slave_parallel_threads=2;
+--source include/start_slave.inc
+
+--connection master
+create table t1 (a int);
+--source include/sync_slave_sql_with_master.inc
+
+--echo #
+--echo # Pt 1) Ensure SBM is updated immediately upon arrival of the next event
+
+--echo # Lock t1 on slave so the first received transaction does not complete/commit
+--connection slave
+LOCK TABLES t1 WRITE;
+
+--connection master
+--echo # Sleep 2 to allow a buffer between events for SBM check
+sleep 2;
+
+--let $ts_trx_before_ins= `SELECT UNIX_TIMESTAMP()`
+--let insert_ctr= 0
+--eval insert into t1 values ($insert_ctr)
+--inc $insert_ctr
+--source include/save_master_gtid.inc
+
+--connection slave
+
+--echo # Waiting for transaction to arrive on slave and begin SQL Delay..
+--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting until MASTER_DELAY seconds after master executed event';
+--source include/wait_condition.inc
+
+--echo # Validating SBM is updated on event arrival..
+--let $sbm_trx1_arrive= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1)
+--let $seconds_since_idling= `SELECT UNIX_TIMESTAMP() - $ts_trx_before_ins`
+if (`SELECT $sbm_trx1_arrive > ($seconds_since_idling + 1)`)
+{
+ --echo # SBM was $sbm_trx1_arrive yet shouldn't have been larger than $seconds_since_idling + 1 (for possible negative clock_diff_with_master)
+ --die Seconds_Behind_Master should reset after idling
+}
+--echo # ..done
+
+--connection slave
+UNLOCK TABLES;
+--source include/sync_with_master_gtid.inc
+
+--echo #
+--echo # Pt 2) If the SQL thread has not entered an idle state, ensure
+--echo # following events do not update SBM
+
+--echo # Stop slave IO thread so it receives both events together on restart
+--connection slave
+--source include/stop_slave_io.inc
+
+--connection master
+
+--echo # Sleep 2 to allow a buffer between events for SBM check
+sleep 2;
+--let $ts_trxpt2_before_ins= `SELECT UNIX_TIMESTAMP()`
+--eval insert into t1 values ($insert_ctr)
+--inc $insert_ctr
+--echo # Sleep 3 to create gap between events
+sleep 3;
+--eval insert into t1 values ($insert_ctr)
+--inc $insert_ctr
+--let $ts_trx_after_ins= `SELECT UNIX_TIMESTAMP()`
+
+--connection slave
+LOCK TABLES t1 WRITE;
+
+START SLAVE IO_THREAD;
+
+--echo # Wait for first transaction to complete SQL delay and begin execution..
+--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock%' AND command LIKE 'Slave_Worker';
+--source include/wait_condition.inc
+
+--echo # Validate SBM calculation doesn't use the second transaction because SQL thread shouldn't have gone idle..
+--let $sbm_after_trx_no_idle= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1)
+--let $timestamp_trxpt2_arrive= `SELECT UNIX_TIMESTAMP()`
+if (`SELECT $sbm_after_trx_no_idle < $timestamp_trxpt2_arrive - $ts_trx_after_ins`)
+{
+ --let $cmpv= `SELECT $timestamp_trxpt2_arrive - $ts_trx_after_ins`
+ --echo # SBM $sbm_after_trx_no_idle was more recent than time since last transaction ($cmpv seconds)
+ --die Seconds_Behind_Master should not have used second transaction timestamp
+}
+--let $seconds_since_idling= `SELECT ($timestamp_trxpt2_arrive - $ts_trxpt2_before_ins)`
+--echo # ..and that SBM wasn't calculated using prior committed transactions
+if (`SELECT $sbm_after_trx_no_idle > ($seconds_since_idling + 1)`)
+{
+ --echo # SBM was $sbm_after_trx_no_idle yet shouldn't have been larger than $seconds_since_idling + 1 (for possible negative clock_diff_with_master)
+ --die Seconds_Behind_Master calculation should not have used prior committed transaction
+}
+--echo # ..done
+
+--connection slave
+UNLOCK TABLES;
+
+--echo #
+--echo # Cleanup
+
+--echo # Reset master_delay
+--source include/stop_slave.inc
+--eval CHANGE MASTER TO master_delay=0
+--eval set @@GLOBAL.slave_parallel_threads=$old_slave_threads
+--source include/start_slave.inc
+
+--connection master
+DROP TABLE t1;
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/sync_with_master_gtid.inc
+
+--source include/rpl_end.inc
+--echo # End of rpl_delayed_parallel_slave_sbm.test
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_analyze.test b/mysql-test/suite/rpl/t/rpl_parallel_analyze.test
new file mode 100644
index 00000000000..921c6f02904
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_analyze.test
@@ -0,0 +1,84 @@
+# The test file is created to prove fixes to
+# MDEV-30323 Some DDLs like ANALYZE can complete on parallel slave out of order
+# Debug-sync tests aiming at parallel replication of ADMIN commands
+# are welcome here.
+
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--echo # Initialize
+--connection slave
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+
+--echo # Setup data
+--connection master
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE ta (a int);
+--let $pre_load_gtid=`SELECT @@last_gtid`
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/sync_with_master_gtid.inc
+
+--source suite/rpl/include/create_or_drop_sync_func.inc
+
+# configure MDEV-30323 slave
+--source include/stop_slave.inc
+SET @old_parallel_threads =@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode =@@GLOBAL.slave_parallel_mode;
+SET @old_gtid_strict_mode =@@GLOBAL.gtid_strict_mode;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode=conservative;
+SET GLOBAL gtid_strict_mode=ON;
+--source include/start_slave.inc
+
+# MDEV-30323 setup needs two group of events the first of which is a DML
+# and ANALYZE is the 2nd.
+# The latter is made to race in slave execution over the DML thanks
+# to a DML latency simulation.
+# In the fixed case the race-over should not be a problem: ultimately
+# ANALYZE must wait for its turn to update slave@@global.gtid_binlog_pos.
+# Otherwise the reported OOO error must be issued.
+
+--connection master
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format=statement;
+INSERT INTO t1 VALUES (foo(1, 'rpl_parallel_after_mark_start_commit WAIT_FOR sig_go', ''));
+
+ANALYZE TABLE ta;
+--source include/save_master_gtid.inc
+
+--connection slave
+--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit"
+--source include/wait_condition.inc
+
+SELECT info FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit";
+if (`select strcmp(@@global.gtid_binlog_pos, '$pre_load_gtid') <> 0 or strcmp(@@global.gtid_slave_pos, '$pre_load_gtid') <> 0`)
+{
+ --let $bs=`SELECT @@global.gtid_binlog_pos`
+ --let $es=`SELECT @@global.gtid_slave_pos`
+ --echo Mismatch between expected $pre_load_gtid state and the actual binlog state " @@global.gtid_binlog_pos = $bs or/and slave execution state @@global.gtid_slave_pos = $es.
+ --die
+}
+
+set @@debug_sync="now signal sig_go";
+--source include/sync_with_master_gtid.inc
+
+--echo # Cleanup
+--connection master
+DROP TABLE t1,ta;
+--let $create_or_drop=drop
+--source suite/rpl/include/create_or_drop_sync_func.inc
+
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/sync_with_master_gtid.inc
+--source include/stop_slave.inc
+SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads;
+SET @@GLOBAL.slave_parallel_mode =@old_parallel_mode;
+SET @@GLOBAL.gtid_strict_mode =@old_gtid_strict_mode;
+--source include/start_slave.inc
+
+--source include/rpl_end.inc