26 Dec '19
revision-id: 359d91aaeec25825b51b0a00f52f272edad7d6cc (mariadb-10.1.39-254-g359d91aaeec)
parent(s): 9f7fcb9f25238945e4fb8cc1a1f98e56457b714f
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-12-26 17:36:32 +0530
message:
MDEV-19680:: Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index) || (!(ptr >= table->record[0] && ptr < table->record[0] + table->s->reclength)))' or alike failed upon SELECT with mix of functions from simple view
Set read_set bitmap for view from the JOIN::all_fields list instead of JOIN::fields_list
as split_sum_func would have added items to the all_fields list.
---
mysql-test/r/func_misc.result | 13 +++++++++++++
mysql-test/t/func_misc.test | 15 +++++++++++++++
sql/sql_lex.cc | 2 +-
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 287a70f1f73..89f6102ef83 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -1479,3 +1479,16 @@ EXECUTE stmt;
x
x
DEALLOCATE PREPARE stmt;
+#
+# MDEV-19680: Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index) ||
+# (!(ptr >= table->record[0] && ptr < table->record[0] + table->s->reclength)))'
+# or alike failed upon SELECT with mix of functions from simple view
+#
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1),(2);
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT ISNULL( BENCHMARK(1, MIN(a))) FROM v1;
+ISNULL( BENCHMARK(1, MIN(a)))
+0
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test
index a8da9068ab8..6412980a5fa 100644
--- a/mysql-test/t/func_misc.test
+++ b/mysql-test/t/func_misc.test
@@ -1154,3 +1154,18 @@ DROP PROCEDURE p1;
PREPARE stmt FROM "SELECT 'x' ORDER BY NAME_CONST( 'f', 'foo' )";
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
+
+--echo #
+--echo # MDEV-19680: Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index) ||
+--echo # (!(ptr >= table->record[0] && ptr < table->record[0] + table->s->reclength)))'
+--echo # or alike failed upon SELECT with mix of functions from simple view
+--echo #
+
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1),(2);
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+SELECT ISNULL( BENCHMARK(1, MIN(a))) FROM v1;
+
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index a36a19357eb..1cd2a369d7a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4177,7 +4177,7 @@ void SELECT_LEX::update_used_tables()
}
Item *item;
- List_iterator_fast<Item> it(join->fields_list);
+ List_iterator_fast<Item> it(join->all_fields);
while ((item= it++))
{
item->update_used_tables();
1
0
[Commits] 714762ddb7b: MDEV-18648: slave_parallel_mode= optimistic default in 10.5
by sujatha 23 Dec '19
by sujatha 23 Dec '19
23 Dec '19
revision-id: 714762ddb7ba0233ed584ed896e8f688fb085aeb (mariadb-10.5.0-79-g714762ddb7b)
parent(s): 7e10e80b8faab51139588a985a684df960ab81b9
author: Sujatha
committer: Sujatha
timestamp: 2019-12-23 17:48:01 +0530
message:
MDEV-18648: slave_parallel_mode= optimistic default in 10.5
Description:
============
To change 'CONSERVATIVE' @@global.slave_parallel_mode default to 'OPTIMISTIC'
in 10.5.
@sql/sys_vars.cc
Changed default parallel_mode to 'OPTIMISTIC'
@sql/rpl_filter.cc
Changed default parallel_mode to 'OPTIMISTIC'
@sql/mysqld.cc
Removed the initialization of 'SLAVE_PARALLEL_CONSERVATIVE' to
'opt_slave_parallel_mode' variable.
@mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test
@mysql-test/suite/rpl/t/rpl_mdev6386.test
Added 'mtr' suppression to ignore 'ER_PRIOR_COMMIT_FAILED'. In case of
'OPTIMISTIC' mode if a transaction gets killed during "wait_for_prior_commit"
it results in above error "1964". Hence suppression needs to be added for this
error.
@mysql-test/suite/rpl/t/rpl_parallel_conflicts.test
Test has a 'slave.opt' which explicitly sets slave_parallel_mode to
'conservative'. When the test ends this mode conflicts with new default mode.
Hence check test case reports an error. The 'slave.opt' is removed and options
are set and reset within test.
@mysql-test/suite/multi_source/info_logs.result
@mysql-test/suite/multi_source/reset_slave.result
@mysql-test/suite/multi_source/simple.result
Result content mismatch in "show slave status" output. This is expected as new
slave_parallel_mode='OPTIMISTIC'.
@mysql-test/include/check-testcase.test
Updated default 'slave_parallel_mode' to 'optimistic'.
Refactored rpl_parallel.test into following test cases.
Test case 1: @mysql-test/suite/rpl/t/rpl_parallel_domain.test
Test case 2: @mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test
Test case 3: @mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test
Test case 4: @mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test
Test case 5: @mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test
Test case 6: @mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test
Test case 7: @mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test
Test case 8: @mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test
Test case 9: @mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test
Test case 10: @mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test
Test case 11: @mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test
Test case 12: @mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test
Test case 13: @mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test
Test case 14: @mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test
Test case 15: @mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test
Test case 16: @mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test
Test case 17: @mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test
Test case 18: @mysql-test/suite/rpl/t/rpl_parallel_mode.test
Test case 19: @mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test
Test case 20: @mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test
Test case 21: @mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test
Test case 22: @mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test
---
mysql-test/include/check-testcase.test | 2 +-
.../suite/binlog_encryption/rpl_parallel.result | 1691 ---------------
.../suite/binlog_encryption/rpl_parallel.test | 1 -
.../rpl_parallel_analyze_table_hang.result | 51 +
.../rpl_parallel_analyze_table_hang.test | 1 +
.../rpl_parallel_deadlock_corrupt_binlog.result | 93 +
.../rpl_parallel_deadlock_corrupt_binlog.test | 1 +
.../binlog_encryption/rpl_parallel_domain.result | 71 +
.../binlog_encryption/rpl_parallel_domain.test | 1 +
.../rpl_parallel_domain_slave_single_grp.result | 101 +
.../rpl_parallel_domain_slave_single_grp.test | 1 +
.../rpl_parallel_free_deferred_event.result | 44 +
.../rpl_parallel_free_deferred_event.test | 1 +
.../rpl_parallel_gco_wait_kill.result | 257 +++
.../rpl_parallel_gco_wait_kill.test | 1 +
.../rpl_parallel_gtid_slave_pos_update_fail.result | 65 +
.../rpl_parallel_gtid_slave_pos_update_fail.test | 1 +
.../rpl_parallel_ignore_error_on_rotate.result | 74 +
.../rpl_parallel_ignore_error_on_rotate.test | 1 +
.../rpl_parallel_incorrect_relay_pos.result | 75 +
.../rpl_parallel_incorrect_relay_pos.test | 1 +
.../rpl_parallel_innodb_lock_conflict.result | 79 +
.../rpl_parallel_innodb_lock_conflict.test | 1 +
.../rpl_parallel_missed_error_handling.result | 65 +
.../rpl_parallel_missed_error_handling.test | 1 +
.../binlog_encryption/rpl_parallel_mode.result | 75 +
.../suite/binlog_encryption/rpl_parallel_mode.test | 1 +
.../rpl_parallel_partial_binlog_trans.result | 51 +
.../rpl_parallel_partial_binlog_trans.test | 1 +
.../rpl_parallel_record_gtid_wakeup.result | 48 +
.../rpl_parallel_record_gtid_wakeup.test | 1 +
.../rpl_parallel_retry_deadlock.result | 192 ++
.../rpl_parallel_retry_deadlock.test | 1 +
.../rpl_parallel_rollback_assert.result | 45 +
.../rpl_parallel_rollback_assert.test | 1 +
.../rpl_parallel_single_grpcmt.result | 161 ++
.../rpl_parallel_single_grpcmt.test | 1 +
.../rpl_parallel_slave_bgc_kill.result | 323 +++
.../rpl_parallel_slave_bgc_kill.test | 1 +
.../rpl_parallel_stop_on_con_kill.result | 102 +
.../rpl_parallel_stop_on_con_kill.test | 1 +
.../rpl_parallel_stop_slave.result | 85 +
.../binlog_encryption/rpl_parallel_stop_slave.test | 1 +
.../rpl_parallel_wrong_binlog_order.result | 75 +
.../rpl_parallel_wrong_binlog_order.test | 1 +
.../rpl_parallel_wrong_exec_master_pos.result | 34 +
.../rpl_parallel_wrong_exec_master_pos.test | 1 +
mysql-test/suite/multi_source/info_logs.result | 8 +-
mysql-test/suite/multi_source/reset_slave.result | 4 +-
mysql-test/suite/multi_source/simple.result | 14 +-
mysql-test/suite/rpl/include/rpl_parallel.inc | 2219 --------------------
.../include/rpl_parallel_analyze_table_hang.inc | 73 +
.../rpl_parallel_deadlock_corrupt_binlog.inc | 79 +
.../suite/rpl/include/rpl_parallel_domain.inc | 87 +
.../rpl_parallel_domain_slave_single_grp.inc | 128 ++
.../include/rpl_parallel_free_deferred_event.inc | 67 +
.../rpl/include/rpl_parallel_gco_wait_kill.inc | 366 ++++
.../rpl_parallel_gtid_slave_pos_update_fail.inc | 98 +
.../rpl_parallel_ignore_error_on_rotate.inc | 96 +
.../include/rpl_parallel_incorrect_relay_pos.inc | 128 ++
.../include/rpl_parallel_innodb_lock_conflict.inc | 107 +
.../include/rpl_parallel_missed_error_handling.inc | 87 +
mysql-test/suite/rpl/include/rpl_parallel_mode.inc | 87 +
.../include/rpl_parallel_partial_binlog_trans.inc | 71 +
.../include/rpl_parallel_record_gtid_wakeup.inc | 72 +
.../rpl/include/rpl_parallel_retry_deadlock.inc | 281 +++
.../rpl/include/rpl_parallel_rollback_assert.inc | 62 +
.../rpl/include/rpl_parallel_single_grpcmt.inc | 170 ++
.../rpl/include/rpl_parallel_slave_bgc_kill.inc | 454 ++++
.../rpl/include/rpl_parallel_stop_on_con_kill.inc | 129 ++
.../suite/rpl/include/rpl_parallel_stop_slave.inc | 114 +
.../include/rpl_parallel_wrong_binlog_order.inc | 91 +
.../include/rpl_parallel_wrong_exec_master_pos.inc | 56 +
mysql-test/suite/rpl/r/rpl_delayed_slave.result | 2 +-
mysql-test/suite/rpl/r/rpl_mdev6386.result | 1 +
mysql-test/suite/rpl/r/rpl_parallel.result | 1690 ---------------
.../rpl/r/rpl_parallel_analyze_table_hang.result | 51 +
.../suite/rpl/r/rpl_parallel_conflicts.result | 9 +
.../r/rpl_parallel_deadlock_corrupt_binlog.result | 93 +
mysql-test/suite/rpl/r/rpl_parallel_domain.result | 71 +
.../r/rpl_parallel_domain_slave_single_grp.result | 101 +
.../rpl/r/rpl_parallel_free_deferred_event.result | 44 +
.../suite/rpl/r/rpl_parallel_gco_wait_kill.result | 257 +++
.../rpl_parallel_gtid_slave_pos_update_fail.result | 65 +
.../r/rpl_parallel_ignore_error_on_rotate.result | 74 +
.../rpl/r/rpl_parallel_incorrect_relay_pos.result | 75 +
.../rpl/r/rpl_parallel_innodb_lock_conflict.result | 79 +
.../suite/rpl/r/rpl_parallel_mdev6589.result | 1 +
.../r/rpl_parallel_missed_error_handling.result | 65 +
mysql-test/suite/rpl/r/rpl_parallel_mode.result | 75 +
.../rpl/r/rpl_parallel_partial_binlog_trans.result | 51 +
.../rpl/r/rpl_parallel_record_gtid_wakeup.result | 48 +
.../suite/rpl/r/rpl_parallel_retry_deadlock.result | 192 ++
.../rpl/r/rpl_parallel_rollback_assert.result | 45 +
.../suite/rpl/r/rpl_parallel_single_grpcmt.result | 160 ++
.../suite/rpl/r/rpl_parallel_slave_bgc_kill.result | 323 +++
.../rpl/r/rpl_parallel_stop_on_con_kill.result | 102 +
.../suite/rpl/r/rpl_parallel_stop_slave.result | 85 +
.../rpl/r/rpl_parallel_wrong_binlog_order.result | 75 +
.../r/rpl_parallel_wrong_exec_master_pos.result | 34 +
.../suite/rpl/t/rpl_delayed_slave.combinations | 1 -
mysql-test/suite/rpl/t/rpl_mdev6386.test | 1 +
mysql-test/suite/rpl/t/rpl_parallel.test | 1 -
.../rpl/t/rpl_parallel_analyze_table_hang.test | 1 +
.../suite/rpl/t/rpl_parallel_conflicts-slave.opt | 1 -
mysql-test/suite/rpl/t/rpl_parallel_conflicts.test | 10 +-
.../t/rpl_parallel_deadlock_corrupt_binlog.test | 1 +
mysql-test/suite/rpl/t/rpl_parallel_domain.test | 1 +
.../t/rpl_parallel_domain_slave_single_grp.test | 1 +
.../rpl/t/rpl_parallel_free_deferred_event.test | 1 +
.../suite/rpl/t/rpl_parallel_gco_wait_kill.test | 1 +
.../t/rpl_parallel_gtid_slave_pos_update_fail.test | 1 +
.../rpl/t/rpl_parallel_ignore_error_on_rotate.test | 1 +
.../rpl/t/rpl_parallel_incorrect_relay_pos.test | 1 +
.../rpl/t/rpl_parallel_innodb_lock_conflict.test | 1 +
mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test | 1 +
.../rpl/t/rpl_parallel_missed_error_handling.test | 1 +
mysql-test/suite/rpl/t/rpl_parallel_mode.test | 1 +
.../rpl/t/rpl_parallel_partial_binlog_trans.test | 1 +
.../rpl/t/rpl_parallel_record_gtid_wakeup.test | 1 +
.../suite/rpl/t/rpl_parallel_retry_deadlock.test | 1 +
.../suite/rpl/t/rpl_parallel_rollback_assert.test | 1 +
.../suite/rpl/t/rpl_parallel_single_grpcmt.test | 1 +
.../suite/rpl/t/rpl_parallel_slave_bgc_kill.test | 1 +
.../suite/rpl/t/rpl_parallel_stop_on_con_kill.test | 1 +
.../suite/rpl/t/rpl_parallel_stop_slave.test | 1 +
.../rpl/t/rpl_parallel_wrong_binlog_order.test | 1 +
.../rpl/t/rpl_parallel_wrong_exec_master_pos.test | 1 +
sql/mysqld.cc | 2 +-
sql/rpl_filter.cc | 2 +-
sql/sys_vars.cc | 2 +-
131 files changed, 7318 insertions(+), 5623 deletions(-)
diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test
index 514c28b0e00..e984c4dc497 100644
--- a/mysql-test/include/check-testcase.test
+++ b/mysql-test/include/check-testcase.test
@@ -66,7 +66,7 @@ if ($tmp)
--echo Gtid_IO_Pos #
--echo Replicate_Do_Domain_Ids
--echo Replicate_Ignore_Domain_Ids
- --echo Parallel_Mode conservative
+ --echo Parallel_Mode optimistic
--echo SQL_Delay 0
--echo SQL_Remaining_Delay NULL
--echo Slave_SQL_Running_State
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel.result b/mysql-test/suite/binlog_encryption/rpl_parallel.result
deleted file mode 100644
index 5f78a378829..00000000000
--- a/mysql-test/suite/binlog_encryption/rpl_parallel.result
+++ /dev/null
@@ -1,1691 +0,0 @@
-include/master-slave.inc
-[connection master]
-connection server_2;
-SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
-SET GLOBAL slave_parallel_threads=10;
-ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=10;
-SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
-OK
-CHANGE MASTER TO master_use_gtid=slave_pos;
-include/start_slave.inc
-SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
-OK
-include/stop_slave.inc
-SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
-OK
-include/start_slave.inc
-SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
-OK
-*** Test long-running query in domain 1 can run in parallel with short queries in domain 0 ***
-connection server_1;
-ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
-CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
-CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (1);
-INSERT INTO t2 VALUES (1);
-connection server_2;
-connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
-LOCK TABLE t1 WRITE;
-connection server_1;
-SET gtid_domain_id=1;
-INSERT INTO t1 VALUES (2);
-SET gtid_domain_id=0;
-INSERT INTO t2 VALUES (2);
-INSERT INTO t2 VALUES (3);
-BEGIN;
-INSERT INTO t2 VALUES (4);
-INSERT INTO t2 VALUES (5);
-COMMIT;
-INSERT INTO t2 VALUES (6);
-connection server_2;
-SELECT * FROM t2 ORDER by a;
-a
-1
-2
-3
-4
-5
-6
-connection con_temp1;
-SELECT * FROM t1;
-a
-1
-UNLOCK TABLES;
-connection server_2;
-SELECT * FROM t1 ORDER BY a;
-a
-1
-2
-*** Test two transactions in different domains committed in opposite order on slave but in a single group commit. ***
-connection server_2;
-include/stop_slave.inc
-connection server_1;
-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;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format='statement';
-SET gtid_domain_id=1;
-INSERT INTO t2 VALUES (foo(10,
-'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'));
-connection server_2;
-FLUSH LOGS;
-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;
-SET @old_format=@@GLOBAL.binlog_format;
-SET GLOBAL binlog_format=statement;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-SET debug_sync='now WAIT_FOR ready1';
-connection server_1;
-SET gtid_domain_id=2;
-INSERT INTO t2 VALUES (foo(11,
-'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'));
-SET gtid_domain_id=0;
-SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
-a
-10
-11
-connection server_2;
-SET debug_sync='now WAIT_FOR ready3';
-SET debug_sync='now SIGNAL cont3';
-SET debug_sync='now WAIT_FOR ready4';
-SET debug_sync='now SIGNAL cont1';
-SET debug_sync='now WAIT_FOR ready2';
-SET debug_sync='now SIGNAL cont4';
-SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
-a
-10
-11
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002
-slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(11,
-'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'))
-slave-bin.000002 # Xid # # COMMIT /* XID */
-slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(10,
-'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'))
-slave-bin.000002 # Xid # # COMMIT /* XID */
-FLUSH LOGS;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET debug_sync='RESET';
-include/start_slave.inc
-*** Test that group-committed transactions on the master can replicate in parallel on the slave. ***
-connection server_1;
-SET debug_sync='RESET';
-FLUSH LOGS;
-CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
-INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7);
-connection server_2;
-connection con_temp1;
-BEGIN;
-INSERT INTO t3 VALUES (2,102);
-connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
-BEGIN;
-INSERT INTO t3 VALUES (4,104);
-connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (2, foo(12,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (4, foo(14,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (6, foo(16,
-'group_commit_waiting_for_prior SIGNAL slave_queued3',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-SET debug_sync='RESET';
-connection server_1;
-SELECT * FROM t3 ORDER BY a;
-a b
-1 1
-2 12
-3 3
-4 14
-5 5
-6 16
-7 7
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000002 # Binlog_checkpoint # # master-bin.000001
-master-bin.000002 # Binlog_checkpoint # # master-bin.000002
-master-bin.000002 # Gtid # # GTID #-#-#
-master-bin.000002 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
-master-bin.000002 # Gtid # # BEGIN GTID #-#-#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
-master-bin.000002 # Xid # # COMMIT /* XID */
-master-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
-''))
-master-bin.000002 # Xid # # COMMIT /* XID */
-master-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
-''))
-master-bin.000002 # Xid # # COMMIT /* XID */
-master-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
-'group_commit_waiting_for_prior SIGNAL slave_queued3',
-''))
-master-bin.000002 # Xid # # COMMIT /* XID */
-connection server_2;
-SET debug_sync='now WAIT_FOR slave_queued3';
-connection con_temp1;
-ROLLBACK;
-connection server_2;
-SET debug_sync='now WAIT_FOR slave_queued1';
-connection con_temp2;
-ROLLBACK;
-connection server_2;
-SET debug_sync='now WAIT_FOR slave_queued2';
-SET debug_sync='now SIGNAL slave_cont1';
-SELECT * FROM t3 ORDER BY a;
-a b
-1 1
-2 12
-3 3
-4 14
-5 5
-6 16
-7 7
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-slave-bin.000003 # Binlog_checkpoint # # slave-bin.000003
-slave-bin.000003 # Gtid # # GTID #-#-#
-slave-bin.000003 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
-slave-bin.000003 # Xid # # COMMIT /* XID */
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
-''))
-slave-bin.000003 # Xid # # COMMIT /* XID */
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
-''))
-slave-bin.000003 # Xid # # COMMIT /* XID */
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
-'group_commit_waiting_for_prior SIGNAL slave_queued3',
-''))
-slave-bin.000003 # Xid # # COMMIT /* XID */
-*** Test STOP SLAVE in parallel mode ***
-connection server_2;
-include/stop_slave.inc
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-connection server_1;
-SET binlog_direct_non_transactional_updates=0;
-SET sql_log_bin=0;
-CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction");
-SET sql_log_bin=1;
-BEGIN;
-INSERT INTO t2 VALUES (20);
-INSERT INTO t1 VALUES (20);
-INSERT INTO t2 VALUES (21);
-INSERT INTO t3 VALUES (20, 20);
-COMMIT;
-INSERT INTO t3 VALUES(21, 21);
-INSERT INTO t3 VALUES(22, 22);
-SET binlog_format=@old_format;
-connection con_temp1;
-BEGIN;
-INSERT INTO t2 VALUES (21);
-connection server_2;
-START SLAVE;
-connection con_temp2;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
-STOP SLAVE;
-connection con_temp1;
-SET debug_sync='now WAIT_FOR wait_for_done_waiting';
-ROLLBACK;
-connection con_temp2;
-SET GLOBAL debug_dbug=@old_dbug;
-SET debug_sync='RESET';
-connection server_2;
-include/wait_for_slave_to_stop.inc
-SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
-a
-20
-SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
-a
-20
-21
-SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
-a b
-20 20
-include/start_slave.inc
-SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
-a
-20
-SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
-a
-20
-21
-SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
-a b
-20 20
-21 21
-22 22
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** Test killing slave threads at various wait points ***
-*** 1. Test killing transaction waiting in commit for previous transaction to commit ***
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (31, foo(31,
-'commit_before_prepare_ordered WAIT_FOR t2_waiting',
-'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-INSERT INTO t3 VALUES (32, foo(32,
-'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
-''));
-INSERT INTO t3 VALUES (33, foo(33,
-'group_commit_waiting_for_prior SIGNAL t2_waiting',
-'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-COMMIT;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (34, foo(34,
-'',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-a b
-31 31
-32 32
-33 33
-34 34
-SET debug_sync='RESET';
-connection server_2;
-SET sql_log_bin=0;
-CALL mtr.add_suppression("Query execution was interrupted");
-CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
-CALL mtr.add_suppression("Slave: Connection was killed");
-SET sql_log_bin=1;
-SET debug_sync='now WAIT_FOR t2_query';
-SET debug_sync='now SIGNAL t2_cont';
-SET debug_sync='now WAIT_FOR t1_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t2_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-STOP SLAVE IO_THREAD;
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-a b
-31 31
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-INSERT INTO t3 VALUES (39,0);
-connection server_2;
-include/start_slave.inc
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-a b
-31 31
-32 32
-33 33
-34 34
-39 0
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** 2. Same as (1), but without restarting IO thread after kill of SQL threads ***
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (41, foo(41,
-'commit_before_prepare_ordered WAIT_FOR t2_waiting',
-'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-INSERT INTO t3 VALUES (42, foo(42,
-'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
-''));
-INSERT INTO t3 VALUES (43, foo(43,
-'group_commit_waiting_for_prior SIGNAL t2_waiting',
-'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-COMMIT;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (44, foo(44,
-'',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
-a b
-41 41
-42 42
-43 43
-44 44
-SET debug_sync='RESET';
-connection server_2;
-SET debug_sync='now WAIT_FOR t2_query';
-SET debug_sync='now SIGNAL t2_cont';
-SET debug_sync='now WAIT_FOR t1_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t2_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-INSERT INTO t3 VALUES (49,0);
-connection server_2;
-START SLAVE SQL_THREAD;
-SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
-a b
-41 41
-42 42
-43 43
-44 44
-49 0
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** 3. Same as (2), but not using gtid mode ***
-connection server_2;
-include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=no;
-include/start_slave.inc
-connection server_1;
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (51, foo(51,
-'commit_before_prepare_ordered WAIT_FOR t2_waiting',
-'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-INSERT INTO t3 VALUES (52, foo(52,
-'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
-''));
-INSERT INTO t3 VALUES (53, foo(53,
-'group_commit_waiting_for_prior SIGNAL t2_waiting',
-'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-COMMIT;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (54, foo(54,
-'',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-a b
-51 51
-52 52
-53 53
-54 54
-SET debug_sync='RESET';
-connection server_2;
-SET debug_sync='now WAIT_FOR t2_query';
-SET debug_sync='now SIGNAL t2_cont';
-SET debug_sync='now WAIT_FOR t1_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t2_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-a b
-51 51
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-INSERT INTO t3 VALUES (59,0);
-connection server_2;
-START SLAVE SQL_THREAD;
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-a b
-51 51
-52 52
-53 53
-54 54
-59 0
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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
-CHANGE MASTER TO master_use_gtid=slave_pos;
-include/start_slave.inc
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=4;
-include/start_slave.inc
-*** 4. Test killing thread that is waiting to start transaction until previous transaction commits ***
-connection server_1;
-SET binlog_format=statement;
-SET gtid_domain_id=2;
-BEGIN;
-INSERT INTO t3 VALUES (70, foo(70,
-'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', ''));
-INSERT INTO t3 VALUES (60, foo(60,
-'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2',
-'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-connection server_2;
-SET debug_sync='now WAIT_FOR d2_query';
-connection server_1;
-SET gtid_domain_id=1;
-BEGIN;
-INSERT INTO t3 VALUES (61, foo(61,
-'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting',
-'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed'));
-INSERT INTO t3 VALUES (62, foo(62,
-'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2',
-'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-connection server_2;
-SET debug_sync='now WAIT_FOR d1_query';
-connection server_1;
-SET gtid_domain_id=0;
-INSERT INTO t3 VALUES (63, foo(63,
-'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2',
-'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont'));
-connection server_2;
-SET debug_sync='now WAIT_FOR d0_query';
-connection server_1;
-SET gtid_domain_id=3;
-BEGIN;
-INSERT INTO t3 VALUES (68, foo(68,
-'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', ''));
-INSERT INTO t3 VALUES (69, foo(69,
-'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2',
-'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-connection server_2;
-SET debug_sync='now WAIT_FOR d3_query';
-SET debug_sync='now SIGNAL d2_cont2';
-SET debug_sync='now WAIT_FOR d2_done';
-SET debug_sync='now SIGNAL d1_cont2';
-SET debug_sync='now WAIT_FOR d1_done';
-SET debug_sync='now SIGNAL d0_cont2';
-SET debug_sync='now WAIT_FOR d0_done';
-SET debug_sync='now SIGNAL d3_cont2';
-SET debug_sync='now WAIT_FOR d3_done';
-connection con_temp3;
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (64, foo(64,
-'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', ''));
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2';
-INSERT INTO t3 VALUES (65, foo(65, '', ''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-INSERT INTO t3 VALUES (66, foo(66, '', ''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4';
-INSERT INTO t3 VALUES (67, foo(67, '', ''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued4';
-SET debug_sync='now SIGNAL master_cont2';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
-a b
-60 60
-61 61
-62 62
-63 63
-64 64
-65 65
-66 66
-67 67
-68 68
-69 69
-70 70
-SET debug_sync='RESET';
-connection server_2;
-SET debug_sync='now SIGNAL d0_cont';
-SET debug_sync='now WAIT_FOR t1_waiting';
-SET debug_sync='now SIGNAL d3_cont';
-SET debug_sync='now WAIT_FOR t2_waiting';
-SET debug_sync='now SIGNAL d1_cont';
-SET debug_sync='now WAIT_FOR t3_waiting';
-SET debug_sync='now SIGNAL d2_cont';
-SET debug_sync='now WAIT_FOR t4_waiting';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t3_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-STOP SLAVE IO_THREAD;
-SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a;
-a b
-60 60
-61 61
-62 62
-63 63
-64 64
-68 68
-69 69
-70 70
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-UPDATE t3 SET b=b+1 WHERE a=60;
-connection server_2;
-include/start_slave.inc
-SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
-a b
-60 61
-61 61
-62 62
-63 63
-64 64
-65 65
-66 66
-67 67
-68 68
-69 69
-70 70
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** 5. Test killing thread that is waiting for queue of max length to shorten ***
-SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued;
-SET GLOBAL slave_parallel_max_queued=9000;
-connection server_1;
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (80, foo(0,
-'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', ''));
-connection server_2;
-SET debug_sync='now WAIT_FOR query_waiting';
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max";
-connection server_1;
-SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
-a b
-80 0
-81 10000
-connection server_2;
-SET debug_sync='now WAIT_FOR wait_queue_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR wait_queue_killed';
-SET debug_sync='now SIGNAL query_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-STOP SLAVE IO_THREAD;
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_max_queued= @old_max_queued;
-connection server_1;
-INSERT INTO t3 VALUES (82,0);
-SET binlog_format=@old_format;
-connection server_2;
-SET debug_sync='RESET';
-include/start_slave.inc
-SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
-a b
-80 0
-81 10000
-82 0
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL replicate_ignore_table="test.t3";
-SET GLOBAL slave_parallel_threads=2;
-include/start_slave.inc
-connection server_1;
-INSERT INTO t3 VALUES (100, rand());
-INSERT INTO t3 VALUES (101, rand());
-connection server_2;
-connection server_1;
-INSERT INTO t3 VALUES (102, rand());
-INSERT INTO t3 VALUES (103, rand());
-INSERT INTO t3 VALUES (104, rand());
-INSERT INTO t3 VALUES (105, rand());
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL replicate_ignore_table="";
-include/start_slave.inc
-connection server_1;
-INSERT INTO t3 VALUES (106, rand());
-INSERT INTO t3 VALUES (107, rand());
-connection server_2;
-SELECT * FROM t3 WHERE a >= 100 ORDER BY a;
-a b
-106 #
-107 #
-*** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-connection server_1;
-INSERT INTO t3 VALUES (110, 1);
-connection server_2;
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-a b
-110 1
-SET sql_log_bin=0;
-INSERT INTO t3 VALUES (111, 666);
-SET sql_log_bin=1;
-connection server_1;
-connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-INSERT INTO t3 VALUES (111, 2);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-INSERT INTO t3 VALUES (112, 3);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET debug_sync='RESET';
-connection server_2;
-include/wait_for_slave_sql_error.inc [errno=1062]
-include/wait_for_slave_sql_to_stop.inc
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-a b
-110 1
-111 666
-SET sql_log_bin=0;
-DELETE FROM t3 WHERE a=111 AND b=666;
-SET sql_log_bin=1;
-START SLAVE SQL_THREAD;
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-a b
-110 1
-111 2
-112 3
-***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts ***
-connection server_2;
-include/stop_slave.inc
-connection server_1;
-CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-connection con1;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-UPDATE t4 SET b=NULL WHERE a=6;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 3;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET debug_sync='RESET';
-connection server_2;
-include/start_slave.inc
-include/stop_slave.inc
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 NULL
-connection server_1;
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-connection con1;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-INSERT INTO t4 VALUES (7, NULL);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 3;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET debug_sync='RESET';
-connection server_2;
-include/start_slave.inc
-include/stop_slave.inc
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 6
-7 NULL
-connection server_1;
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-connection con1;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-UPDATE t4 SET b=NULL WHERE a=6;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format='statement';
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 1;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET @old_format=@@GLOBAL.binlog_format;
-SET debug_sync='RESET';
-connection server_2;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
-include/start_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-2 2
-3 NULL
-4 4
-5 NULL
-6 NULL
-SET @last_gtid= 'GTID';
-SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
-CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
-AS result;
-result
-GTID found ok
-SELECT "ROW FOUND" AS `Is the row found?`
- FROM mysql.gtid_slave_pos
-WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
-Is the row found?
-ROW FOUND
-*** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=1;
-SET DEBUG_SYNC= 'RESET';
-include/start_slave.inc
-connection server_1;
-CREATE TABLE t5 (a INT PRIMARY KEY, b INT);
-INSERT INTO t5 VALUES (1,1);
-INSERT INTO t5 VALUES (2,2), (3,8);
-INSERT INTO t5 VALUES (4,16);
-connection server_2;
-test_check
-OK
-test_check
-OK
-connection server_1;
-FLUSH LOGS;
-connection server_2;
-test_check
-OK
-test_check
-OK
-*** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error ***
-connection server_1;
-CREATE TABLE t6 (a INT) ENGINE=MyISAM;
-CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1;
-connection con1;
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont';
-INSERT INTO t6 VALUES (1), (2), (3);
-connection server_1;
-SET debug_sync='now WAIT_FOR ready';
-KILL QUERY CONID;
-SET debug_sync='now SIGNAL cont';
-connection con1;
-ERROR 70100: Query execution was interrupted
-SET binlog_format= @old_format;
-SET debug_sync='RESET';
-connection server_1;
-SET debug_sync='RESET';
-connection server_2;
-include/wait_for_slave_sql_error.inc [errno=1317]
-STOP SLAVE IO_THREAD;
-SET GLOBAL gtid_slave_pos= 'AFTER_ERROR_GTID_POS';
-include/start_slave.inc
-connection server_1;
-INSERT INTO t6 VALUES (4);
-SELECT * FROM t6 ORDER BY a;
-a
-1
-4
-connection server_2;
-SELECT * FROM t6 ORDER BY a;
-a
-4
-*** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 ***
-connection server_1;
-INSERT INTO t2 VALUES (31);
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads= 0;
-include/start_slave.inc
-SET sql_log_bin= 0;
-INSERT INTO t2 VALUES (32);
-SET sql_log_bin= 1;
-connection server_1;
-INSERT INTO t2 VALUES (32);
-FLUSH LOGS;
-INSERT INTO t2 VALUES (33);
-INSERT INTO t2 VALUES (34);
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-a
-31
-32
-33
-34
-include/save_master_gtid.inc
-connection server_2;
-include/wait_for_slave_sql_error.inc [errno=1062]
-connection server_2;
-include/stop_slave_io.inc
-SET GLOBAL slave_parallel_threads=10;
-START SLAVE;
-include/wait_for_slave_sql_error.inc [errno=1062]
-START SLAVE SQL_THREAD;
-include/wait_for_slave_sql_error.inc [errno=1062]
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-a
-31
-32
-SET sql_slave_skip_counter= 1;
-ERROR HY000: When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position
-include/stop_slave_io.inc
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-a
-31
-32
-33
-34
-*** MDEV-6775: Wrong binlog order in parallel replication ***
-connection server_1;
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6);
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log";
-SET @old_format=@@GLOBAL.binlog_format;
-SET GLOBAL binlog_format=ROW;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-connection con1;
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-UPDATE t4 SET b=NULL WHERE a=6;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 3;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-SET binlog_format= @old_format;
-connection con2;
-SET binlog_format= @old_format;
-SET debug_sync='RESET';
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 NULL
-connection server_2;
-include/start_slave.inc
-SET debug_sync= 'now WAIT_FOR waiting';
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 NULL
-SET debug_sync= 'now SIGNAL cont';
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL binlog_format= @old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-7237: Parallel replication: incorrect relaylog position after stop/start the slave ***
-connection server_1;
-INSERT INTO t2 VALUES (40);
-connection server_2;
-include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=no;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_scheduled_gtid_0_x_100";
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-connection server_1;
-INSERT INTO t2 VALUES (41);
-INSERT INTO t2 VALUES (42);
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-DELETE FROM t2 WHERE a=40;
-SET binlog_format= @old_format;
-INSERT INTO t2 VALUES (43);
-INSERT INTO t2 VALUES (44);
-FLUSH LOGS;
-INSERT INTO t2 VALUES (45);
-SET gtid_seq_no=100;
-INSERT INTO t2 VALUES (46);
-connection con_temp2;
-BEGIN;
-SELECT * FROM t2 WHERE a=40 FOR UPDATE;
-a
-40
-connection server_2;
-include/start_slave.inc
-SET debug_sync= 'now WAIT_FOR scheduled_gtid_0_x_100';
-STOP SLAVE;
-connection con_temp2;
-SET debug_sync= 'now WAIT_FOR wait_for_done_waiting';
-ROLLBACK;
-connection server_2;
-include/wait_for_slave_sql_to_stop.inc
-SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
-a
-41
-42
-include/start_slave.inc
-SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
-a
-41
-42
-43
-44
-45
-46
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET DEBUG_SYNC= 'RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-CHANGE MASTER TO master_use_gtid=slave_pos;
-include/start_slave.inc
-*** MDEV-7326 Server deadlock in connection with parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=3;
-SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
-include/start_slave.inc
-connection server_1;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format= STATEMENT;
-INSERT INTO t1 VALUES (foo(50,
-"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
-"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
-connection server_1;
-INSERT INTO t2 VALUES (foo(50,
-"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
-"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
-connection server_1;
-INSERT INTO t1 VALUES (foo(51,
-"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
-"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
-SET DEBUG_SYNC= "now SIGNAL t1_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
-connection server_1;
-INSERT INTO t1 VALUES (52);
-SET BINLOG_FORMAT= @old_format;
-SELECT * FROM t2 WHERE a>=50 ORDER BY a;
-a
-50
-SELECT * FROM t1 WHERE a>=50 ORDER BY a;
-a
-50
-51
-52
-connection server_2;
-SET DEBUG_SYNC= "now SIGNAL prep_cont";
-SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
-SET DEBUG_SYNC= "now SIGNAL t2_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
-SET DEBUG_SYNC= "now SIGNAL t1_cont2";
-connection server_1;
-connection server_2;
-SELECT * FROM t2 WHERE a>=50 ORDER BY a;
-a
-50
-SELECT * FROM t1 WHERE a>=50 ORDER BY a;
-a
-50
-51
-52
-SET DEBUG_SYNC="reset";
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-7326 Server deadlock in connection with parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=3;
-SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
-include/start_slave.inc
-connection server_1;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format= STATEMENT;
-INSERT INTO t1 VALUES (foo(60,
-"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
-"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
-connection server_1;
-INSERT INTO t2 VALUES (foo(60,
-"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
-"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t1 VALUES (foo(61,
-"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
-"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-INSERT INTO t6 VALUES (62);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection server_1;
-SET debug_sync='RESET';
-SET BINLOG_FORMAT= @old_format;
-SELECT * FROM t2 WHERE a>=60 ORDER BY a;
-a
-60
-SELECT * FROM t1 WHERE a>=60 ORDER BY a;
-a
-60
-61
-SELECT * FROM t6 WHERE a>=60 ORDER BY a;
-a
-62
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
-SET DEBUG_SYNC= "now SIGNAL t1_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
-connection server_2;
-SET DEBUG_SYNC= "now SIGNAL prep_cont";
-SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
-SET DEBUG_SYNC= "now SIGNAL t2_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
-SET DEBUG_SYNC= "now SIGNAL t1_cont2";
-connection server_1;
-connection server_2;
-SELECT * FROM t2 WHERE a>=60 ORDER BY a;
-a
-60
-SELECT * FROM t1 WHERE a>=60 ORDER BY a;
-a
-60
-61
-SELECT * FROM t6 WHERE a>=60 ORDER BY a;
-a
-62
-SET DEBUG_SYNC="reset";
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=1;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
-connection server_1;
-INSERT INTO t2 VALUES (101);
-INSERT INTO t2 VALUES (102);
-INSERT INTO t2 VALUES (103);
-INSERT INTO t2 VALUES (104);
-INSERT INTO t2 VALUES (105);
-SET gtid_seq_no=1000;
-INSERT INTO t2 VALUES (106);
-INSERT INTO t2 VALUES (107);
-INSERT INTO t2 VALUES (108);
-INSERT INTO t2 VALUES (109);
-INSERT INTO t2 VALUES (110);
-INSERT INTO t2 VALUES (111);
-INSERT INTO t2 VALUES (112);
-INSERT INTO t2 VALUES (113);
-INSERT INTO t2 VALUES (114);
-INSERT INTO t2 VALUES (115);
-INSERT INTO t2 VALUES (116);
-INSERT INTO t2 VALUES (117);
-INSERT INTO t2 VALUES (118);
-INSERT INTO t2 VALUES (119);
-INSERT INTO t2 VALUES (120);
-INSERT INTO t2 VALUES (121);
-INSERT INTO t2 VALUES (122);
-INSERT INTO t2 VALUES (123);
-INSERT INTO t2 VALUES (124);
-INSERT INTO t2 VALUES (125);
-INSERT INTO t2 VALUES (126);
-INSERT INTO t2 VALUES (127);
-INSERT INTO t2 VALUES (128);
-INSERT INTO t2 VALUES (129);
-INSERT INTO t2 VALUES (130);
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
-a
-101
-102
-103
-104
-105
-107
-108
-109
-110
-111
-112
-113
-114
-115
-116
-117
-118
-119
-120
-121
-122
-123
-124
-125
-126
-127
-128
-129
-130
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-6676 - test syntax of @@slave_parallel_mode ***
-connection server_2;
-Parallel_Mode = 'conservative'
-include/stop_slave.inc
-SET GLOBAL slave_parallel_mode='aggressive';
-Parallel_Mode = 'aggressive'
-SET GLOBAL slave_parallel_mode='conservative';
-Parallel_Mode = 'conservative'
-*** MDEV-6676 - test that empty parallel_mode does not replicate in parallel ***
-connection server_1;
-INSERT INTO t2 VALUES (1040);
-include/save_master_gtid.inc
-connection server_2;
-SET GLOBAL slave_parallel_mode='none';
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply";
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
-a
-1040
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-*** MDEV-6676 - test disabling domain-based parallel replication ***
-connection server_1;
-SET gtid_domain_id = 1;
-INSERT INTO t2 VALUES (1041);
-INSERT INTO t2 VALUES (1042);
-INSERT INTO t2 VALUES (1043);
-INSERT INTO t2 VALUES (1044);
-INSERT INTO t2 VALUES (1045);
-INSERT INTO t2 VALUES (1046);
-DELETE FROM t2 WHERE a >= 1041;
-SET gtid_domain_id = 2;
-INSERT INTO t2 VALUES (1041);
-INSERT INTO t2 VALUES (1042);
-INSERT INTO t2 VALUES (1043);
-INSERT INTO t2 VALUES (1044);
-INSERT INTO t2 VALUES (1045);
-INSERT INTO t2 VALUES (1046);
-SET gtid_domain_id = 0;
-include/save_master_gtid.inc
-connection server_2;
-SET GLOBAL slave_parallel_mode=minimal;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
-a
-1040
-1041
-1042
-1043
-1044
-1045
-1046
-*** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_mode='conservative';
-SET GLOBAL slave_parallel_threads=10;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep';
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @commit_id= 10000;
-ANALYZE TABLE t2;
-Table Op Msg_type Msg_text
-test.t2 analyze status Engine-independent statistics collected
-test.t2 analyze status OK
-INSERT INTO t3 VALUES (120, 0);
-SET @commit_id= 10001;
-INSERT INTO t3 VALUES (121, 0);
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
-a b
-120 0
-121 0
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
-a b
-120 0
-121 0
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
-include/start_slave.inc
-*** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. ***
-connection server_2;
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep';
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @old_server_id= @@SESSION.server_id;
-SET SESSION server_id= 100;
-SET @commit_id= 10010;
-ALTER TABLE t1 COMMENT "Hulubulu!";
-SET SESSION server_id= @old_server_id;
-INSERT INTO t3 VALUES (130, 0);
-SET @commit_id= 10011;
-INSERT INTO t3 VALUES (131, 0);
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
-a b
-130 0
-131 0
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
-a b
-130 0
-131 0
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
-include/start_slave.inc
-*** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) ***
-connection server_1;
-INSERT INTO t3 VALUES (201,0), (202,0);
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_mdev8031';
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @commit_id= 10200;
-INSERT INTO t3 VALUES (203, 1);
-INSERT INTO t3 VALUES (204, 1);
-INSERT INTO t3 VALUES (205, 1);
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=205;
-UPDATE t3 SET b=b+1 WHERE a=205;
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 3
-202 4
-203 4
-204 4
-205 3
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 3
-202 4
-203 4
-204 4
-205 3
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
-include/start_slave.inc
-*** Check getting deadlock killed inside open_binlog() during retry. ***
-connection server_2;
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill';
-SET @old_max= @@GLOBAL.max_relay_log_size;
-SET GLOBAL max_relay_log_size= 4096;
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @commit_id= 10210;
-Omit long queries that cause relaylog rotations and transaction retries...
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 6
-202 8
-203 7
-204 7
-205 5
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 6
-202 8
-203 7
-204 7
-205 5
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_debg;
-SET GLOBAL max_relay_log_size= @old_max;
-include/start_slave.inc
-*** MDEV-8725: Assertion on ROLLBACK statement in the binary log ***
-connection server_1;
-BEGIN;
-INSERT INTO t2 VALUES (2000);
-INSERT INTO t1 VALUES (2000);
-INSERT INTO t2 VALUES (2001);
-ROLLBACK;
-SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
-a
-2000
-SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
-a
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
-a
-2000
-SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
-a
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=@old_parallel_threads;
-include/start_slave.inc
-SET DEBUG_SYNC= 'RESET';
-connection server_1;
-DROP function foo;
-DROP TABLE t1,t2,t3,t4,t5,t6;
-SET DEBUG_SYNC= 'RESET';
-include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel.test b/mysql-test/suite/binlog_encryption/rpl_parallel.test
deleted file mode 100644
index dba54e4fd7a..00000000000
--- a/mysql-test/suite/binlog_encryption/rpl_parallel.test
+++ /dev/null
@@ -1 +0,0 @@
---source suite/rpl/include/rpl_parallel.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_analyze_table_hang.result b/mysql-test/suite/binlog_encryption/rpl_parallel_analyze_table_hang.result
new file mode 100644
index 00000000000..3c3cd2601e8
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_analyze_table_hang.result
@@ -0,0 +1,51 @@
+*** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep';
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @commit_id= 10000;
+ANALYZE TABLE t2;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+INSERT INTO t3 VALUES (120, 0);
+SET @commit_id= 10001;
+INSERT INTO t3 VALUES (121, 0);
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
+a b
+120 0
+121 0
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
+a b
+120 0
+121 0
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+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 t2,t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_analyze_table_hang.test b/mysql-test/suite/binlog_encryption/rpl_parallel_analyze_table_hang.test
new file mode 100644
index 00000000000..69e76692ce1
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_analyze_table_hang.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_analyze_table_hang.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_deadlock_corrupt_binlog.result b/mysql-test/suite/binlog_encryption/rpl_parallel_deadlock_corrupt_binlog.result
new file mode 100644
index 00000000000..74d1d53b67c
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_deadlock_corrupt_binlog.result
@@ -0,0 +1,93 @@
+*** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=1;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
+connection server_1;
+INSERT INTO t2 VALUES (101);
+INSERT INTO t2 VALUES (102);
+INSERT INTO t2 VALUES (103);
+INSERT INTO t2 VALUES (104);
+INSERT INTO t2 VALUES (105);
+SET gtid_seq_no=1000;
+INSERT INTO t2 VALUES (106);
+INSERT INTO t2 VALUES (107);
+INSERT INTO t2 VALUES (108);
+INSERT INTO t2 VALUES (109);
+INSERT INTO t2 VALUES (110);
+INSERT INTO t2 VALUES (111);
+INSERT INTO t2 VALUES (112);
+INSERT INTO t2 VALUES (113);
+INSERT INTO t2 VALUES (114);
+INSERT INTO t2 VALUES (115);
+INSERT INTO t2 VALUES (116);
+INSERT INTO t2 VALUES (117);
+INSERT INTO t2 VALUES (118);
+INSERT INTO t2 VALUES (119);
+INSERT INTO t2 VALUES (120);
+INSERT INTO t2 VALUES (121);
+INSERT INTO t2 VALUES (122);
+INSERT INTO t2 VALUES (123);
+INSERT INTO t2 VALUES (124);
+INSERT INTO t2 VALUES (125);
+INSERT INTO t2 VALUES (126);
+INSERT INTO t2 VALUES (127);
+INSERT INTO t2 VALUES (128);
+INSERT INTO t2 VALUES (129);
+INSERT INTO t2 VALUES (130);
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
+a
+101
+102
+103
+104
+105
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t2;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_deadlock_corrupt_binlog.test b/mysql-test/suite/binlog_encryption/rpl_parallel_deadlock_corrupt_binlog.test
new file mode 100644
index 00000000000..71c589dcd88
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_deadlock_corrupt_binlog.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_deadlock_corrupt_binlog.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_domain.result b/mysql-test/suite/binlog_encryption/rpl_parallel_domain.result
new file mode 100644
index 00000000000..69b9678d149
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_domain.result
@@ -0,0 +1,71 @@
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
+OK
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
+OK
+include/stop_slave.inc
+SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
+OK
+include/start_slave.inc
+SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
+OK
+*** Test long-running query in domain 1 can run in parallel with short queries in domain 0 ***
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1);
+connection server_2;
+connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+LOCK TABLE t1 WRITE;
+connection server_1;
+SET gtid_domain_id=1;
+INSERT INTO t1 VALUES (2);
+SET gtid_domain_id=0;
+INSERT INTO t2 VALUES (2);
+INSERT INTO t2 VALUES (3);
+BEGIN;
+INSERT INTO t2 VALUES (4);
+INSERT INTO t2 VALUES (5);
+COMMIT;
+INSERT INTO t2 VALUES (6);
+connection server_2;
+SELECT * FROM t2 ORDER by a;
+a
+1
+2
+3
+4
+5
+6
+connection con_temp1;
+SELECT * FROM t1;
+a
+1
+UNLOCK TABLES;
+connection server_2;
+SELECT * FROM t1 ORDER BY a;
+a
+1
+2
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1,t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_domain.test b/mysql-test/suite/binlog_encryption/rpl_parallel_domain.test
new file mode 100644
index 00000000000..b498b8616c8
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_domain.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_domain.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_domain_slave_single_grp.result b/mysql-test/suite/binlog_encryption/rpl_parallel_domain_slave_single_grp.result
new file mode 100644
index 00000000000..613aac64487
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_domain_slave_single_grp.result
@@ -0,0 +1,101 @@
+*** Test two transactions in different domains committed in opposite order on slave but in a single group commit. ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1);
+connection server_2;
+include/stop_slave.inc
+connection server_1;
+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;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format='statement';
+SET gtid_domain_id=1;
+INSERT INTO t2 VALUES (foo(10,
+'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'));
+connection server_2;
+FLUSH LOGS;
+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;
+SET @old_format=@@GLOBAL.binlog_format;
+SET GLOBAL binlog_format=statement;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+SET debug_sync='now WAIT_FOR ready1';
+connection server_1;
+SET gtid_domain_id=2;
+INSERT INTO t2 VALUES (foo(11,
+'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'));
+SET gtid_domain_id=0;
+SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
+a
+10
+11
+connection server_2;
+SET debug_sync='now WAIT_FOR ready3';
+SET debug_sync='now SIGNAL cont3';
+SET debug_sync='now WAIT_FOR ready4';
+SET debug_sync='now SIGNAL cont1';
+SET debug_sync='now WAIT_FOR ready2';
+SET debug_sync='now SIGNAL cont4';
+SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
+a
+10
+11
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002
+slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(11,
+'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'))
+slave-bin.000002 # Xid # # COMMIT /* XID */
+slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(10,
+'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'))
+slave-bin.000002 # Xid # # COMMIT /* XID */
+FLUSH LOGS;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL binlog_format=@old_format;
+connection server_1;
+DROP function foo;
+DROP TABLE t1,t2;
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL binlog_format=@old_format;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_domain_slave_single_grp.test b/mysql-test/suite/binlog_encryption/rpl_parallel_domain_slave_single_grp.test
new file mode 100644
index 00000000000..ce9239f189e
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_domain_slave_single_grp.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_domain_slave_single_grp.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_free_deferred_event.result b/mysql-test/suite/binlog_encryption/rpl_parallel_free_deferred_event.result
new file mode 100644
index 00000000000..6718561a321
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_free_deferred_event.result
@@ -0,0 +1,44 @@
+*** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL replicate_ignore_table="test.t3";
+SET GLOBAL slave_parallel_threads=2;
+include/start_slave.inc
+connection server_1;
+INSERT INTO t3 VALUES (100, rand());
+INSERT INTO t3 VALUES (101, rand());
+connection server_2;
+connection server_1;
+INSERT INTO t3 VALUES (102, rand());
+INSERT INTO t3 VALUES (103, rand());
+INSERT INTO t3 VALUES (104, rand());
+INSERT INTO t3 VALUES (105, rand());
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL replicate_ignore_table="";
+include/start_slave.inc
+connection server_1;
+INSERT INTO t3 VALUES (106, rand());
+INSERT INTO t3 VALUES (107, rand());
+connection server_2;
+SELECT * FROM t3 WHERE a >= 100 ORDER BY a;
+a b
+106 #
+107 #
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_free_deferred_event.test b/mysql-test/suite/binlog_encryption/rpl_parallel_free_deferred_event.test
new file mode 100644
index 00000000000..d0b6c970210
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_free_deferred_event.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_free_deferred_event.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_gco_wait_kill.result b/mysql-test/suite/binlog_encryption/rpl_parallel_gco_wait_kill.result
new file mode 100644
index 00000000000..4472550c4f2
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_gco_wait_kill.result
@@ -0,0 +1,257 @@
+*** Test killing thread that is waiting to start transaction until previous transaction commits ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Query execution was interrupted");
+CALL mtr.add_suppression("Slave: Connection was killed");
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET sql_log_bin=1;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode= 'conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+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 server_2;
+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 GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=4;
+include/start_slave.inc
+connection server_1;
+SET gtid_domain_id=2;
+BEGIN;
+INSERT INTO t3 VALUES (70, foo(70,
+'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', ''));
+INSERT INTO t3 VALUES (60, foo(60,
+'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2',
+'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+connection server_2;
+SET debug_sync='now WAIT_FOR d2_query';
+connection server_1;
+SET gtid_domain_id=1;
+BEGIN;
+INSERT INTO t3 VALUES (61, foo(61,
+'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting',
+'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed'));
+INSERT INTO t3 VALUES (62, foo(62,
+'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2',
+'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+connection server_2;
+SET debug_sync='now WAIT_FOR d1_query';
+connection server_1;
+SET gtid_domain_id=0;
+INSERT INTO t3 VALUES (63, foo(63,
+'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2',
+'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont'));
+connection server_2;
+SET debug_sync='now WAIT_FOR d0_query';
+connection server_1;
+SET gtid_domain_id=3;
+BEGIN;
+INSERT INTO t3 VALUES (68, foo(68,
+'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', ''));
+INSERT INTO t3 VALUES (69, foo(69,
+'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2',
+'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+connection server_2;
+SET debug_sync='now WAIT_FOR d3_query';
+SET debug_sync='now SIGNAL d2_cont2';
+SET debug_sync='now WAIT_FOR d2_done';
+SET debug_sync='now SIGNAL d1_cont2';
+SET debug_sync='now WAIT_FOR d1_done';
+SET debug_sync='now SIGNAL d0_cont2';
+SET debug_sync='now WAIT_FOR d0_done';
+SET debug_sync='now SIGNAL d3_cont2';
+SET debug_sync='now WAIT_FOR d3_done';
+connection con_temp3;
+INSERT INTO t3 VALUES (64, foo(64,
+'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', ''));
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2';
+INSERT INTO t3 VALUES (65, foo(65, '', ''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (66, foo(66, '', ''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4';
+INSERT INTO t3 VALUES (67, foo(67, '', ''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued4';
+SET debug_sync='now SIGNAL master_cont2';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
+a b
+60 60
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+70 70
+SET debug_sync='RESET';
+connection server_2;
+SET debug_sync='now SIGNAL d0_cont';
+SET debug_sync='now WAIT_FOR t1_waiting';
+SET debug_sync='now SIGNAL d3_cont';
+SET debug_sync='now WAIT_FOR t2_waiting';
+SET debug_sync='now SIGNAL d1_cont';
+SET debug_sync='now WAIT_FOR t3_waiting';
+SET debug_sync='now SIGNAL d2_cont';
+SET debug_sync='now WAIT_FOR t4_waiting';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t3_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+STOP SLAVE IO_THREAD;
+SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a;
+a b
+60 60
+61 61
+62 62
+63 63
+64 64
+68 68
+69 69
+70 70
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+UPDATE t3 SET b=b+1 WHERE a=60;
+connection server_2;
+include/start_slave.inc
+SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
+a b
+60 61
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+70 70
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** 5. Test killing thread that is waiting for queue of max length to shorten ***
+SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued;
+SET GLOBAL slave_parallel_max_queued=9000;
+connection server_1;
+INSERT INTO t3 VALUES (80, foo(0,
+'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', ''));
+connection server_2;
+SET debug_sync='now WAIT_FOR query_waiting';
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max";
+connection server_1;
+SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
+a b
+80 0
+81 10000
+connection server_2;
+SET debug_sync='now WAIT_FOR wait_queue_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR wait_queue_killed';
+SET debug_sync='now SIGNAL query_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+STOP SLAVE IO_THREAD;
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_max_queued= @old_max_queued;
+connection server_1;
+INSERT INTO t3 VALUES (82,0);
+connection server_2;
+SET debug_sync='RESET';
+include/start_slave.inc
+SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
+a b
+80 0
+81 10000
+82 0
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP function foo;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_gco_wait_kill.test b/mysql-test/suite/binlog_encryption/rpl_parallel_gco_wait_kill.test
new file mode 100644
index 00000000000..853465f1760
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_gco_wait_kill.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_gco_wait_kill.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_gtid_slave_pos_update_fail.result b/mysql-test/suite/binlog_encryption/rpl_parallel_gtid_slave_pos_update_fail.result
new file mode 100644
index 00000000000..2e7e7f547af
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_gtid_slave_pos_update_fail.result
@@ -0,0 +1,65 @@
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection server_2;
+include/stop_slave.inc
+connection con1;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+UPDATE t4 SET b=NULL WHERE a=6;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 1;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
+include/start_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+2 2
+3 NULL
+4 4
+5 NULL
+6 NULL
+SET @last_gtid= 'GTID';
+SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
+CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
+AS result;
+result
+GTID found ok
+SELECT "ROW FOUND" AS `Is the row found?`
+ FROM mysql.gtid_slave_pos
+WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
+Is the row found?
+ROW FOUND
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+disconnect con2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_gtid_slave_pos_update_fail.test b/mysql-test/suite/binlog_encryption/rpl_parallel_gtid_slave_pos_update_fail.test
new file mode 100644
index 00000000000..67105ccafee
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_gtid_slave_pos_update_fail.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_gtid_slave_pos_update_fail.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_ignore_error_on_rotate.result b/mysql-test/suite/binlog_encryption/rpl_parallel_ignore_error_on_rotate.result
new file mode 100644
index 00000000000..d00740dba3d
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_ignore_error_on_rotate.result
@@ -0,0 +1,74 @@
+*** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+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=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+SET gtid_domain_id=1;
+INSERT INTO t2 VALUES (1);
+SET gtid_domain_id=0;
+SET gtid_domain_id=2;
+INSERT INTO t2 VALUES (2);
+SET gtid_domain_id=0;
+INSERT INTO t2 VALUES (31);
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads= 0;
+include/start_slave.inc
+SET sql_log_bin= 0;
+INSERT INTO t2 VALUES (32);
+SET sql_log_bin= 1;
+connection server_1;
+INSERT INTO t2 VALUES (32);
+FLUSH LOGS;
+INSERT INTO t2 VALUES (33);
+INSERT INTO t2 VALUES (34);
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+a
+31
+32
+33
+34
+include/save_master_gtid.inc
+connection server_2;
+include/wait_for_slave_sql_error.inc [errno=1062]
+connection server_2;
+include/stop_slave_io.inc
+SET GLOBAL slave_parallel_threads=10;
+START SLAVE;
+include/wait_for_slave_sql_error.inc [errno=1062]
+START SLAVE SQL_THREAD;
+include/wait_for_slave_sql_error.inc [errno=1062]
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+a
+31
+32
+SET sql_slave_skip_counter= 1;
+ERROR HY000: When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position
+include/stop_slave_io.inc
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+a
+31
+32
+33
+34
+connection server_2;
+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 t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_ignore_error_on_rotate.test b/mysql-test/suite/binlog_encryption/rpl_parallel_ignore_error_on_rotate.test
new file mode 100644
index 00000000000..ce57184d812
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_ignore_error_on_rotate.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_ignore_error_on_rotate.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_incorrect_relay_pos.result b/mysql-test/suite/binlog_encryption/rpl_parallel_incorrect_relay_pos.result
new file mode 100644
index 00000000000..6ca7f2b68e8
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_incorrect_relay_pos.result
@@ -0,0 +1,75 @@
+*** MDEV-7237: Parallel replication: incorrect relaylog position after stop/start the slave ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (40);
+connection server_2;
+connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=no;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_scheduled_gtid_0_x_100";
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+connection server_1;
+INSERT INTO t2 VALUES (41);
+INSERT INTO t2 VALUES (42);
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+DELETE FROM t2 WHERE a=40;
+SET binlog_format= @old_format;
+INSERT INTO t2 VALUES (43);
+INSERT INTO t2 VALUES (44);
+FLUSH LOGS;
+INSERT INTO t2 VALUES (45);
+SET gtid_seq_no=100;
+INSERT INTO t2 VALUES (46);
+connection con_temp2;
+BEGIN;
+SELECT * FROM t2 WHERE a=40 FOR UPDATE;
+a
+40
+connection server_2;
+include/start_slave.inc
+SET debug_sync= 'now WAIT_FOR scheduled_gtid_0_x_100';
+STOP SLAVE;
+connection con_temp2;
+SET debug_sync= 'now WAIT_FOR wait_for_done_waiting';
+ROLLBACK;
+connection server_2;
+include/wait_for_slave_sql_to_stop.inc
+SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
+a
+41
+42
+include/start_slave.inc
+SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
+a
+41
+42
+43
+44
+45
+46
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_incorrect_relay_pos.test b/mysql-test/suite/binlog_encryption/rpl_parallel_incorrect_relay_pos.test
new file mode 100644
index 00000000000..ddec96e8792
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_incorrect_relay_pos.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_incorrect_relay_pos.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_innodb_lock_conflict.result b/mysql-test/suite/binlog_encryption/rpl_parallel_innodb_lock_conflict.result
new file mode 100644
index 00000000000..1411db16af6
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_innodb_lock_conflict.result
@@ -0,0 +1,79 @@
+***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET sql_log_bin=1;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection con1;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+UPDATE t4 SET b=NULL WHERE a=6;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 3;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+include/start_slave.inc
+include/stop_slave.inc
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 NULL
+connection server_1;
+DELETE FROM t4;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+connection con1;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t4 VALUES (7, NULL);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 3;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+include/start_slave.inc
+include/stop_slave.inc
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 6
+7 NULL
+connection server_2;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+disconnect con1;
+disconnect con2;
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_innodb_lock_conflict.test b/mysql-test/suite/binlog_encryption/rpl_parallel_innodb_lock_conflict.test
new file mode 100644
index 00000000000..624667d5408
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_innodb_lock_conflict.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_innodb_lock_conflict.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_missed_error_handling.result b/mysql-test/suite/binlog_encryption/rpl_parallel_missed_error_handling.result
new file mode 100644
index 00000000000..e9d04c02d7a
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_missed_error_handling.result
@@ -0,0 +1,65 @@
+*** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+INSERT INTO t3 VALUES (110, 1);
+connection server_2;
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+a b
+110 1
+SET sql_log_bin=0;
+INSERT INTO t3 VALUES (111, 666);
+SET sql_log_bin=1;
+connection server_1;
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (111, 2);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+INSERT INTO t3 VALUES (112, 3);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+include/wait_for_slave_sql_error.inc [errno=1062]
+include/wait_for_slave_sql_to_stop.inc
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+a b
+110 1
+111 666
+SET sql_log_bin=0;
+DELETE FROM t3 WHERE a=111 AND b=666;
+SET sql_log_bin=1;
+START SLAVE SQL_THREAD;
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+a b
+110 1
+111 2
+112 3
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+disconnect con1;
+disconnect con2;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_missed_error_handling.test b/mysql-test/suite/binlog_encryption/rpl_parallel_missed_error_handling.test
new file mode 100644
index 00000000000..c6d09f2196b
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_missed_error_handling.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_missed_error_handling.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_mode.result b/mysql-test/suite/binlog_encryption/rpl_parallel_mode.result
new file mode 100644
index 00000000000..313290b1fd2
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_mode.result
@@ -0,0 +1,75 @@
+*** MDEV-6676 - test syntax of @@slave_parallel_mode ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+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=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+connection server_2;
+Parallel_Mode = 'optimistic'
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='aggressive';
+Parallel_Mode = 'aggressive'
+SET GLOBAL slave_parallel_mode='conservative';
+Parallel_Mode = 'conservative'
+*** MDEV-6676 - test that empty parallel_mode does not replicate in parallel ***
+connection server_1;
+INSERT INTO t2 VALUES (1040);
+include/save_master_gtid.inc
+connection server_2;
+SET GLOBAL slave_parallel_mode='none';
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply";
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
+a
+1040
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+*** MDEV-6676 - test disabling domain-based parallel replication ***
+connection server_1;
+SET gtid_domain_id = 1;
+INSERT INTO t2 VALUES (1041);
+INSERT INTO t2 VALUES (1042);
+INSERT INTO t2 VALUES (1043);
+INSERT INTO t2 VALUES (1044);
+INSERT INTO t2 VALUES (1045);
+INSERT INTO t2 VALUES (1046);
+DELETE FROM t2 WHERE a >= 1041;
+SET gtid_domain_id = 2;
+INSERT INTO t2 VALUES (1041);
+INSERT INTO t2 VALUES (1042);
+INSERT INTO t2 VALUES (1043);
+INSERT INTO t2 VALUES (1044);
+INSERT INTO t2 VALUES (1045);
+INSERT INTO t2 VALUES (1046);
+SET gtid_domain_id = 0;
+include/save_master_gtid.inc
+connection server_2;
+SET GLOBAL slave_parallel_mode=minimal;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
+a
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+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 t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_mode.test b/mysql-test/suite/binlog_encryption/rpl_parallel_mode.test
new file mode 100644
index 00000000000..93170f61c95
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_mode.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_mode.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_partial_binlog_trans.result b/mysql-test/suite/binlog_encryption/rpl_parallel_partial_binlog_trans.result
new file mode 100644
index 00000000000..ab1cac692a0
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_partial_binlog_trans.result
@@ -0,0 +1,51 @@
+*** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t6 (a INT) ENGINE=MyISAM;
+CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1;
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection con1;
+SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont';
+INSERT INTO t6 VALUES (1), (2), (3);
+connection server_1;
+SET debug_sync='now WAIT_FOR ready';
+KILL QUERY CONID;
+SET debug_sync='now SIGNAL cont';
+connection con1;
+ERROR 70100: Query execution was interrupted
+SET debug_sync='RESET';
+connection server_1;
+SET debug_sync='RESET';
+connection server_2;
+include/wait_for_slave_sql_error.inc [errno=1317]
+STOP SLAVE IO_THREAD;
+SET GLOBAL gtid_slave_pos= 'AFTER_ERROR_GTID_POS';
+include/start_slave.inc
+connection server_1;
+INSERT INTO t6 VALUES (4);
+SELECT * FROM t6 ORDER BY a;
+a
+1
+4
+connection server_2;
+SELECT * FROM t6 ORDER BY a;
+a
+4
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t6;
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_partial_binlog_trans.test b/mysql-test/suite/binlog_encryption/rpl_parallel_partial_binlog_trans.test
new file mode 100644
index 00000000000..4f90cf4808e
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_partial_binlog_trans.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_partial_binlog_trans.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_record_gtid_wakeup.result b/mysql-test/suite/binlog_encryption/rpl_parallel_record_gtid_wakeup.result
new file mode 100644
index 00000000000..cbe53e4f623
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_record_gtid_wakeup.result
@@ -0,0 +1,48 @@
+*** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep';
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @old_server_id= @@SESSION.server_id;
+SET SESSION server_id= 100;
+SET @commit_id= 10010;
+ALTER TABLE t1 COMMENT "Hulubulu!";
+SET SESSION server_id= @old_server_id;
+INSERT INTO t3 VALUES (130, 0);
+SET @commit_id= 10011;
+INSERT INTO t3 VALUES (131, 0);
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
+a b
+130 0
+131 0
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
+a b
+130 0
+131 0
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1,t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_record_gtid_wakeup.test b/mysql-test/suite/binlog_encryption/rpl_parallel_record_gtid_wakeup.test
new file mode 100644
index 00000000000..cb3b0dfa119
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_record_gtid_wakeup.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_record_gtid_wakeup.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_retry_deadlock.result b/mysql-test/suite/binlog_encryption/rpl_parallel_retry_deadlock.result
new file mode 100644
index 00000000000..1f5a23db848
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_retry_deadlock.result
@@ -0,0 +1,192 @@
+*** MDEV-7326 Server deadlock in connection with parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t6 (a INT) ENGINE=MyISAM;
+connection server_2;
+connection server_1;
+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 server_2;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=3;
+SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
+include/start_slave.inc
+connection server_1;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+INSERT INTO t1 VALUES (foo(50,
+"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
+"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
+connection server_1;
+INSERT INTO t2 VALUES (foo(50,
+"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
+"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
+connection server_1;
+INSERT INTO t1 VALUES (foo(51,
+"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
+"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
+SET DEBUG_SYNC= "now SIGNAL t1_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
+connection server_1;
+INSERT INTO t1 VALUES (52);
+SET BINLOG_FORMAT= @old_format;
+SELECT * FROM t2 WHERE a>=50 ORDER BY a;
+a
+50
+SELECT * FROM t1 WHERE a>=50 ORDER BY a;
+a
+50
+51
+52
+connection server_2;
+SET DEBUG_SYNC= "now SIGNAL prep_cont";
+SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
+SET DEBUG_SYNC= "now SIGNAL t2_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
+SET DEBUG_SYNC= "now SIGNAL t1_cont2";
+connection server_1;
+connection server_2;
+SELECT * FROM t2 WHERE a>=50 ORDER BY a;
+a
+50
+SELECT * FROM t1 WHERE a>=50 ORDER BY a;
+a
+50
+51
+52
+SET DEBUG_SYNC="reset";
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** MDEV-7326 Server deadlock in connection with parallel replication ***
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=3;
+SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
+include/start_slave.inc
+connection server_1;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+INSERT INTO t1 VALUES (foo(60,
+"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
+"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
+connection server_1;
+INSERT INTO t2 VALUES (foo(60,
+"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
+"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+SET binlog_format=statement;
+INSERT INTO t1 VALUES (foo(61,
+"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
+"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+INSERT INTO t6 VALUES (62);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection server_1;
+SET debug_sync='RESET';
+SET BINLOG_FORMAT= @old_format;
+SELECT * FROM t2 WHERE a>=60 ORDER BY a;
+a
+60
+SELECT * FROM t1 WHERE a>=60 ORDER BY a;
+a
+60
+61
+SELECT * FROM t6 WHERE a>=60 ORDER BY a;
+a
+62
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
+SET DEBUG_SYNC= "now SIGNAL t1_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
+connection server_2;
+SET DEBUG_SYNC= "now SIGNAL prep_cont";
+SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
+SET DEBUG_SYNC= "now SIGNAL t2_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
+SET DEBUG_SYNC= "now SIGNAL t1_cont2";
+connection server_1;
+connection server_2;
+SELECT * FROM t2 WHERE a>=60 ORDER BY a;
+a
+60
+SELECT * FROM t1 WHERE a>=60 ORDER BY a;
+a
+60
+61
+SELECT * FROM t6 WHERE a>=60 ORDER BY a;
+a
+62
+SET DEBUG_SYNC="reset";
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP function foo;
+DROP TABLE t1,t2,t6;
+disconnect con_temp3;
+disconnect con_temp4;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_retry_deadlock.test b/mysql-test/suite/binlog_encryption/rpl_parallel_retry_deadlock.test
new file mode 100644
index 00000000000..61c2cb22a75
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_retry_deadlock.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_retry_deadlock.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_rollback_assert.result b/mysql-test/suite/binlog_encryption/rpl_parallel_rollback_assert.result
new file mode 100644
index 00000000000..af9c5f14687
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_rollback_assert.result
@@ -0,0 +1,45 @@
+*** MDEV-8725: Assertion on ROLLBACK statement in the binary log ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+BEGIN;
+INSERT INTO t2 VALUES (2000);
+INSERT INTO t1 VALUES (2000);
+INSERT INTO t2 VALUES (2001);
+ROLLBACK;
+SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
+a
+2000
+SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
+a
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+connection server_1;
+INSERT INTO t2 VALUES (2020);
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
+a
+2020
+SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
+a
+2000
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1,t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_rollback_assert.test b/mysql-test/suite/binlog_encryption/rpl_parallel_rollback_assert.test
new file mode 100644
index 00000000000..181305219be
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_rollback_assert.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_rollback_assert.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_single_grpcmt.result b/mysql-test/suite/binlog_encryption/rpl_parallel_single_grpcmt.result
new file mode 100644
index 00000000000..25fc9a189ac
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_single_grpcmt.result
@@ -0,0 +1,161 @@
+*** Test that group-committed transactions on the master can replicate in parallel on the slave. ***
+include/master-slave.inc
+[connection master]
+connection server_1;
+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 server_2;
+include/stop_slave.inc
+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;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7);
+connection server_2;
+connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+BEGIN;
+INSERT INTO t3 VALUES (2,102);
+connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+BEGIN;
+INSERT INTO t3 VALUES (4,104);
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+SET binlog_format=statement;
+INSERT INTO t3 VALUES (2, foo(12,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+SET binlog_format=statement;
+INSERT INTO t3 VALUES (4, foo(14,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+SET binlog_format=statement;
+INSERT INTO t3 VALUES (6, foo(16,
+'group_commit_waiting_for_prior SIGNAL slave_queued3',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+SET debug_sync='RESET';
+connection server_1;
+SELECT * FROM t3 ORDER BY a;
+a b
+1 1
+2 12
+3 3
+4 14
+5 5
+6 16
+7 7
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint # # master-bin.000001
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+''))
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+''))
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
+'group_commit_waiting_for_prior SIGNAL slave_queued3',
+''))
+master-bin.000001 # Xid # # COMMIT /* XID */
+connection server_2;
+SET debug_sync='now WAIT_FOR slave_queued3';
+connection con_temp1;
+ROLLBACK;
+connection server_2;
+SET debug_sync='now WAIT_FOR slave_queued1';
+connection con_temp2;
+ROLLBACK;
+connection server_2;
+SET debug_sync='now WAIT_FOR slave_queued2';
+SET debug_sync='now SIGNAL slave_cont1';
+SELECT * FROM t3 ORDER BY a;
+a b
+1 1
+2 12
+3 3
+4 14
+5 5
+6 16
+7 7
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000001 # Gtid # # GTID #-#-#
+slave-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
+slave-bin.000001 # Gtid # # GTID #-#-#
+slave-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
+slave-bin.000001 # Xid # # COMMIT /* XID */
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+''))
+slave-bin.000001 # Xid # # COMMIT /* XID */
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+''))
+slave-bin.000001 # Xid # # COMMIT /* XID */
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
+'group_commit_waiting_for_prior SIGNAL slave_queued3',
+''))
+slave-bin.000001 # Xid # # COMMIT /* XID */
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP function foo;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_single_grpcmt.test b/mysql-test/suite/binlog_encryption/rpl_parallel_single_grpcmt.test
new file mode 100644
index 00000000000..6a13735c29c
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_single_grpcmt.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_single_grpcmt.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_slave_bgc_kill.result b/mysql-test/suite/binlog_encryption/rpl_parallel_slave_bgc_kill.result
new file mode 100644
index 00000000000..320bf0e49f8
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_slave_bgc_kill.result
@@ -0,0 +1,323 @@
+*** Test killing slave threads at various wait points ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+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 server_2;
+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;
+*** 1. Test killing transaction waiting in commit for previous transaction to commit ***
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (31, foo(31,
+'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+INSERT INTO t3 VALUES (32, foo(32,
+'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+''));
+INSERT INTO t3 VALUES (33, foo(33,
+'group_commit_waiting_for_prior SIGNAL t2_waiting',
+'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+COMMIT;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (34, foo(34,
+'',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+a b
+31 31
+32 32
+33 33
+34 34
+SET debug_sync='RESET';
+connection server_2;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Query execution was interrupted");
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+CALL mtr.add_suppression("Slave: Connection was killed");
+SET sql_log_bin=1;
+SET debug_sync='now WAIT_FOR t2_query';
+SET debug_sync='now SIGNAL t2_cont';
+SET debug_sync='now WAIT_FOR t1_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t2_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+STOP SLAVE IO_THREAD;
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+a b
+31 31
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+INSERT INTO t3 VALUES (39,0);
+connection server_2;
+include/start_slave.inc
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+a b
+31 31
+32 32
+33 33
+34 34
+39 0
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** 2. Same as (1), but without restarting IO thread after kill of SQL threads ***
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (41, foo(41,
+'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+INSERT INTO t3 VALUES (42, foo(42,
+'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+''));
+INSERT INTO t3 VALUES (43, foo(43,
+'group_commit_waiting_for_prior SIGNAL t2_waiting',
+'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+COMMIT;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (44, foo(44,
+'',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
+a b
+41 41
+42 42
+43 43
+44 44
+SET debug_sync='RESET';
+connection server_2;
+SET debug_sync='now WAIT_FOR t2_query';
+SET debug_sync='now SIGNAL t2_cont';
+SET debug_sync='now WAIT_FOR t1_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t2_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+INSERT INTO t3 VALUES (49,0);
+connection server_2;
+START SLAVE SQL_THREAD;
+SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
+a b
+41 41
+42 42
+43 43
+44 44
+49 0
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** 3. Same as (2), but not using gtid mode ***
+connection server_2;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=no;
+include/start_slave.inc
+connection server_1;
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (51, foo(51,
+'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+INSERT INTO t3 VALUES (52, foo(52,
+'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+''));
+INSERT INTO t3 VALUES (53, foo(53,
+'group_commit_waiting_for_prior SIGNAL t2_waiting',
+'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+COMMIT;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (54, foo(54,
+'',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+a b
+51 51
+52 52
+53 53
+54 54
+SET debug_sync='RESET';
+connection server_2;
+SET debug_sync='now WAIT_FOR t2_query';
+SET debug_sync='now SIGNAL t2_cont';
+SET debug_sync='now WAIT_FOR t1_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t2_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+a b
+51 51
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+INSERT INTO t3 VALUES (59,0);
+connection server_2;
+START SLAVE SQL_THREAD;
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+a b
+51 51
+52 52
+53 53
+54 54
+59 0
+connection server_2;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP function foo;
+DROP TABLE t1,t2,t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_slave_bgc_kill.test b/mysql-test/suite/binlog_encryption/rpl_parallel_slave_bgc_kill.test
new file mode 100644
index 00000000000..72597f32685
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_slave_bgc_kill.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_slave_bgc_kill.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_stop_on_con_kill.result b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_on_con_kill.result
new file mode 100644
index 00000000000..bf0ed9e4374
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_on_con_kill.result
@@ -0,0 +1,102 @@
+*** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (201,0), (202,0);
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_mdev8031';
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @commit_id= 10200;
+INSERT INTO t3 VALUES (203, 1);
+INSERT INTO t3 VALUES (204, 1);
+INSERT INTO t3 VALUES (205, 1);
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=205;
+UPDATE t3 SET b=b+1 WHERE a=205;
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 3
+202 4
+203 4
+204 4
+205 3
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 3
+202 4
+203 4
+204 4
+205 3
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+include/start_slave.inc
+*** Check getting deadlock killed inside open_binlog() during retry. ***
+connection server_2;
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill';
+SET @old_max= @@GLOBAL.max_relay_log_size;
+SET GLOBAL max_relay_log_size= 4096;
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @commit_id= 10210;
+Omit long queries that cause relaylog rotations and transaction retries...
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 6
+202 8
+203 7
+204 7
+205 5
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 6
+202 8
+203 7
+204 7
+205 5
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_debg;
+SET GLOBAL max_relay_log_size= @old_max;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_stop_on_con_kill.test b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_on_con_kill.test
new file mode 100644
index 00000000000..adec2dc631c
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_on_con_kill.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_stop_on_con_kill.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_stop_slave.result b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_slave.result
new file mode 100644
index 00000000000..6c9fd168e73
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_slave.result
@@ -0,0 +1,85 @@
+*** Test STOP SLAVE in parallel mode ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+connection server_1;
+SET binlog_direct_non_transactional_updates=0;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction");
+SET sql_log_bin=1;
+BEGIN;
+INSERT INTO t2 VALUES (20);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t2 VALUES (21);
+INSERT INTO t3 VALUES (20, 20);
+COMMIT;
+INSERT INTO t3 VALUES(21, 21);
+INSERT INTO t3 VALUES(22, 22);
+connection con_temp1;
+BEGIN;
+INSERT INTO t2 VALUES (21);
+connection server_2;
+START SLAVE;
+connection con_temp2;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
+STOP SLAVE;
+connection con_temp1;
+SET debug_sync='now WAIT_FOR wait_for_done_waiting';
+ROLLBACK;
+connection con_temp2;
+SET GLOBAL debug_dbug=@old_dbug;
+SET debug_sync='RESET';
+connection server_2;
+include/wait_for_slave_to_stop.inc
+SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
+a
+20
+SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
+a
+20
+21
+SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
+a b
+20 20
+include/start_slave.inc
+SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
+a
+20
+SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
+a
+20
+21
+SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
+a b
+20 20
+21 21
+22 22
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+disconnect con_temp1;
+disconnect con_temp2;
+connection server_1;
+DROP TABLE t1,t2,t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_stop_slave.test b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_slave.test
new file mode 100644
index 00000000000..c59b2805569
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_stop_slave.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_stop_slave.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_binlog_order.result b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_binlog_order.result
new file mode 100644
index 00000000000..f6781f64d30
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_binlog_order.result
@@ -0,0 +1,75 @@
+*** MDEV-6775: Wrong binlog order in parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6);
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log";
+SET @old_format=@@GLOBAL.binlog_format;
+SET GLOBAL binlog_format=ROW;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+connection con1;
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+UPDATE t4 SET b=NULL WHERE a=6;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 3;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+SET binlog_format= @old_format;
+connection con2;
+SET binlog_format= @old_format;
+SET debug_sync='RESET';
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 NULL
+connection server_2;
+include/start_slave.inc
+SET debug_sync= 'now WAIT_FOR waiting';
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 NULL
+SET debug_sync= 'now SIGNAL cont';
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL binlog_format= @old_format;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+disconnect con2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_binlog_order.test b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_binlog_order.test
new file mode 100644
index 00000000000..4141dfce6d6
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_binlog_order.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_wrong_binlog_order.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_exec_master_pos.result b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_exec_master_pos.result
new file mode 100644
index 00000000000..47cfa5e08e2
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_exec_master_pos.result
@@ -0,0 +1,34 @@
+*** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t5 (a INT PRIMARY KEY, b INT);
+INSERT INTO t5 VALUES (1,1);
+INSERT INTO t5 VALUES (2,2), (3,8);
+INSERT INTO t5 VALUES (4,16);
+connection server_2;
+test_check
+OK
+test_check
+OK
+connection server_1;
+FLUSH LOGS;
+connection server_2;
+test_check
+OK
+test_check
+OK
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t5;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_exec_master_pos.test b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_exec_master_pos.test
new file mode 100644
index 00000000000..34268eb6622
--- /dev/null
+++ b/mysql-test/suite/binlog_encryption/rpl_parallel_wrong_exec_master_pos.test
@@ -0,0 +1 @@
+--source suite/rpl/include/rpl_parallel_wrong_exec_master_pos.inc
diff --git a/mysql-test/suite/multi_source/info_logs.result b/mysql-test/suite/multi_source/info_logs.result
index 531a6178cdb..f8519a99964 100644
--- a/mysql-test/suite/multi_source/info_logs.result
+++ b/mysql-test/suite/multi_source/info_logs.result
@@ -90,16 +90,16 @@ MASTER 2.2
#
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_tra
nsaction
s Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
- Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
-MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
+ Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
+MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
include/wait_for_slave_to_start.inc
set default_master_connection = 'MASTER 2.2';
include/wait_for_slave_to_start.inc
set default_master_connection = '';
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_tra
nsaction
s Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
- Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 6 0 60.000
-MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 6 0 60.000
+ Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 6 0 60.000
+MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 6 0 60.000
#
# List of files matching '*info*' pattern
# after slave server restart
diff --git a/mysql-test/suite/multi_source/reset_slave.result b/mysql-test/suite/multi_source/reset_slave.result
index c1d74ab9f3f..c048784e28d 100644
--- a/mysql-test/suite/multi_source/reset_slave.result
+++ b/mysql-test/suite/multi_source/reset_slave.result
@@ -14,14 +14,14 @@ connection slave;
stop slave 'master1';
show slave 'master1' status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups
- 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-master1.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space> None 0 No NULL No 0 0 1 No conservative 0 NULL 2 1 0
+ 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-master1.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space> None 0 No NULL No 0 0 1 No optimistic 0 NULL 2 1 0
mysqld-relay-bin-master1.000001
mysqld-relay-bin-master1.000002
mysqld-relay-bin-master1.index
reset slave 'master1';
show slave 'master1' status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups
- 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space> None 0 No NULL No 0 0 1 No conservative 0 NULL 2 1 0
+ 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space> None 0 No NULL No 0 0 1 No optimistic 0 NULL 2 1 0
reset slave 'master1' all;
show slave 'master1' status;
ERROR HY000: There is no master connection 'master1'
diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result
index 93ea1c023bc..922c7555875 100644
--- a/mysql-test/suite/multi_source/simple.result
+++ b/mysql-test/suite/multi_source/simple.result
@@ -19,8 +19,8 @@ connection master2;
connection slave;
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_tra
nsaction
s Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
-slave1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave1.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
-slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
+slave1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave1.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
+slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
start all slaves;
stop slave 'slave1';
show slave 'slave1' status;
@@ -70,7 +70,7 @@ Using_Gtid No
Gtid_IO_Pos
Replicate_Do_Domain_Ids
Replicate_Ignore_Domain_Ids
-Parallel_Mode conservative
+Parallel_Mode optimistic
SQL_Delay 0
SQL_Remaining_Delay NULL
Slave_SQL_Running_State
@@ -80,18 +80,18 @@ Slave_Transactional_Groups 0
reset slave 'slave1';
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_tra
nsaction
s Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
-slave1 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space1> None 0 No NULL No 0 0 1 No conservative 0 NULL 0 0 0 0 1073741824 7 0 60.000
-slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
+slave1 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space1> None 0 No NULL No 0 0 1 No optimistic 0 NULL 0 0 0 0 1073741824 7 0 60.000
+slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
reset slave 'slave1' all;
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_tra
nsaction
s Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
-slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
+slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 0 0 0 1073741824 7 0 60.000
stop all slaves;
Warnings:
Note 1938 SLAVE 'slave2' stopped
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_tra
nsaction
s Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
-slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space1> None 0 No NULL No 0 0 2 No conservative 0 NULL 0 0 0 0 1073741824 7 0 60.000
+slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space1> None 0 No NULL No 0 0 2 No optimistic 0 NULL 0 0 0 0 1073741824 7 0 60.000
stop all slaves;
include/reset_master_slave.inc
disconnect slave;
diff --git a/mysql-test/suite/rpl/include/rpl_parallel.inc b/mysql-test/suite/rpl/include/rpl_parallel.inc
deleted file mode 100644
index 42354343084..00000000000
--- a/mysql-test/suite/rpl/include/rpl_parallel.inc
+++ /dev/null
@@ -1,2219 +0,0 @@
-#
-# This include file is used by more than one test suite
-# (currently rpl and binlog_encryption).
-# Please check all dependent tests after modifying it
-#
-
---source include/have_innodb.inc
---source include/have_debug.inc
---source include/have_debug_sync.inc
---source include/master-slave.inc
-
-# Test various aspects of parallel replication.
-
---connection server_2
-SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
---error ER_SLAVE_MUST_STOP
-SET GLOBAL slave_parallel_threads=10;
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=10;
-
-# Check that we do not spawn any worker threads when no slave is running.
-SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-
-CHANGE MASTER TO master_use_gtid=slave_pos;
---source include/start_slave.inc
-
-# Check that worker threads get spawned when slave starts.
-SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-# ... and that worker threads get removed when slave stops.
---source include/stop_slave.inc
-SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
---source include/start_slave.inc
-SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-
---echo *** Test long-running query in domain 1 can run in parallel with short queries in domain 0 ***
-
---connection server_1
-ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
-CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
-CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (1);
-INSERT INTO t2 VALUES (1);
---save_master_pos
-
---connection server_2
---sync_with_master
-
-# Block the table t1 to simulate a replicated query taking a long time.
---connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
-LOCK TABLE t1 WRITE;
-
---connection server_1
-SET gtid_domain_id=1;
-# This query will be blocked on the slave until UNLOCK TABLES.
-INSERT INTO t1 VALUES (2);
-SET gtid_domain_id=0;
-# These t2 queries can be replicated in parallel with the prior t1 query, as
-# they are in a separate replication domain.
-INSERT INTO t2 VALUES (2);
-INSERT INTO t2 VALUES (3);
-BEGIN;
-INSERT INTO t2 VALUES (4);
-INSERT INTO t2 VALUES (5);
-COMMIT;
-INSERT INTO t2 VALUES (6);
-
---connection server_2
---let $wait_condition= SELECT COUNT(*) = 6 FROM t2
---source include/wait_condition.inc
-
-SELECT * FROM t2 ORDER by a;
-
---connection con_temp1
-SELECT * FROM t1;
-UNLOCK TABLES;
-
---connection server_2
---let $wait_condition= SELECT COUNT(*) = 2 FROM t1
---source include/wait_condition.inc
-
-SELECT * FROM t1 ORDER BY a;
-
-
---echo *** Test two transactions in different domains committed in opposite order on slave but in a single group commit. ***
---connection server_2
---source include/stop_slave.inc
-
---connection server_1
-# 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;
-
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format='statement';
-SET gtid_domain_id=1;
-INSERT INTO t2 VALUES (foo(10,
- 'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
- 'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'));
-
---connection server_2
-FLUSH LOGS;
---source include/wait_for_binlog_checkpoint.inc
-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;
-SET @old_format=@@GLOBAL.binlog_format;
-SET GLOBAL binlog_format=statement;
-# We need to restart all parallel threads for the new global setting to
-# be copied to the session-level values.
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-# First make sure the first insert is ready to commit, but not queued yet.
-SET debug_sync='now WAIT_FOR ready1';
-
---connection server_1
-SET gtid_domain_id=2;
-INSERT INTO t2 VALUES (foo(11,
- 'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
- 'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'));
-SET gtid_domain_id=0;
-SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
-
---connection server_2
-# Now wait for the second insert to queue itself as the leader, and then
-# wait for more commits to queue up.
-SET debug_sync='now WAIT_FOR ready3';
-SET debug_sync='now SIGNAL cont3';
-SET debug_sync='now WAIT_FOR ready4';
-# Now allow the first insert to queue up to participate in group commit.
-SET debug_sync='now SIGNAL cont1';
-SET debug_sync='now WAIT_FOR ready2';
-# Finally allow the second insert to proceed and do the group commit.
-SET debug_sync='now SIGNAL cont4';
-
---let $wait_condition= SELECT COUNT(*) = 2 FROM t2 WHERE a >= 10
---source include/wait_condition.inc
-SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
-# The two INSERT transactions should have been committed in opposite order,
-# but in the same group commit (seen by precense of cid=# in the SHOW
-# BINLOG output).
---let $binlog_file= slave-bin.000002
---source include/show_binlog_events.inc
-FLUSH LOGS;
---source include/wait_for_binlog_checkpoint.inc
-
-# Restart all the slave parallel worker threads, to clear all debug_sync actions.
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET debug_sync='RESET';
---source include/start_slave.inc
-
-
---echo *** Test that group-committed transactions on the master can replicate in parallel on the slave. ***
---connection server_1
-SET debug_sync='RESET';
-FLUSH LOGS;
---source include/wait_for_binlog_checkpoint.inc
-CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
-# Create some sentinel rows so that the rows inserted in parallel fall into
-# separate gaps and do not cause gap lock conflicts.
-INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7);
---save_master_pos
---connection server_2
---sync_with_master
-
-# We want to test that the transactions can execute out-of-order on
-# the slave, but still end up committing in-order, and in a single
-# group commit.
-#
-# The idea is to group-commit three transactions together on the master:
-# A, B, and C. On the slave, C will execute the insert first, then A,
-# and then B. But B manages to complete before A has time to commit, so
-# all three end up committing together.
-#
-# So we start by setting up some row locks that will block transactions
-# A and B from executing, allowing C to run first.
-
---connection con_temp1
-BEGIN;
-INSERT INTO t3 VALUES (2,102);
---connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
-BEGIN;
-INSERT INTO t3 VALUES (4,104);
-
-# On the master, queue three INSERT transactions as a single group commit.
---connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (2, foo(12,
- 'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
- ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (4, foo(14,
- 'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
- ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-
---connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (6, foo(16,
- 'group_commit_waiting_for_prior SIGNAL slave_queued3',
- ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con_temp3
-REAP;
---connection con_temp4
-REAP;
---connection con_temp5
-REAP;
-SET debug_sync='RESET';
-
---connection server_1
-SELECT * FROM t3 ORDER BY a;
---let $binlog_file= master-bin.000002
---source include/show_binlog_events.inc
-
-# First, wait until insert 3 is ready to queue up for group commit, but is
-# waiting for insert 2 to commit before it can do so itself.
---connection server_2
-SET debug_sync='now WAIT_FOR slave_queued3';
-
-# Next, let insert 1 proceed, and allow it to queue up as the group commit
-# leader, but let it wait for insert 2 to also queue up before proceeding.
---connection con_temp1
-ROLLBACK;
---connection server_2
-SET debug_sync='now WAIT_FOR slave_queued1';
-
-# Now let insert 2 proceed and queue up.
---connection con_temp2
-ROLLBACK;
---connection server_2
-SET debug_sync='now WAIT_FOR slave_queued2';
-# And finally, we can let insert 1 proceed and do the group commit with all
-# three insert transactions together.
-SET debug_sync='now SIGNAL slave_cont1';
-
-# Wait for the commit to complete and check that all three transactions
-# group-committed together (will be seen in the binlog as all three having
-# cid=# on their GTID event).
---let $wait_condition= SELECT COUNT(*) = 3 FROM t3 WHERE a IN (2,4,6)
---source include/wait_condition.inc
-SELECT * FROM t3 ORDER BY a;
---let $binlog_file= slave-bin.000003
---source include/show_binlog_events.inc
-
-
---echo *** Test STOP SLAVE in parallel mode ***
---connection server_2
---source include/stop_slave.inc
-# Respawn all worker threads to clear any left-over debug_sync or other stuff.
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-
---connection server_1
-# Set up a couple of transactions. The first will be blocked halfway
-# through on a lock, and while it is blocked we initiate STOP SLAVE.
-# We then test that the halfway-initiated transaction is allowed to
-# complete, but no subsequent ones.
-# We have to use statement-based mode and set
-# binlog_direct_non_transactional_updates=0; otherwise the binlog will
-# be split into two event groups, one for the MyISAM part and one for the
-# InnoDB part.
-SET binlog_direct_non_transactional_updates=0;
-SET sql_log_bin=0;
-CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction");
-SET sql_log_bin=1;
-BEGIN;
-INSERT INTO t2 VALUES (20);
---disable_warnings
-INSERT INTO t1 VALUES (20);
---enable_warnings
-INSERT INTO t2 VALUES (21);
-INSERT INTO t3 VALUES (20, 20);
-COMMIT;
-INSERT INTO t3 VALUES(21, 21);
-INSERT INTO t3 VALUES(22, 22);
-SET binlog_format=@old_format;
---save_master_pos
-
-# Start a connection that will block the replicated transaction halfway.
---connection con_temp1
-BEGIN;
-INSERT INTO t2 VALUES (21);
-
---connection server_2
-START SLAVE;
-# Wait for the MyISAM change to be visible, after which replication will wait
-# for con_temp1 to roll back.
---let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE a=20
---source include/wait_condition.inc
-
---connection con_temp2
-# Initiate slave stop. It will have to wait for the current event group
-# to complete.
-# The dbug injection causes debug_sync to signal 'wait_for_done_waiting'
-# when the SQL driver thread is ready.
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
-send STOP SLAVE;
-
---connection con_temp1
-SET debug_sync='now WAIT_FOR wait_for_done_waiting';
-ROLLBACK;
-
---connection con_temp2
-reap;
-SET GLOBAL debug_dbug=@old_dbug;
-SET debug_sync='RESET';
-
---connection server_2
---source include/wait_for_slave_to_stop.inc
-# We should see the first transaction applied, but not the two others.
-SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
-SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
-SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
-
---source include/start_slave.inc
---sync_with_master
-SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
-SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
-SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
-
-
---connection server_2
-# Respawn all worker threads to clear any left-over debug_sync or other stuff.
---source include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-
---echo *** Test killing slave threads at various wait points ***
---echo *** 1. Test killing transaction waiting in commit for previous transaction to commit ***
-
-# Set up three transactions on the master that will be group-committed
-# together so they can be replicated in parallel on the slave.
---connection con_temp3
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (31, foo(31,
- 'commit_before_prepare_ordered WAIT_FOR t2_waiting',
- 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con_temp4
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-# This insert is just so we can get T2 to wait while a query is running that we
-# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
-INSERT INTO t3 VALUES (32, foo(32,
- 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
- ''));
-# This insert sets up debug_sync points so that T2 will tell when it is at its
-# wait point where we want to kill it - and when it has been killed.
-INSERT INTO t3 VALUES (33, foo(33,
- 'group_commit_waiting_for_prior SIGNAL t2_waiting',
- 'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-send COMMIT;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-
---connection con_temp5
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (34, foo(34,
- '',
- ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con_temp3
-REAP;
---connection con_temp4
-REAP;
---connection con_temp5
-REAP;
-
---connection server_1
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-SET debug_sync='RESET';
-
---connection server_2
-SET sql_log_bin=0;
-CALL mtr.add_suppression("Query execution was interrupted");
-CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
-CALL mtr.add_suppression("Slave: Connection was killed");
-SET sql_log_bin=1;
-# Wait until T2 is inside executing its insert of 32, then find it in SHOW
-# PROCESSLIST to know its thread id for KILL later.
-SET debug_sync='now WAIT_FOR t2_query';
---let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(32%' AND INFO NOT LIKE '%LIKE%'`
-SET debug_sync='now SIGNAL t2_cont';
-
-# Wait until T2 has entered its wait for T1 to commit, and T1 has
-# progressed into its commit phase.
-SET debug_sync='now WAIT_FOR t1_ready';
-
-# Now kill the transaction T2.
---replace_result $thd_id THD_ID
-eval KILL $thd_id;
-
-# Wait until T2 has reacted on the kill.
-SET debug_sync='now WAIT_FOR t2_killed';
-
-# Now we can allow T1 to proceed.
-SET debug_sync='now SIGNAL t1_cont';
-
---let $slave_sql_errno= 1317,1927,1964
---source include/wait_for_slave_sql_error.inc
-STOP SLAVE IO_THREAD;
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-
-# Now we have to disable the debug_sync statements, so they do not trigger
-# when the events are retried.
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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_1
-INSERT INTO t3 VALUES (39,0);
---save_master_pos
-
---connection server_2
---source include/start_slave.inc
---sync_with_master
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-# Restore the foo() function.
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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;
-
-
---connection server_2
-# Respawn all worker threads to clear any left-over debug_sync or other stuff.
---source include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-
---echo *** 2. Same as (1), but without restarting IO thread after kill of SQL threads ***
-
-# Set up three transactions on the master that will be group-committed
-# together so they can be replicated in parallel on the slave.
---connection con_temp3
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (41, foo(41,
- 'commit_before_prepare_ordered WAIT_FOR t2_waiting',
- 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con_temp4
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-# This insert is just so we can get T2 to wait while a query is running that we
-# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
-INSERT INTO t3 VALUES (42, foo(42,
- 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
- ''));
-# This insert sets up debug_sync points so that T2 will tell when it is at its
-# wait point where we want to kill it - and when it has been killed.
-INSERT INTO t3 VALUES (43, foo(43,
- 'group_commit_waiting_for_prior SIGNAL t2_waiting',
- 'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-send COMMIT;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-
---connection con_temp5
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (44, foo(44,
- '',
- ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con_temp3
-REAP;
---connection con_temp4
-REAP;
---connection con_temp5
-REAP;
-
---connection server_1
-SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
-SET debug_sync='RESET';
-
---connection server_2
-# Wait until T2 is inside executing its insert of 42, then find it in SHOW
-# PROCESSLIST to know its thread id for KILL later.
-SET debug_sync='now WAIT_FOR t2_query';
---let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(42%' AND INFO NOT LIKE '%LIKE%'`
-SET debug_sync='now SIGNAL t2_cont';
-
-# Wait until T2 has entered its wait for T1 to commit, and T1 has
-# progressed into its commit phase.
-SET debug_sync='now WAIT_FOR t1_ready';
-
-# Now kill the transaction T2.
---replace_result $thd_id THD_ID
-eval KILL $thd_id;
-
-# Wait until T2 has reacted on the kill.
-SET debug_sync='now WAIT_FOR t2_killed';
-
-# Now we can allow T1 to proceed.
-SET debug_sync='now SIGNAL t1_cont';
-
---let $slave_sql_errno= 1317,1927,1964
---source include/wait_for_slave_sql_error.inc
-
-# Now we have to disable the debug_sync statements, so they do not trigger
-# when the events are retried.
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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_1
-INSERT INTO t3 VALUES (49,0);
---save_master_pos
-
---connection server_2
-START SLAVE SQL_THREAD;
---sync_with_master
-SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
-# Restore the foo() function.
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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;
-
-
---connection server_2
-# Respawn all worker threads to clear any left-over debug_sync or other stuff.
---source include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-
---echo *** 3. Same as (2), but not using gtid mode ***
-
---connection server_2
---source include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=no;
---source include/start_slave.inc
-
---connection server_1
-# Set up three transactions on the master that will be group-committed
-# together so they can be replicated in parallel on the slave.
---connection con_temp3
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (51, foo(51,
- 'commit_before_prepare_ordered WAIT_FOR t2_waiting',
- 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con_temp4
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-# This insert is just so we can get T2 to wait while a query is running that we
-# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
-INSERT INTO t3 VALUES (52, foo(52,
- 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
- ''));
-# This insert sets up debug_sync points so that T2 will tell when it is at its
-# wait point where we want to kill it - and when it has been killed.
-INSERT INTO t3 VALUES (53, foo(53,
- 'group_commit_waiting_for_prior SIGNAL t2_waiting',
- 'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-send COMMIT;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-
---connection con_temp5
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-send INSERT INTO t3 VALUES (54, foo(54,
- '',
- ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con_temp3
-REAP;
---connection con_temp4
-REAP;
---connection con_temp5
-REAP;
-
---connection server_1
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-SET debug_sync='RESET';
-
---connection server_2
-# Wait until T2 is inside executing its insert of 52, then find it in SHOW
-# PROCESSLIST to know its thread id for KILL later.
-SET debug_sync='now WAIT_FOR t2_query';
---let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(52%' AND INFO NOT LIKE '%LIKE%'`
-SET debug_sync='now SIGNAL t2_cont';
-
-# Wait until T2 has entered its wait for T1 to commit, and T1 has
-# progressed into its commit phase.
-SET debug_sync='now WAIT_FOR t1_ready';
-
-# Now kill the transaction T2.
---replace_result $thd_id THD_ID
-eval KILL $thd_id;
-
-# Wait until T2 has reacted on the kill.
-SET debug_sync='now WAIT_FOR t2_killed';
-
-# Now we can allow T1 to proceed.
-SET debug_sync='now SIGNAL t1_cont';
-
---let $slave_sql_errno= 1317,1927,1964
---source include/wait_for_slave_sql_error.inc
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-
-# Now we have to disable the debug_sync statements, so they do not trigger
-# when the events are retried.
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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_1
-INSERT INTO t3 VALUES (59,0);
---save_master_pos
-
---connection server_2
-START SLAVE SQL_THREAD;
---sync_with_master
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-# Restore the foo() function.
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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;
-
-
---source include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=slave_pos;
---source include/start_slave.inc
-
---connection server_2
-# Respawn all worker threads to clear any left-over debug_sync or other stuff.
---source include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=4;
---source include/start_slave.inc
-
-
---echo *** 4. Test killing thread that is waiting to start transaction until previous transaction commits ***
-
-# We set up four transactions T1, T2, T3, and T4 on the master. T2, T3, and T4
-# can run in parallel with each other (same group commit and commit id),
-# but not in parallel with T1.
-#
-# We use four worker threads, each Ti will be queued on each their own
-# worker thread. We will delay T1 commit, T3 will wait for T1 to begin
-# commit before it can start. We will kill T3 during this wait, and
-# check that everything works correctly.
-#
-# It is rather tricky to get the correct thread id of the worker to kill.
-# We start by injecting four dummy transactions in a debug_sync-controlled
-# manner to be able to get known thread ids for the workers in a pool with
-# just 4 worker threads. Then we let in each of the real test transactions
-# T1-T4 one at a time in a way which allows us to know which transaction
-# ends up with which thread id.
-
---connection server_1
-SET binlog_format=statement;
-SET gtid_domain_id=2;
-BEGIN;
-# This debug_sync will linger on and be used to control T4 later.
-INSERT INTO t3 VALUES (70, foo(70,
- 'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', ''));
-INSERT INTO t3 VALUES (60, foo(60,
- 'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2',
- 'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-
---connection server_2
-SET debug_sync='now WAIT_FOR d2_query';
---let $d2_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(60%' AND INFO NOT LIKE '%LIKE%'`
-
---connection server_1
-SET gtid_domain_id=1;
-BEGIN;
-# These debug_sync's will linger on and be used to control T3 later.
-INSERT INTO t3 VALUES (61, foo(61,
- 'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting',
- 'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed'));
-INSERT INTO t3 VALUES (62, foo(62,
- 'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2',
- 'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-
---connection server_2
-SET debug_sync='now WAIT_FOR d1_query';
---let $d1_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(62%' AND INFO NOT LIKE '%LIKE%'`
-
---connection server_1
-SET gtid_domain_id=0;
-INSERT INTO t3 VALUES (63, foo(63,
- 'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2',
- 'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont'));
-
---connection server_2
-SET debug_sync='now WAIT_FOR d0_query';
---let $d0_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(63%' AND INFO NOT LIKE '%LIKE%'`
-
---connection server_1
-SET gtid_domain_id=3;
-BEGIN;
-# These debug_sync's will linger on and be used to control T2 later.
-INSERT INTO t3 VALUES (68, foo(68,
- 'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', ''));
-INSERT INTO t3 VALUES (69, foo(69,
- 'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2',
- 'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-
---connection server_2
-SET debug_sync='now WAIT_FOR d3_query';
---let $d3_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(69%' AND INFO NOT LIKE '%LIKE%'`
-
-SET debug_sync='now SIGNAL d2_cont2';
-SET debug_sync='now WAIT_FOR d2_done';
-SET debug_sync='now SIGNAL d1_cont2';
-SET debug_sync='now WAIT_FOR d1_done';
-SET debug_sync='now SIGNAL d0_cont2';
-SET debug_sync='now WAIT_FOR d0_done';
-SET debug_sync='now SIGNAL d3_cont2';
-SET debug_sync='now WAIT_FOR d3_done';
-
-# Now prepare the real transactions T1, T2, T3, T4 on the master.
-
---connection con_temp3
-# Create transaction T1.
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (64, foo(64,
- 'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', ''));
-
-# Create transaction T2, as a group commit leader on the master.
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2';
-send INSERT INTO t3 VALUES (65, foo(65, '', ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-
---connection con_temp4
-# Create transaction T3, participating in T2's group commit.
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-send INSERT INTO t3 VALUES (66, foo(66, '', ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued3';
-
---connection con_temp5
-# Create transaction T4, participating in group commit with T2 and T3.
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4';
-send INSERT INTO t3 VALUES (67, foo(67, '', ''));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued4';
-SET debug_sync='now SIGNAL master_cont2';
-
---connection con_temp3
-REAP;
---connection con_temp4
-REAP;
---connection con_temp5
-REAP;
-
---connection server_1
-SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
-SET debug_sync='RESET';
-
---connection server_2
-# Now we have the four transactions pending for replication on the slave.
-# Let them be queued for our three worker threads in a controlled fashion.
-# We put them at a stage where T1 is delayed and T3 is waiting for T1 to
-# commit before T3 can start. Then we kill T3.
-
-# Make the worker D0 free, and wait for T1 to be queued in it.
-SET debug_sync='now SIGNAL d0_cont';
-SET debug_sync='now WAIT_FOR t1_waiting';
-
-# Make the worker D3 free, and wait for T2 to be queued in it.
-SET debug_sync='now SIGNAL d3_cont';
-SET debug_sync='now WAIT_FOR t2_waiting';
-
-# Now release worker D1, and wait for T3 to be queued in it.
-# T3 will wait for T1 to commit before it can start.
-SET debug_sync='now SIGNAL d1_cont';
-SET debug_sync='now WAIT_FOR t3_waiting';
-
-# Release worker D2. Wait for T4 to be queued, so we are sure it has
-# received the debug_sync signal (else we might overwrite it with the
-# next debug_sync).
-SET debug_sync='now SIGNAL d2_cont';
-SET debug_sync='now WAIT_FOR t4_waiting';
-
-# Now we kill the waiting transaction T3 in worker D1.
---replace_result $d1_thd_id THD_ID
-eval KILL $d1_thd_id;
-
-# Wait until T3 has reacted on the kill.
-SET debug_sync='now WAIT_FOR t3_killed';
-
-# Now we can allow T1 to proceed.
-SET debug_sync='now SIGNAL t1_cont';
-
---let $slave_sql_errno= 1317,1927,1964
---source include/wait_for_slave_sql_error.inc
-STOP SLAVE IO_THREAD;
-# Since T2, T3, and T4 run in parallel, we can not be sure if T2 will have time
-# to commit or not before the stop. However, T1 should commit, and T3/T4 may
-# not have committed. (After slave restart we check that all become committed
-# eventually).
-SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a;
-
-# Now we have to disable the debug_sync statements, so they do not trigger
-# when the events are retried.
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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_1
-UPDATE t3 SET b=b+1 WHERE a=60;
---save_master_pos
-
---connection server_2
---source include/start_slave.inc
---sync_with_master
-SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
-# Restore the foo() function.
-SET sql_log_bin=0;
-DROP FUNCTION foo;
---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;
-
---connection server_2
-# Respawn all worker threads to clear any left-over debug_sync or other stuff.
---source include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-
---echo *** 5. Test killing thread that is waiting for queue of max length to shorten ***
-
-# Find the thread id of the driver SQL thread that we want to kill.
---let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Slave has read all relay log%'
---source include/wait_condition.inc
---let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Slave has read all relay log%'`
-SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued;
-SET GLOBAL slave_parallel_max_queued=9000;
-
---connection server_1
---let bigstring= `SELECT REPEAT('x', 10000)`
-SET binlog_format=statement;
-# Create an event that will wait to be signalled.
-INSERT INTO t3 VALUES (80, foo(0,
- 'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', ''));
-
---connection server_2
-SET debug_sync='now WAIT_FOR query_waiting';
-# Inject that the SQL driver thread will signal `wait_queue_ready' to debug_sync
-# as it goes to wait for the event queue to become smaller than the value of
-# @@slave_parallel_max_queued.
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max";
-
---connection server_1
---disable_query_log
-# Create an event that will fill up the queue.
-# The Xid event at the end of the event group will have to wait for the Query
-# event with the INSERT to drain so the queue becomes shorter. However that in
-# turn waits for the prior event group to continue.
-eval INSERT INTO t3 VALUES (81, LENGTH('$bigstring'));
---enable_query_log
-SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
-
---connection server_2
-SET debug_sync='now WAIT_FOR wait_queue_ready';
-
---replace_result $thd_id THD_ID
-eval KILL $thd_id;
-
-SET debug_sync='now WAIT_FOR wait_queue_killed';
-SET debug_sync='now SIGNAL query_cont';
-
---let $slave_sql_errno= 1317,1927,1964
---source include/wait_for_slave_sql_error.inc
-STOP SLAVE IO_THREAD;
-
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_max_queued= @old_max_queued;
-
---connection server_1
-INSERT INTO t3 VALUES (82,0);
-SET binlog_format=@old_format;
---save_master_pos
-
---connection server_2
-SET debug_sync='RESET';
---source include/start_slave.inc
---sync_with_master
-SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
-
-
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
---echo *** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication ***
-
---connection server_2
-# Use just two worker threads, so we are sure to get the rpl_group_info added
-# to the free list, which is what triggered the bug.
---source include/stop_slave.inc
-SET GLOBAL replicate_ignore_table="test.t3";
-SET GLOBAL slave_parallel_threads=2;
---source include/start_slave.inc
-
---connection server_1
-INSERT INTO t3 VALUES (100, rand());
-INSERT INTO t3 VALUES (101, rand());
-
---save_master_pos
-
---connection server_2
---sync_with_master
-
---connection server_1
-INSERT INTO t3 VALUES (102, rand());
-INSERT INTO t3 VALUES (103, rand());
-INSERT INTO t3 VALUES (104, rand());
-INSERT INTO t3 VALUES (105, rand());
-
---save_master_pos
-
---connection server_2
---sync_with_master
---source include/stop_slave.inc
-SET GLOBAL replicate_ignore_table="";
---source include/start_slave.inc
-
---connection server_1
-INSERT INTO t3 VALUES (106, rand());
-INSERT INTO t3 VALUES (107, rand());
---save_master_pos
-
---connection server_2
---sync_with_master
---replace_column 2 #
-SELECT * FROM t3 WHERE a >= 100 ORDER BY a;
-
-
---echo *** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction ***
-
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
---connection server_1
-INSERT INTO t3 VALUES (110, 1);
---save_master_pos
-
---connection server_2
---sync_with_master
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-# Inject a duplicate key error.
-SET sql_log_bin=0;
-INSERT INTO t3 VALUES (111, 666);
-SET sql_log_bin=1;
-
---connection server_1
-
-# Create a group commit with two inserts, the first one conflicts with a row on the slave
---connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-send INSERT INTO t3 VALUES (111, 2);
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-send INSERT INTO t3 VALUES (112, 3);
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con1
-REAP;
---connection con2
-REAP;
-SET debug_sync='RESET';
---save_master_pos
-
---connection server_2
---let $slave_sql_errno= 1062
---source include/wait_for_slave_sql_error.inc
---source include/wait_for_slave_sql_to_stop.inc
-# We should not see the row (112,3) here, it should be rolled back due to
-# error signal from the prior transaction.
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-SET sql_log_bin=0;
-DELETE FROM t3 WHERE a=111 AND b=666;
-SET sql_log_bin=1;
-START SLAVE SQL_THREAD;
---sync_with_master
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-
-
---echo ***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts ***
---connection server_2
---source include/stop_slave.inc
-
---connection server_1
-CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-
-# Create a group commit with UPDATE and DELETE, in that order.
-# The bug was that while the UPDATE's row lock does not block the DELETE, the
-# DELETE's gap lock _does_ block the UPDATE. This could cause a deadlock
-# on the slave.
---connection con1
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-send UPDATE t4 SET b=NULL WHERE a=6;
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con2
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-send DELETE FROM t4 WHERE b <= 3;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con1
-REAP;
---connection con2
-REAP;
-SET debug_sync='RESET';
---save_master_pos
-
---connection server_2
---source include/start_slave.inc
---sync_with_master
---source include/stop_slave.inc
-
-SELECT * FROM t4 ORDER BY a;
-
-
-# Another example, this one with INSERT vs. DELETE
---connection server_1
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-
-# Create a group commit with INSERT and DELETE, in that order.
-# The bug was that while the INSERT's insert intention lock does not block
-# the DELETE, the DELETE's gap lock _does_ block the INSERT. This could cause
-# a deadlock on the slave.
---connection con1
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-send INSERT INTO t4 VALUES (7, NULL);
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con2
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-send DELETE FROM t4 WHERE b <= 3;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con1
-REAP;
---connection con2
-REAP;
-SET debug_sync='RESET';
---save_master_pos
-
---connection server_2
---source include/start_slave.inc
---sync_with_master
---source include/stop_slave.inc
-
-SELECT * FROM t4 ORDER BY a;
-
-
-# MDEV-6549, failing to update gtid_slave_pos for a transaction that was retried.
-# The problem was that when a transaction updates the mysql.gtid_slave_pos
-# table, it clears the flag that marks that there is a GTID position that
-# needs to be updated. Then, if the transaction got killed after that due
-# to a deadlock, the subsequent retry would fail to notice that the GTID needs
-# to be recorded in gtid_slave_pos.
-#
-# (In the original bug report, the symptom was an assertion; this was however
-# just a side effect of the missing update of gtid_slave_pos, which also
-# happened to cause a missing clear of OPTION_GTID_BEGIN).
---connection server_1
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-
-# Create two transactions that can run in parallel on the slave but cause
-# a deadlock if the second runs before the first.
---connection con1
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-send UPDATE t4 SET b=NULL WHERE a=6;
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con2
-# Must use statement-based binlogging. Otherwise the transaction will not be
-# binlogged at all, as it modifies no rows.
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format='statement';
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-send DELETE FROM t4 WHERE b <= 1;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con1
-REAP;
---connection con2
-REAP;
-SET @old_format=@@GLOBAL.binlog_format;
-SET debug_sync='RESET';
---save_master_pos
---let $last_gtid= `SELECT @@last_gtid`
-
---connection server_2
-# Disable the usual skip of gap locks for transactions that are run in
-# parallel, using DBUG. This allows the deadlock to occur, and this in turn
-# triggers a retry of the second transaction, and the code that was buggy and
-# caused the gtid_slave_pos update to be skipped in the retry.
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
---source include/start_slave.inc
---sync_with_master
-SET GLOBAL debug_dbug=@old_dbug;
-
-SELECT * FROM t4 ORDER BY a;
-# Check that the GTID of the second transaction was correctly recorded in
-# gtid_slave_pos, in the variable as well as in the table.
---replace_result $last_gtid GTID
-eval SET @last_gtid= '$last_gtid';
-SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
- CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
- AS result;
-SELECT "ROW FOUND" AS `Is the row found?`
- FROM mysql.gtid_slave_pos
- WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
-
-
---echo *** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=1;
-SET DEBUG_SYNC= 'RESET';
---source include/start_slave.inc
-
---connection server_1
-CREATE TABLE t5 (a INT PRIMARY KEY, b INT);
-INSERT INTO t5 VALUES (1,1);
-INSERT INTO t5 VALUES (2,2), (3,8);
-INSERT INTO t5 VALUES (4,16);
---save_master_pos
-
---connection server_2
---sync_with_master
-let $io_file= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1);
-let $io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1);
-let $sql_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1);
-let $sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
---disable_query_log
-eval SELECT IF('$io_file' = '$sql_file', "OK", "Not ok, $io_file <> $sql_file") AS test_check;
-eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS test_check;
---enable_query_log
-
---connection server_1
-FLUSH LOGS;
---source include/wait_for_binlog_checkpoint.inc
---save_master_pos
-
---connection server_2
---sync_with_master
-let $io_file= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1);
-let $io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1);
-let $sql_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1);
-let $sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
---disable_query_log
-eval SELECT IF('$io_file' = '$sql_file', "OK", "Not ok, $io_file <> $sql_file") AS test_check;
-eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS test_check;
---enable_query_log
-
-
---echo *** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error ***
-
---connection server_1
-CREATE TABLE t6 (a INT) ENGINE=MyISAM;
-CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1;
-
---connection con1
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
---let $conid = `SELECT CONNECTION_ID()`
-SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont';
-send INSERT INTO t6 VALUES (1), (2), (3);
-
---connection server_1
-SET debug_sync='now WAIT_FOR ready';
---replace_result $conid CONID
-eval KILL QUERY $conid;
-SET debug_sync='now SIGNAL cont';
-
---connection con1
---error ER_QUERY_INTERRUPTED
---reap
-SET binlog_format= @old_format;
-SET debug_sync='RESET';
---let $after_error_gtid_pos= `SELECT @@gtid_binlog_pos`
-
---connection server_1
-SET debug_sync='RESET';
-
-
---connection server_2
---let $slave_sql_errno= 1317
---source include/wait_for_slave_sql_error.inc
-STOP SLAVE IO_THREAD;
---replace_result $after_error_gtid_pos AFTER_ERROR_GTID_POS
-eval SET GLOBAL gtid_slave_pos= '$after_error_gtid_pos';
---source include/start_slave.inc
-
---connection server_1
-INSERT INTO t6 VALUES (4);
-SELECT * FROM t6 ORDER BY a;
---save_master_pos
-
---connection server_2
---sync_with_master
-SELECT * FROM t6 ORDER BY a;
-
-
---echo *** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 ***
-
---connection server_1
-INSERT INTO t2 VALUES (31);
---let $gtid1= `SELECT @@LAST_GTID`
---source include/save_master_gtid.inc
-
---connection server_2
---source include/sync_with_master_gtid.inc
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads= 0;
---source include/start_slave.inc
-
-# Force a duplicate key error on the slave.
-SET sql_log_bin= 0;
-INSERT INTO t2 VALUES (32);
-SET sql_log_bin= 1;
-
---connection server_1
-INSERT INTO t2 VALUES (32);
---let $gtid2= `SELECT @@LAST_GTID`
-# Rotate the binlog; the bug is triggered when the master binlog file changes
-# after the event group that causes the duplicate key error.
-FLUSH LOGS;
-INSERT INTO t2 VALUES (33);
-INSERT INTO t2 VALUES (34);
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
---source include/save_master_gtid.inc
-
---connection server_2
---let $slave_sql_errno= 1062
---source include/wait_for_slave_sql_error.inc
-
---connection server_2
---source include/stop_slave_io.inc
-SET GLOBAL slave_parallel_threads=10;
-START SLAVE;
-
---let $slave_sql_errno= 1062
---source include/wait_for_slave_sql_error.inc
-
-# Note: IO thread is still running at this point.
-# The bug seems to have been that restarting the SQL thread after an error with
-# the IO thread still running, somehow picks up a later relay log position and
-# thus ends up skipping the failing event, rather than re-executing.
-
-START SLAVE SQL_THREAD;
---let $slave_sql_errno= 1062
---source include/wait_for_slave_sql_error.inc
-
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-
-# Skip the duplicate error, so we can proceed.
---error ER_SLAVE_SKIP_NOT_IN_GTID
-SET sql_slave_skip_counter= 1;
---source include/stop_slave_io.inc
---disable_query_log
-eval SET GLOBAL gtid_slave_pos = REPLACE(@@gtid_slave_pos, "$gtid1", "$gtid2");
---enable_query_log
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-
-
---echo *** MDEV-6775: Wrong binlog order in parallel replication ***
---connection server_1
-# A bit tricky bug to reproduce. On the master, we binlog in statement-mode
-# two transactions, an UPDATE followed by a DELETE. On the slave, we replicate
-# with binlog-mode set to ROW, which means the DELETE, which modifies no rows,
-# is not binlogged. Then we inject a wait in the group commit code on the
-# slave, shortly before the actual commit of the UPDATE. The bug was that the
-# DELETE could wake up from wait_for_prior_commit() before the commit of the
-# UPDATE. So the test could see the slave position updated to after DELETE,
-# while the UPDATE was still not visible.
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6);
---source include/save_master_gtid.inc
-
---connection server_2
---source include/sync_with_master_gtid.inc
---source include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log";
-SET @old_format=@@GLOBAL.binlog_format;
-SET GLOBAL binlog_format=ROW;
-# Re-spawn the worker threads to be sure they pick up the new binlog format
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-
---connection con1
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-send UPDATE t4 SET b=NULL WHERE a=6;
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con2
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-send DELETE FROM t4 WHERE b <= 3;
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con1
-REAP;
-SET binlog_format= @old_format;
---connection con2
-REAP;
-SET binlog_format= @old_format;
-SET debug_sync='RESET';
---save_master_pos
-SELECT * FROM t4 ORDER BY a;
-
---connection server_2
---source include/start_slave.inc
-SET debug_sync= 'now WAIT_FOR waiting';
---sync_with_master
-SELECT * FROM t4 ORDER BY a;
-SET debug_sync= 'now SIGNAL cont';
-
-# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC.
---source include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL binlog_format= @old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-
---echo *** MDEV-7237: Parallel replication: incorrect relaylog position after stop/start the slave ***
---connection server_1
-INSERT INTO t2 VALUES (40);
---save_master_pos
-
---connection server_2
---sync_with_master
---source include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=no;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-# This DBUG injection causes a DEBUG_SYNC signal "scheduled_gtid_0_x_100" when
-# GTID 0-1-100 has been scheduled for and fetched by a worker thread.
-SET GLOBAL debug_dbug="+d,rpl_parallel_scheduled_gtid_0_x_100";
-# This DBUG injection causes a DEBUG_SYNC signal "wait_for_done_waiting" when
-# STOP SLAVE has signalled all worker threads to stop.
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
-# Reset worker threads to make DBUG setting catch on.
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-
-
---connection server_1
-# Setup some transaction for the slave to replicate.
-INSERT INTO t2 VALUES (41);
-INSERT INTO t2 VALUES (42);
-# Need to log the DELETE in statement format, so we can see it in processlist.
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-DELETE FROM t2 WHERE a=40;
-SET binlog_format= @old_format;
-INSERT INTO t2 VALUES (43);
-INSERT INTO t2 VALUES (44);
-# Force the slave to switch to a new relay log file.
-FLUSH LOGS;
-INSERT INTO t2 VALUES (45);
-# Inject a GTID 0-1-100, which will trigger a DEBUG_SYNC signal when this
-# transaction has been fetched by a worker thread.
-SET gtid_seq_no=100;
-INSERT INTO t2 VALUES (46);
---save_master_pos
-
---connection con_temp2
-# Temporarily block the DELETE on a=40 from completing.
-BEGIN;
-SELECT * FROM t2 WHERE a=40 FOR UPDATE;
-
-
---connection server_2
---source include/start_slave.inc
-
-# Wait for a worker thread to start on the DELETE that will be blocked
-# temporarily by the SELECT FOR UPDATE.
---let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE state='updating' and info LIKE '%DELETE FROM t2 WHERE a=40%'
---source include/wait_condition.inc
-
-# The DBUG injection set above will make the worker thread signal the following
-# debug_sync when the GTID 0-1-100 has been reached by a worker thread.
-# Thus, at this point, the SQL driver thread has reached the next
-# relay log file name, while a worker thread is still processing a
-# transaction in the previous relay log file, blocked on the SELECT FOR
-# UPDATE.
-SET debug_sync= 'now WAIT_FOR scheduled_gtid_0_x_100';
-# At this point, the SQL driver thread is in the new relay log file, while
-# the DELETE from the old relay log file is not yet complete. We will stop
-# the slave at this point. The bug was that the DELETE statement would
-# update the slave position to the _new_ relay log file name instead of
-# its own old file name. Thus, by stoping and restarting the slave at this
-# point, we would get an error at restart due to incorrect position. (If
-# we would let the slave catch up before stopping, the incorrect position
-# would be corrected by a later transaction).
-
-send STOP SLAVE;
-
---connection con_temp2
-# Wait for STOP SLAVE to have proceeded sufficiently that it has signalled
-# all worker threads to stop; this ensures that we will stop after the DELETE
-# transaction (and not after a later transaction that might have been able
-# to set a fixed position).
-SET debug_sync= 'now WAIT_FOR wait_for_done_waiting';
-# Now release the row lock that was blocking the replication of DELETE.
-ROLLBACK;
-
---connection server_2
-reap;
---source include/wait_for_slave_sql_to_stop.inc
-SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
-# Now restart the slave. With the bug present, this would start at an
-# incorrect relay log position, causing relay log read error (or if unlucky,
-# silently skip a number of events).
---source include/start_slave.inc
---sync_with_master
-SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
---source include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET DEBUG_SYNC= 'RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-CHANGE MASTER TO master_use_gtid=slave_pos;
---source include/start_slave.inc
-
-
---echo *** MDEV-7326 Server deadlock in connection with parallel replication ***
-# We use three transactions, each in a separate group commit.
-# T1 does mark_start_commit(), then gets a deadlock error.
-# T2 wakes up and starts running
-# T1 does unmark_start_commit()
-# T3 goes to wait for T2 to start its commit
-# T2 does mark_start_commit()
-# The bug was that at this point, T3 got deadlocked. Because T1 has unmarked(),
-# T3 did not yet see the count_committing_event_groups reach its target value
-# yet. But when T1 later re-did mark_start_commit(), it failed to send a wakeup
-# to T3.
-
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=3;
-SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
---source include/start_slave.inc
-
---connection server_1
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format= STATEMENT;
-# This debug_sync will linger on and be used to control T3 later.
-INSERT INTO t1 VALUES (foo(50,
- "rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
- "rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
---save_master_pos
---connection server_2
-# Wait for the debug_sync point for T3 to be set. But let the preparation
-# transaction remain hanging, so that T1 and T2 will be scheduled for the
-# remaining two worker threads.
-SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
-
---connection server_1
-INSERT INTO t2 VALUES (foo(50,
- "rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
- "rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
---save_master_pos
-
---connection server_2
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
-# T1 has now done mark_start_commit(). It will later do a rollback and retry.
-
---connection server_1
-# Use a MyISAM table for T2 and T3, so they do not trigger the
-# rpl_parallel_simulate_temp_err_xid DBUG insertion on XID event.
-INSERT INTO t1 VALUES (foo(51,
- "rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
- "rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
-
---connection server_2
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
-# T2 has now started running, but has not yet done mark_start_commit()
-SET DEBUG_SYNC= "now SIGNAL t1_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
-# T1 has now done unmark_start_commit() in preparation for its retry.
-
---connection server_1
-INSERT INTO t1 VALUES (52);
-SET BINLOG_FORMAT= @old_format;
-SELECT * FROM t2 WHERE a>=50 ORDER BY a;
-SELECT * FROM t1 WHERE a>=50 ORDER BY a;
-
---connection server_2
-# Let the preparation transaction complete, so that the same worker thread
-# can continue with the transaction T3.
-SET DEBUG_SYNC= "now SIGNAL prep_cont";
-SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
-# T3 has now gone to wait for T2 to start committing
-SET DEBUG_SYNC= "now SIGNAL t2_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
-# T2 has now done mark_start_commit().
-# Let things run, and check that T3 does not get deadlocked.
-SET DEBUG_SYNC= "now SIGNAL t1_cont2";
---sync_with_master
-
---connection server_1
---save_master_pos
---connection server_2
---sync_with_master
-SELECT * FROM t2 WHERE a>=50 ORDER BY a;
-SELECT * FROM t1 WHERE a>=50 ORDER BY a;
-SET DEBUG_SYNC="reset";
-
-# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC.
---source include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
-
---echo *** MDEV-7326 Server deadlock in connection with parallel replication ***
-# Similar to the previous test, but with T2 and T3 in the same GCO.
-# We use three transactions, T1 in one group commit and T2/T3 in another.
-# T1 does mark_start_commit(), then gets a deadlock error.
-# T2 wakes up and starts running
-# T1 does unmark_start_commit()
-# T3 goes to wait for T1 to start its commit
-# T2 does mark_start_commit()
-# The bug was that at this point, T3 got deadlocked. T2 increments the
-# count_committing_event_groups but does not signal T3, as they are in
-# the same GCO. Then later when T1 increments, it would also not signal
-# T3, because now the count_committing_event_groups is not equal to the
-# wait_count of T3 (it is one larger).
-
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=3;
-SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
---source include/start_slave.inc
-
---connection server_1
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format= STATEMENT;
-# This debug_sync will linger on and be used to control T3 later.
-INSERT INTO t1 VALUES (foo(60,
- "rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
- "rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
---save_master_pos
---connection server_2
-# Wait for the debug_sync point for T3 to be set. But let the preparation
-# transaction remain hanging, so that T1 and T2 will be scheduled for the
-# remaining two worker threads.
-SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
-
---connection server_1
-INSERT INTO t2 VALUES (foo(60,
- "rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
- "rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
---save_master_pos
-
---connection server_2
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
-# T1 has now done mark_start_commit(). It will later do a rollback and retry.
-
-# Do T2 and T3 in a single group commit.
-# Use a MyISAM table for T2 and T3, so they do not trigger the
-# rpl_parallel_simulate_temp_err_xid DBUG insertion on XID event.
---connection con_temp3
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-send INSERT INTO t1 VALUES (foo(61,
- "rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
- "rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued1';
-
---connection con_temp4
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-send INSERT INTO t6 VALUES (62);
-
---connection server_1
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-
---connection con_temp3
-REAP;
---connection con_temp4
-REAP;
-
---connection server_1
-SET debug_sync='RESET';
-SET BINLOG_FORMAT= @old_format;
-SELECT * FROM t2 WHERE a>=60 ORDER BY a;
-SELECT * FROM t1 WHERE a>=60 ORDER BY a;
-SELECT * FROM t6 WHERE a>=60 ORDER BY a;
-
---connection server_2
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
-# T2 has now started running, but has not yet done mark_start_commit()
-SET DEBUG_SYNC= "now SIGNAL t1_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
-# T1 has now done unmark_start_commit() in preparation for its retry.
-
---connection server_2
-# Let the preparation transaction complete, so that the same worker thread
-# can continue with the transaction T3.
-SET DEBUG_SYNC= "now SIGNAL prep_cont";
-SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
-# T3 has now gone to wait for T2 to start committing
-SET DEBUG_SYNC= "now SIGNAL t2_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
-# T2 has now done mark_start_commit().
-# Let things run, and check that T3 does not get deadlocked.
-SET DEBUG_SYNC= "now SIGNAL t1_cont2";
---sync_with_master
-
---connection server_1
---save_master_pos
---connection server_2
---sync_with_master
-SELECT * FROM t2 WHERE a>=60 ORDER BY a;
-SELECT * FROM t1 WHERE a>=60 ORDER BY a;
-SELECT * FROM t6 WHERE a>=60 ORDER BY a;
-SET DEBUG_SYNC="reset";
-
-# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC.
---source include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
---echo *** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
-
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=1;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
-
---connection server_1
-INSERT INTO t2 VALUES (101);
-INSERT INTO t2 VALUES (102);
-INSERT INTO t2 VALUES (103);
-INSERT INTO t2 VALUES (104);
-INSERT INTO t2 VALUES (105);
-# Inject a partial event group (missing XID at the end). The bug was that such
-# partial group was not handled appropriately, leading to server deadlock.
-SET gtid_seq_no=1000;
-INSERT INTO t2 VALUES (106);
-INSERT INTO t2 VALUES (107);
-INSERT INTO t2 VALUES (108);
-INSERT INTO t2 VALUES (109);
-INSERT INTO t2 VALUES (110);
-INSERT INTO t2 VALUES (111);
-INSERT INTO t2 VALUES (112);
-INSERT INTO t2 VALUES (113);
-INSERT INTO t2 VALUES (114);
-INSERT INTO t2 VALUES (115);
-INSERT INTO t2 VALUES (116);
-INSERT INTO t2 VALUES (117);
-INSERT INTO t2 VALUES (118);
-INSERT INTO t2 VALUES (119);
-INSERT INTO t2 VALUES (120);
-INSERT INTO t2 VALUES (121);
-INSERT INTO t2 VALUES (122);
-INSERT INTO t2 VALUES (123);
-INSERT INTO t2 VALUES (124);
-INSERT INTO t2 VALUES (125);
-INSERT INTO t2 VALUES (126);
-INSERT INTO t2 VALUES (127);
-INSERT INTO t2 VALUES (128);
-INSERT INTO t2 VALUES (129);
-INSERT INTO t2 VALUES (130);
---source include/save_master_gtid.inc
-
---connection server_2
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-# The partial event group (a=106) should be rolled back and thus missing.
-SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
-
---source include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=10;
---source include/start_slave.inc
-
---echo *** MDEV-6676 - test syntax of @@slave_parallel_mode ***
---connection server_2
-
---let $status_items= Parallel_Mode
---source include/show_slave_status.inc
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_mode='aggressive';
---let $status_items= Parallel_Mode
---source include/show_slave_status.inc
-SET GLOBAL slave_parallel_mode='conservative';
---let $status_items= Parallel_Mode
---source include/show_slave_status.inc
-
-
---echo *** MDEV-6676 - test that empty parallel_mode does not replicate in parallel ***
---connection server_1
-INSERT INTO t2 VALUES (1040);
---source include/save_master_gtid.inc
-
---connection server_2
-SET GLOBAL slave_parallel_mode='none';
-# Test that we do not use parallel apply, by injecting an unconditional
-# crash in the parallel apply code.
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply";
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
---source include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-
-
---echo *** MDEV-6676 - test disabling domain-based parallel replication ***
---connection server_1
-# Let's do a bunch of transactions that will conflict if run out-of-order in
-# domain-based parallel replication mode.
-SET gtid_domain_id = 1;
-INSERT INTO t2 VALUES (1041);
-INSERT INTO t2 VALUES (1042);
-INSERT INTO t2 VALUES (1043);
-INSERT INTO t2 VALUES (1044);
-INSERT INTO t2 VALUES (1045);
-INSERT INTO t2 VALUES (1046);
-DELETE FROM t2 WHERE a >= 1041;
-SET gtid_domain_id = 2;
-INSERT INTO t2 VALUES (1041);
-INSERT INTO t2 VALUES (1042);
-INSERT INTO t2 VALUES (1043);
-INSERT INTO t2 VALUES (1044);
-INSERT INTO t2 VALUES (1045);
-INSERT INTO t2 VALUES (1046);
-SET gtid_domain_id = 0;
---source include/save_master_gtid.inc
---connection server_2
-SET GLOBAL slave_parallel_mode=minimal;
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
-
---echo *** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang ***
-
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_mode='conservative';
-SET GLOBAL slave_parallel_threads=10;
-
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep';
-
---connection server_1
-# Inject two group commits. The bug was that ANALYZE TABLE would call
-# wakeup_subsequent_commits() too early, allowing the following transaction
-# in the same group to run ahead and binlog and free the GCO. Then we get
-# wrong binlog order and later access freed GCO, which causes lost wakeup
-# of following GCO and thus replication hang.
-# We injected a small sleep in ANALYZE to make the race easier to hit (this
-# can only cause false negatives in versions with the bug, not false positives,
-# so sleep is ok here. And it's in general not possible to trigger reliably
-# the race with debug_sync, since the bugfix makes the race impossible).
-
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-
-# Group commit with cid=10000, two event groups.
-SET @commit_id= 10000;
-ANALYZE TABLE t2;
-INSERT INTO t3 VALUES (120, 0);
-
-# Group commit with cid=10001, one event group.
-SET @commit_id= 10001;
-INSERT INTO t3 VALUES (121, 0);
-
-SET SESSION debug_dbug=@old_dbug;
-
-SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
---source include/save_master_gtid.inc
-
---connection server_2
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-
-SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
-
---source include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
---source include/start_slave.inc
-
-
---echo *** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. ***
-
---connection server_2
---source include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep';
-
---connection server_1
-# Inject two group commits. The bug was that record_gtid for a
-# non-transactional event group would commit its own transaction, which would
-# cause ha_commit_trans() to call wakeup_subsequent_commits() too early. This
-# in turn lead to access to freed group_commit_orderer object, losing a wakeup
-# and causing slave threads to hang.
-# We inject a small sleep in the corresponding record_gtid() to make the race
-# easier to hit.
-
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-
-# Group commit with cid=10010, two event groups.
-SET @old_server_id= @@SESSION.server_id;
-SET SESSION server_id= 100;
-SET @commit_id= 10010;
-ALTER TABLE t1 COMMENT "Hulubulu!";
-SET SESSION server_id= @old_server_id;
-INSERT INTO t3 VALUES (130, 0);
-
-# Group commit with cid=10011, one event group.
-SET @commit_id= 10011;
-INSERT INTO t3 VALUES (131, 0);
-
-SET SESSION debug_dbug=@old_dbug;
-
-SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
---source include/save_master_gtid.inc
-
---connection server_2
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-
-SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
-
---source include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
---source include/start_slave.inc
-
-
---echo *** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) ***
-
---connection server_1
-INSERT INTO t3 VALUES (201,0), (202,0);
---source include/save_master_gtid.inc
-
---connection server_2
---source include/sync_with_master_gtid.inc
---source include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_mdev8031';
-
---connection server_1
-# We artificially create a situation that hopefully resembles the original
-# bug which was only seen "in the wild", and only once.
-# Setup a fake group commit with lots of conflicts that will lead to deadloc
-# kill. The slave DBUG injection causes the slave to be deadlock killed at
-# a particular point during the retry, and then later do a small sleep at
-# another critical point where the prior transaction then has a chance to
-# complete. Finally an extra KILL check catches an unhandled, lingering
-# deadlock kill. So rather artificial, but at least it exercises the
-# relevant code paths.
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-
-SET @commit_id= 10200;
-INSERT INTO t3 VALUES (203, 1);
-INSERT INTO t3 VALUES (204, 1);
-INSERT INTO t3 VALUES (205, 1);
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=205;
-UPDATE t3 SET b=b+1 WHERE a=205;
-SET SESSION debug_dbug=@old_dbug;
-
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
---source include/save_master_gtid.inc
-
---connection server_2
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
---source include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
---source include/start_slave.inc
-
-
---echo *** Check getting deadlock killed inside open_binlog() during retry. ***
-
---connection server_2
---source include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill';
-SET @old_max= @@GLOBAL.max_relay_log_size;
-SET GLOBAL max_relay_log_size= 4096;
-
---connection server_1
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-
---let $large= `SELECT REPEAT("*", 8192)`
-SET @commit_id= 10210;
---echo Omit long queries that cause relaylog rotations and transaction retries...
---disable_query_log
-eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=205 /* $large */;
-eval UPDATE t3 SET b=b+1 WHERE a=205 /* $large */;
---enable_query_log
-SET SESSION debug_dbug=@old_dbug;
-
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
---source include/save_master_gtid.inc
-
---connection server_2
---source include/start_slave.inc
---source include/sync_with_master_gtid.inc
-
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
---source include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_debg;
-SET GLOBAL max_relay_log_size= @old_max;
---source include/start_slave.inc
-
---echo *** MDEV-8725: Assertion on ROLLBACK statement in the binary log ***
---connection server_1
-# Inject an event group terminated by ROLLBACK, by mixing MyISAM and InnoDB
-# in a transaction. The bug was an assertion on the ROLLBACK due to
-# mark_start_commit() being already called.
---disable_warnings
-BEGIN;
-INSERT INTO t2 VALUES (2000);
-INSERT INTO t1 VALUES (2000);
-INSERT INTO t2 VALUES (2001);
-ROLLBACK;
---enable_warnings
-SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
-SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
---source include/save_master_gtid.inc
-
---connection server_2
---source include/sync_with_master_gtid.inc
-SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
-SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
-
-
-# Clean up.
---connection server_2
---source include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=@old_parallel_threads;
---source include/start_slave.inc
-SET DEBUG_SYNC= 'RESET';
-
---connection server_1
-DROP function foo;
-DROP TABLE t1,t2,t3,t4,t5,t6;
-SET DEBUG_SYNC= 'RESET';
-
---source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_analyze_table_hang.inc b/mysql-test/suite/rpl/include/rpl_parallel_analyze_table_hang.inc
new file mode 100644
index 00000000000..62a7501c36b
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_analyze_table_hang.inc
@@ -0,0 +1,73 @@
+--echo *** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang ***
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep';
+
+--connection server_1
+# Inject two group commits. The bug was that ANALYZE TABLE would call
+# wakeup_subsequent_commits() too early, allowing the following transaction
+# in the same group to run ahead and binlog and free the GCO. Then we get
+# wrong binlog order and later access freed GCO, which causes lost wakeup
+# of following GCO and thus replication hang.
+# We injected a small sleep in ANALYZE to make the race easier to hit (this
+# can only cause false negatives in versions with the bug, not false positives,
+# so sleep is ok here. And it's in general not possible to trigger reliably
+# the race with debug_sync, since the bugfix makes the race impossible).
+
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+
+# Group commit with cid=10000, two event groups.
+SET @commit_id= 10000;
+ANALYZE TABLE t2;
+INSERT INTO t3 VALUES (120, 0);
+
+# Group commit with cid=10001, one event group.
+SET @commit_id= 10001;
+INSERT INTO t3 VALUES (121, 0);
+
+SET SESSION debug_dbug=@old_dbug;
+
+SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+
+SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
+
+# Clean up.
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t2,t3;
+
+--source include/rpl_end.inc
+
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_deadlock_corrupt_binlog.inc b/mysql-test/suite/rpl/include/rpl_parallel_deadlock_corrupt_binlog.inc
new file mode 100644
index 00000000000..3a135ef5cc4
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_deadlock_corrupt_binlog.inc
@@ -0,0 +1,79 @@
+--echo *** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=1;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
+
+--connection server_1
+INSERT INTO t2 VALUES (101);
+INSERT INTO t2 VALUES (102);
+INSERT INTO t2 VALUES (103);
+INSERT INTO t2 VALUES (104);
+INSERT INTO t2 VALUES (105);
+# Inject a partial event group (missing XID at the end). The bug was that such
+# partial group was not handled appropriately, leading to server deadlock.
+SET gtid_seq_no=1000;
+INSERT INTO t2 VALUES (106);
+INSERT INTO t2 VALUES (107);
+INSERT INTO t2 VALUES (108);
+INSERT INTO t2 VALUES (109);
+INSERT INTO t2 VALUES (110);
+INSERT INTO t2 VALUES (111);
+INSERT INTO t2 VALUES (112);
+INSERT INTO t2 VALUES (113);
+INSERT INTO t2 VALUES (114);
+INSERT INTO t2 VALUES (115);
+INSERT INTO t2 VALUES (116);
+INSERT INTO t2 VALUES (117);
+INSERT INTO t2 VALUES (118);
+INSERT INTO t2 VALUES (119);
+INSERT INTO t2 VALUES (120);
+INSERT INTO t2 VALUES (121);
+INSERT INTO t2 VALUES (122);
+INSERT INTO t2 VALUES (123);
+INSERT INTO t2 VALUES (124);
+INSERT INTO t2 VALUES (125);
+INSERT INTO t2 VALUES (126);
+INSERT INTO t2 VALUES (127);
+INSERT INTO t2 VALUES (128);
+INSERT INTO t2 VALUES (129);
+INSERT INTO t2 VALUES (130);
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+# The partial event group (a=106) should be rolled back and thus missing.
+SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
+
+# Cleanup
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP TABLE t2;
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_domain.inc b/mysql-test/suite/rpl/include/rpl_parallel_domain.inc
new file mode 100644
index 00000000000..eda08cc2916
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_domain.inc
@@ -0,0 +1,87 @@
+# Test should work with both conservative and optimistic modes
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+# Test various aspects of parallel replication.
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--error ER_SLAVE_MUST_STOP
+SET GLOBAL slave_parallel_threads=10;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+
+# Check that we do not spawn any worker threads when no slave is running.
+SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+# Check that worker threads get spawned when slave starts.
+SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+# ... and that worker threads get removed when slave stops.
+--source include/stop_slave.inc
+SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+--source include/start_slave.inc
+SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+
+--echo *** Test long-running query in domain 1 can run in parallel with short queries in domain 0 ***
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+# Block the table t1 to simulate a replicated query taking a long time.
+--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
+LOCK TABLE t1 WRITE;
+
+--connection server_1
+SET gtid_domain_id=1;
+# This query will be blocked on the slave until UNLOCK TABLES.
+INSERT INTO t1 VALUES (2);
+SET gtid_domain_id=0;
+# These t2 queries can be replicated in parallel with the prior t1 query, as
+# they are in a separate replication domain.
+INSERT INTO t2 VALUES (2);
+INSERT INTO t2 VALUES (3);
+BEGIN;
+INSERT INTO t2 VALUES (4);
+INSERT INTO t2 VALUES (5);
+COMMIT;
+INSERT INTO t2 VALUES (6);
+
+--connection server_2
+--let $wait_condition= SELECT COUNT(*) = 6 FROM t2
+--source include/wait_condition.inc
+
+SELECT * FROM t2 ORDER by a;
+
+--connection con_temp1
+SELECT * FROM t1;
+UNLOCK TABLES;
+
+--connection server_2
+--let $wait_condition= SELECT COUNT(*) = 2 FROM t1
+--source include/wait_condition.inc
+
+SELECT * FROM t1 ORDER BY a;
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t1,t2;
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_domain_slave_single_grp.inc b/mysql-test/suite/rpl/include/rpl_parallel_domain_slave_single_grp.inc
new file mode 100644
index 00000000000..856efd065df
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_domain_slave_single_grp.inc
@@ -0,0 +1,128 @@
+# Test is independent of slave_parallel_mode
+--echo *** Test two transactions in different domains committed in opposite order on slave but in a single group commit. ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+# Test various aspects of parallel replication.
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+
+--connection server_1
+# 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;
+
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format='statement';
+SET gtid_domain_id=1;
+INSERT INTO t2 VALUES (foo(10,
+ 'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
+ 'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'));
+
+--connection server_2
+FLUSH LOGS;
+--source include/wait_for_binlog_checkpoint.inc
+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;
+SET @old_format=@@GLOBAL.binlog_format;
+SET GLOBAL binlog_format=statement;
+# We need to restart all parallel threads for the new global setting to
+# be copied to the session-level values.
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+--source include/start_slave.inc
+
+# First make sure the first insert is ready to commit, but not queued yet.
+SET debug_sync='now WAIT_FOR ready1';
+
+--connection server_1
+SET gtid_domain_id=2;
+INSERT INTO t2 VALUES (foo(11,
+ 'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
+ 'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'));
+SET gtid_domain_id=0;
+SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
+
+--connection server_2
+# Now wait for the second insert to queue itself as the leader, and then
+# wait for more commits to queue up.
+SET debug_sync='now WAIT_FOR ready3';
+SET debug_sync='now SIGNAL cont3';
+SET debug_sync='now WAIT_FOR ready4';
+# Now allow the first insert to queue up to participate in group commit.
+SET debug_sync='now SIGNAL cont1';
+SET debug_sync='now WAIT_FOR ready2';
+# Finally allow the second insert to proceed and do the group commit.
+SET debug_sync='now SIGNAL cont4';
+
+--let $wait_condition= SELECT COUNT(*) = 2 FROM t2 WHERE a >= 10
+--source include/wait_condition.inc
+SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
+# The two INSERT transactions should have been committed in opposite order,
+# but in the same group commit (seen by precense of cid=# in the SHOW
+# BINLOG output).
+--let $binlog_file= slave-bin.000002
+--source include/show_binlog_events.inc
+FLUSH LOGS;
+--source include/wait_for_binlog_checkpoint.inc
+
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL binlog_format=@old_format;
+
+--connection server_1
+DROP function foo;
+DROP TABLE t1,t2;
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL binlog_format=@old_format;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_free_deferred_event.inc b/mysql-test/suite/rpl/include/rpl_parallel_free_deferred_event.inc
new file mode 100644
index 00000000000..41f372eddf8
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_free_deferred_event.inc
@@ -0,0 +1,67 @@
+--echo *** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication ***
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+# Use just two worker threads, so we are sure to get the rpl_group_info added
+# to the free list, which is what triggered the bug.
+--source include/stop_slave.inc
+SET GLOBAL replicate_ignore_table="test.t3";
+SET GLOBAL slave_parallel_threads=2;
+--source include/start_slave.inc
+
+--connection server_1
+INSERT INTO t3 VALUES (100, rand());
+INSERT INTO t3 VALUES (101, rand());
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--connection server_1
+INSERT INTO t3 VALUES (102, rand());
+INSERT INTO t3 VALUES (103, rand());
+INSERT INTO t3 VALUES (104, rand());
+INSERT INTO t3 VALUES (105, rand());
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+SET GLOBAL replicate_ignore_table="";
+--source include/start_slave.inc
+
+--connection server_1
+INSERT INTO t3 VALUES (106, rand());
+INSERT INTO t3 VALUES (107, rand());
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--replace_column 2 #
+SELECT * FROM t3 WHERE a >= 100 ORDER BY a;
+
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t3;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_gco_wait_kill.inc b/mysql-test/suite/rpl/include/rpl_parallel_gco_wait_kill.inc
new file mode 100644
index 00000000000..d918b2ea692
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_gco_wait_kill.inc
@@ -0,0 +1,366 @@
+--echo *** Test killing thread that is waiting to start transaction until previous transaction commits ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode;
+--source include/stop_slave.inc
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Query execution was interrupted");
+CALL mtr.add_suppression("Slave: Connection was killed");
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET sql_log_bin=1;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode= 'conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--connection server_1
+# 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_2
+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;
+# We need to restart all parallel threads for the new global setting to
+# be copied to the session-level values.
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=4;
+--source include/start_slave.inc
+
+
+# We set up four transactions T1, T2, T3, and T4 on the master. T2, T3, and T4
+# can run in parallel with each other (same group commit and commit id),
+# but not in parallel with T1.
+#
+# We use four worker threads, each Ti will be queued on each their own
+# worker thread. We will delay T1 commit, T3 will wait for T1 to begin
+# commit before it can start. We will kill T3 during this wait, and
+# check that everything works correctly.
+#
+# It is rather tricky to get the correct thread id of the worker to kill.
+# We start by injecting four dummy transactions in a debug_sync-controlled
+# manner to be able to get known thread ids for the workers in a pool with
+# just 4 worker threads. Then we let in each of the real test transactions
+# T1-T4 one at a time in a way which allows us to know which transaction
+# ends up with which thread id.
+
+--connection server_1
+SET gtid_domain_id=2;
+BEGIN;
+# This debug_sync will linger on and be used to control T4 later.
+INSERT INTO t3 VALUES (70, foo(70,
+ 'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', ''));
+INSERT INTO t3 VALUES (60, foo(60,
+ 'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2',
+ 'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+
+--connection server_2
+SET debug_sync='now WAIT_FOR d2_query';
+--let $d2_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(60%' AND INFO NOT LIKE '%LIKE%'`
+
+--connection server_1
+SET gtid_domain_id=1;
+BEGIN;
+# These debug_sync's will linger on and be used to control T3 later.
+INSERT INTO t3 VALUES (61, foo(61,
+ 'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting',
+ 'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed'));
+INSERT INTO t3 VALUES (62, foo(62,
+ 'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2',
+ 'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+
+--connection server_2
+SET debug_sync='now WAIT_FOR d1_query';
+--let $d1_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(62%' AND INFO NOT LIKE '%LIKE%'`
+
+--connection server_1
+SET gtid_domain_id=0;
+INSERT INTO t3 VALUES (63, foo(63,
+ 'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2',
+ 'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont'));
+
+--connection server_2
+SET debug_sync='now WAIT_FOR d0_query';
+--let $d0_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(63%' AND INFO NOT LIKE '%LIKE%'`
+
+--connection server_1
+SET gtid_domain_id=3;
+BEGIN;
+# These debug_sync's will linger on and be used to control T2 later.
+INSERT INTO t3 VALUES (68, foo(68,
+ 'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', ''));
+INSERT INTO t3 VALUES (69, foo(69,
+ 'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2',
+ 'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+
+--connection server_2
+SET debug_sync='now WAIT_FOR d3_query';
+--let $d3_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(69%' AND INFO NOT LIKE '%LIKE%'`
+
+SET debug_sync='now SIGNAL d2_cont2';
+SET debug_sync='now WAIT_FOR d2_done';
+SET debug_sync='now SIGNAL d1_cont2';
+SET debug_sync='now WAIT_FOR d1_done';
+SET debug_sync='now SIGNAL d0_cont2';
+SET debug_sync='now WAIT_FOR d0_done';
+SET debug_sync='now SIGNAL d3_cont2';
+SET debug_sync='now WAIT_FOR d3_done';
+
+# Now prepare the real transactions T1, T2, T3, T4 on the master.
+
+--connection con_temp3
+# Create transaction T1.
+INSERT INTO t3 VALUES (64, foo(64,
+ 'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', ''));
+
+# Create transaction T2, as a group commit leader on the master.
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2';
+send INSERT INTO t3 VALUES (65, foo(65, '', ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+
+--connection con_temp4
+# Create transaction T3, participating in T2's group commit.
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+send INSERT INTO t3 VALUES (66, foo(66, '', ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued3';
+
+--connection con_temp5
+# Create transaction T4, participating in group commit with T2 and T3.
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4';
+send INSERT INTO t3 VALUES (67, foo(67, '', ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued4';
+SET debug_sync='now SIGNAL master_cont2';
+
+--connection con_temp3
+REAP;
+--connection con_temp4
+REAP;
+--connection con_temp5
+REAP;
+
+--connection server_1
+SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
+SET debug_sync='RESET';
+
+--connection server_2
+# Now we have the four transactions pending for replication on the slave.
+# Let them be queued for our three worker threads in a controlled fashion.
+# We put them at a stage where T1 is delayed and T3 is waiting for T1 to
+# commit before T3 can start. Then we kill T3.
+
+# Make the worker D0 free, and wait for T1 to be queued in it.
+SET debug_sync='now SIGNAL d0_cont';
+SET debug_sync='now WAIT_FOR t1_waiting';
+
+# Make the worker D3 free, and wait for T2 to be queued in it.
+SET debug_sync='now SIGNAL d3_cont';
+SET debug_sync='now WAIT_FOR t2_waiting';
+
+# Now release worker D1, and wait for T3 to be queued in it.
+# T3 will wait for T1 to commit before it can start.
+SET debug_sync='now SIGNAL d1_cont';
+SET debug_sync='now WAIT_FOR t3_waiting';
+
+# Release worker D2. Wait for T4 to be queued, so we are sure it has
+# received the debug_sync signal (else we might overwrite it with the
+# next debug_sync).
+SET debug_sync='now SIGNAL d2_cont';
+SET debug_sync='now WAIT_FOR t4_waiting';
+
+# Now we kill the waiting transaction T3 in worker D1.
+--replace_result $d1_thd_id THD_ID
+eval KILL $d1_thd_id;
+
+# Wait until T3 has reacted on the kill.
+SET debug_sync='now WAIT_FOR t3_killed';
+
+# Now we can allow T1 to proceed.
+SET debug_sync='now SIGNAL t1_cont';
+
+--let $slave_sql_errno= 1317,1927,1964
+--source include/wait_for_slave_sql_error.inc
+STOP SLAVE IO_THREAD;
+# Since T2, T3, and T4 run in parallel, we can not be sure if T2 will have time
+# to commit or not before the stop. However, T1 should commit, and T3/T4 may
+# not have committed. (After slave restart we check that all become committed
+# eventually).
+SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a;
+
+# Now we have to disable the debug_sync statements, so they do not trigger
+# when the events are retried.
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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_1
+UPDATE t3 SET b=b+1 WHERE a=60;
+--save_master_pos
+
+--connection server_2
+--source include/start_slave.inc
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
+# Restore the foo() function.
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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;
+
+--connection server_2
+# Respawn all worker threads to clear any left-over debug_sync or other stuff.
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+--source include/start_slave.inc
+
+--echo *** 5. Test killing thread that is waiting for queue of max length to shorten ***
+
+# Find the thread id of the driver SQL thread that we want to kill.
+--let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Slave has read all relay log%'
+--source include/wait_condition.inc
+--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Slave has read all relay log%'`
+SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued;
+SET GLOBAL slave_parallel_max_queued=9000;
+
+--connection server_1
+--let bigstring= `SELECT REPEAT('x', 10000)`
+# Create an event that will wait to be signalled.
+INSERT INTO t3 VALUES (80, foo(0,
+ 'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', ''));
+
+--connection server_2
+SET debug_sync='now WAIT_FOR query_waiting';
+# Inject that the SQL driver thread will signal `wait_queue_ready' to debug_sync
+# as it goes to wait for the event queue to become smaller than the value of
+# @@slave_parallel_max_queued.
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max";
+
+--connection server_1
+--disable_query_log
+# Create an event that will fill up the queue.
+# The Xid event at the end of the event group will have to wait for the Query
+# event with the INSERT to drain so the queue becomes shorter. However that in
+# turn waits for the prior event group to continue.
+eval INSERT INTO t3 VALUES (81, LENGTH('$bigstring'));
+--enable_query_log
+SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
+
+--connection server_2
+SET debug_sync='now WAIT_FOR wait_queue_ready';
+
+--replace_result $thd_id THD_ID
+eval KILL $thd_id;
+
+SET debug_sync='now WAIT_FOR wait_queue_killed';
+SET debug_sync='now SIGNAL query_cont';
+
+--let $slave_sql_errno= 1317,1927,1964
+--source include/wait_for_slave_sql_error.inc
+STOP SLAVE IO_THREAD;
+
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_max_queued= @old_max_queued;
+
+--connection server_1
+INSERT INTO t3 VALUES (82,0);
+--save_master_pos
+
+--connection server_2
+SET debug_sync='RESET';
+--source include/start_slave.inc
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
+
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP function foo;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_gtid_slave_pos_update_fail.inc b/mysql-test/suite/rpl/include/rpl_parallel_gtid_slave_pos_update_fail.inc
new file mode 100644
index 00000000000..da1a07d3b87
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_gtid_slave_pos_update_fail.inc
@@ -0,0 +1,98 @@
+# MDEV-6549, failing to update gtid_slave_pos for a transaction that was retried.
+
+# The problem was that when a transaction updates the mysql.gtid_slave_pos
+# table, it clears the flag that marks that there is a GTID position that
+# needs to be updated. Then, if the transaction got killed after that due
+# to a deadlock, the subsequent retry would fail to notice that the GTID needs
+# to be recorded in gtid_slave_pos.
+#
+# (In the original bug report, the symptom was an assertion; this was however
+# just a side effect of the missing update of gtid_slave_pos, which also
+# happened to cause a missing clear of OPTION_GTID_BEGIN).
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+# Must use statement-based binlogging. Otherwise the transaction will not be
+# binlogged at all, as it modifies no rows.
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+
+# Create two transactions that can run in parallel on the slave but cause
+# a deadlock if the second runs before the first.
+--connection con1
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send UPDATE t4 SET b=NULL WHERE a=6;
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con2
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send DELETE FROM t4 WHERE b <= 1;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con1
+REAP;
+--connection con2
+REAP;
+SET debug_sync='RESET';
+--save_master_pos
+--let $last_gtid= `SELECT @@last_gtid`
+
+--connection server_2
+# Disable the usual skip of gap locks for transactions that are run in
+# parallel, using DBUG. This allows the deadlock to occur, and this in turn
+# triggers a retry of the second transaction, and the code that was buggy and
+# caused the gtid_slave_pos update to be skipped in the retry.
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
+--source include/start_slave.inc
+--sync_with_master
+SET GLOBAL debug_dbug=@old_dbug;
+
+SELECT * FROM t4 ORDER BY a;
+# Check that the GTID of the second transaction was correctly recorded in
+# gtid_slave_pos, in the variable as well as in the table.
+--replace_result $last_gtid GTID
+eval SET @last_gtid= '$last_gtid';
+SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
+ CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
+ AS result;
+SELECT "ROW FOUND" AS `Is the row found?`
+ FROM mysql.gtid_slave_pos
+ WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+--disconnect con1
+--disconnect con2
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_ignore_error_on_rotate.inc b/mysql-test/suite/rpl/include/rpl_parallel_ignore_error_on_rotate.inc
new file mode 100644
index 00000000000..2fab9f8032b
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_ignore_error_on_rotate.inc
@@ -0,0 +1,96 @@
+--echo *** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 ***
+
+--source include/have_innodb.inc
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source 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=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+SET gtid_domain_id=1;
+INSERT INTO t2 VALUES (1);
+SET gtid_domain_id=0;
+SET gtid_domain_id=2;
+INSERT INTO t2 VALUES (2);
+SET gtid_domain_id=0;
+INSERT INTO t2 VALUES (31);
+--let $gtid1= `SELECT @@LAST_GTID`
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/sync_with_master_gtid.inc
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads= 0;
+--source include/start_slave.inc
+
+# Force a duplicate key error on the slave.
+SET sql_log_bin= 0;
+INSERT INTO t2 VALUES (32);
+SET sql_log_bin= 1;
+
+--connection server_1
+INSERT INTO t2 VALUES (32);
+--let $gtid2= `SELECT @@LAST_GTID`
+# Rotate the binlog; the bug is triggered when the master binlog file changes
+# after the event group that causes the duplicate key error.
+FLUSH LOGS;
+INSERT INTO t2 VALUES (33);
+INSERT INTO t2 VALUES (34);
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+--source include/save_master_gtid.inc
+
+--connection server_2
+--let $slave_sql_errno= 1062
+--source include/wait_for_slave_sql_error.inc
+
+--connection server_2
+--source include/stop_slave_io.inc
+SET GLOBAL slave_parallel_threads=10;
+START SLAVE;
+
+--let $slave_sql_errno= 1062
+--source include/wait_for_slave_sql_error.inc
+
+# Note: IO thread is still running at this point.
+# The bug seems to have been that restarting the SQL thread after an error with
+# the IO thread still running, somehow picks up a later relay log position and
+# thus ends up skipping the failing event, rather than re-executing.
+
+START SLAVE SQL_THREAD;
+--let $slave_sql_errno= 1062
+--source include/wait_for_slave_sql_error.inc
+
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+
+# Skip the duplicate error, so we can proceed.
+--error ER_SLAVE_SKIP_NOT_IN_GTID
+SET sql_slave_skip_counter= 1;
+--source include/stop_slave_io.inc
+--disable_query_log
+eval SET GLOBAL gtid_slave_pos = REPLACE(@@gtid_slave_pos, "$gtid1", "$gtid2");
+--enable_query_log
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t2;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_incorrect_relay_pos.inc b/mysql-test/suite/rpl/include/rpl_parallel_incorrect_relay_pos.inc
new file mode 100644
index 00000000000..3cf0afd63ca
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_incorrect_relay_pos.inc
@@ -0,0 +1,128 @@
+--echo *** MDEV-7237: Parallel replication: incorrect relaylog position after stop/start the slave ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source include/stop_slave.inc
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_threads=10;
+# Test assumes that 'conservative' mode is in effect. i.e
+# Do not start parallel execution of this event group until all prior groups
+# have reached the commit phase. Upon execution of STOP SLAVE there can be one
+# group which is executing and the rest are doing group commit order wait.
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (40);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
+--source include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=no;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+# This DBUG injection causes a DEBUG_SYNC signal "scheduled_gtid_0_x_100" when
+# GTID 0-1-100 has been scheduled for and fetched by a worker thread.
+SET GLOBAL debug_dbug="+d,rpl_parallel_scheduled_gtid_0_x_100";
+# This DBUG injection causes a DEBUG_SYNC signal "wait_for_done_waiting" when
+# STOP SLAVE has signalled all worker threads to stop.
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
+# Reset worker threads to make DBUG setting catch on.
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+
+
+--connection server_1
+# Setup some transaction for the slave to replicate.
+INSERT INTO t2 VALUES (41);
+INSERT INTO t2 VALUES (42);
+# Need to log the DELETE in statement format, so we can see it in processlist.
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+DELETE FROM t2 WHERE a=40;
+SET binlog_format= @old_format;
+INSERT INTO t2 VALUES (43);
+INSERT INTO t2 VALUES (44);
+# Force the slave to switch to a new relay log file.
+FLUSH LOGS;
+INSERT INTO t2 VALUES (45);
+# Inject a GTID 0-1-100, which will trigger a DEBUG_SYNC signal when this
+# transaction has been fetched by a worker thread.
+SET gtid_seq_no=100;
+INSERT INTO t2 VALUES (46);
+--save_master_pos
+
+--connection con_temp2
+# Temporarily block the DELETE on a=40 from completing.
+BEGIN;
+SELECT * FROM t2 WHERE a=40 FOR UPDATE;
+
+--connection server_2
+--source include/start_slave.inc
+
+# Wait for a worker thread to start on the DELETE that will be blocked
+# temporarily by the SELECT FOR UPDATE.
+--let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE state='updating' and info LIKE '%DELETE FROM t2 WHERE a=40%'
+--source include/wait_condition.inc
+
+# The DBUG injection set above will make the worker thread signal the following
+# debug_sync when the GTID 0-1-100 has been reached by a worker thread.
+# Thus, at this point, the SQL driver thread has reached the next
+# relay log file name, while a worker thread is still processing a
+# transaction in the previous relay log file, blocked on the SELECT FOR
+# UPDATE.
+SET debug_sync= 'now WAIT_FOR scheduled_gtid_0_x_100';
+# At this point, the SQL driver thread is in the new relay log file, while
+# the DELETE from the old relay log file is not yet complete. We will stop
+# the slave at this point. The bug was that the DELETE statement would
+# update the slave position to the _new_ relay log file name instead of
+# its own old file name. Thus, by stoping and restarting the slave at this
+# point, we would get an error at restart due to incorrect position. (If
+# we would let the slave catch up before stopping, the incorrect position
+# would be corrected by a later transaction).
+
+send STOP SLAVE;
+
+--connection con_temp2
+# Wait for STOP SLAVE to have proceeded sufficiently that it has signalled
+# all worker threads to stop; this ensures that we will stop after the DELETE
+# transaction (and not after a later transaction that might have been able
+# to set a fixed position).
+SET debug_sync= 'now WAIT_FOR wait_for_done_waiting';
+# Now release the row lock that was blocking the replication of DELETE.
+ROLLBACK;
+
+--connection server_2
+reap;
+--source include/wait_for_slave_sql_to_stop.inc
+SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
+# Now restart the slave. With the bug present, this would start at an
+# incorrect relay log position, causing relay log read error (or if unlucky,
+# silently skip a number of events).
+--source include/start_slave.inc
+--sync_with_master
+SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
+
+# Clean up.
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t2;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_innodb_lock_conflict.inc b/mysql-test/suite/rpl/include/rpl_parallel_innodb_lock_conflict.inc
new file mode 100644
index 00000000000..90304937445
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_innodb_lock_conflict.inc
@@ -0,0 +1,107 @@
+--echo ***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET sql_log_bin=1;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+
+# Create a group commit with UPDATE and DELETE, in that order.
+# The bug was that while the UPDATE's row lock does not block the DELETE, the
+# DELETE's gap lock _does_ block the UPDATE. This could cause a deadlock
+# on the slave.
+--connection con1
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send UPDATE t4 SET b=NULL WHERE a=6;
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con2
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send DELETE FROM t4 WHERE b <= 3;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con1
+REAP;
+--connection con2
+REAP;
+SET debug_sync='RESET';
+--save_master_pos
+
+--connection server_2
+--source include/start_slave.inc
+--sync_with_master
+--source include/stop_slave.inc
+
+SELECT * FROM t4 ORDER BY a;
+
+
+# Another example, this one with INSERT vs. DELETE
+--connection server_1
+DELETE FROM t4;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+
+# Create a group commit with INSERT and DELETE, in that order.
+# The bug was that while the INSERT's insert intention lock does not block
+# the DELETE, the DELETE's gap lock _does_ block the INSERT. This could cause
+# a deadlock on the slave.
+--connection con1
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send INSERT INTO t4 VALUES (7, NULL);
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con2
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send DELETE FROM t4 WHERE b <= 3;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con1
+REAP;
+--connection con2
+REAP;
+SET debug_sync='RESET';
+--save_master_pos
+
+--connection server_2
+--source include/start_slave.inc
+--sync_with_master
+--source include/stop_slave.inc
+
+SELECT * FROM t4 ORDER BY a;
+
+
+# Clean up.
+--connection server_2
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+--disconnect con1
+--disconnect con2
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_missed_error_handling.inc b/mysql-test/suite/rpl/include/rpl_parallel_missed_error_handling.inc
new file mode 100644
index 00000000000..33b1bcb11d9
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_missed_error_handling.inc
@@ -0,0 +1,87 @@
+--echo *** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--connection server_1
+INSERT INTO t3 VALUES (110, 1);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+# Inject a duplicate key error.
+SET sql_log_bin=0;
+INSERT INTO t3 VALUES (111, 666);
+SET sql_log_bin=1;
+
+--connection server_1
+
+# Create a group commit with two inserts, the first one conflicts with a row on the slave
+--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send INSERT INTO t3 VALUES (111, 2);
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send INSERT INTO t3 VALUES (112, 3);
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con1
+REAP;
+--connection con2
+REAP;
+SET debug_sync='RESET';
+--save_master_pos
+
+--connection server_2
+--let $slave_sql_errno= 1062
+--source include/wait_for_slave_sql_error.inc
+--source include/wait_for_slave_sql_to_stop.inc
+# We should not see the row (112,3) here, it should be rolled back due to
+# error signal from the prior transaction.
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+SET sql_log_bin=0;
+DELETE FROM t3 WHERE a=111 AND b=666;
+SET sql_log_bin=1;
+START SLAVE SQL_THREAD;
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+--disconnect con1
+--disconnect con2
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_mode.inc b/mysql-test/suite/rpl/include/rpl_parallel_mode.inc
new file mode 100644
index 00000000000..67104069e9a
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_mode.inc
@@ -0,0 +1,87 @@
+--echo *** MDEV-6676 - test syntax of @@slave_parallel_mode ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source 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=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--let $status_items= Parallel_Mode
+--source include/show_slave_status.inc
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='aggressive';
+--let $status_items= Parallel_Mode
+--source include/show_slave_status.inc
+SET GLOBAL slave_parallel_mode='conservative';
+--let $status_items= Parallel_Mode
+--source include/show_slave_status.inc
+
+--echo *** MDEV-6676 - test that empty parallel_mode does not replicate in parallel ***
+--connection server_1
+INSERT INTO t2 VALUES (1040);
+--source include/save_master_gtid.inc
+
+--connection server_2
+SET GLOBAL slave_parallel_mode='none';
+# Test that we do not use parallel apply, by injecting an unconditional
+# crash in the parallel apply code.
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply";
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+
+
+--echo *** MDEV-6676 - test disabling domain-based parallel replication ***
+--connection server_1
+# Let's do a bunch of transactions that will conflict if run out-of-order in
+# domain-based parallel replication mode.
+SET gtid_domain_id = 1;
+INSERT INTO t2 VALUES (1041);
+INSERT INTO t2 VALUES (1042);
+INSERT INTO t2 VALUES (1043);
+INSERT INTO t2 VALUES (1044);
+INSERT INTO t2 VALUES (1045);
+INSERT INTO t2 VALUES (1046);
+DELETE FROM t2 WHERE a >= 1041;
+SET gtid_domain_id = 2;
+INSERT INTO t2 VALUES (1041);
+INSERT INTO t2 VALUES (1042);
+INSERT INTO t2 VALUES (1043);
+INSERT INTO t2 VALUES (1044);
+INSERT INTO t2 VALUES (1045);
+INSERT INTO t2 VALUES (1046);
+SET gtid_domain_id = 0;
+--source include/save_master_gtid.inc
+--connection server_2
+SET GLOBAL slave_parallel_mode=minimal;
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
+
+# Cleanup
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t2;
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_partial_binlog_trans.inc b/mysql-test/suite/rpl/include/rpl_parallel_partial_binlog_trans.inc
new file mode 100644
index 00000000000..7247925285f
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_partial_binlog_trans.inc
@@ -0,0 +1,71 @@
+--echo *** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t6 (a INT) ENGINE=MyISAM;
+CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1;
+--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+
+--connection con1
+--let $conid = `SELECT CONNECTION_ID()`
+SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont';
+send INSERT INTO t6 VALUES (1), (2), (3);
+
+--connection server_1
+SET debug_sync='now WAIT_FOR ready';
+--replace_result $conid CONID
+eval KILL QUERY $conid;
+SET debug_sync='now SIGNAL cont';
+
+--connection con1
+--error ER_QUERY_INTERRUPTED
+--reap
+SET debug_sync='RESET';
+--let $after_error_gtid_pos= `SELECT @@gtid_binlog_pos`
+
+--connection server_1
+SET debug_sync='RESET';
+
+--connection server_2
+--let $slave_sql_errno= 1317
+--source include/wait_for_slave_sql_error.inc
+STOP SLAVE IO_THREAD;
+--replace_result $after_error_gtid_pos AFTER_ERROR_GTID_POS
+eval SET GLOBAL gtid_slave_pos= '$after_error_gtid_pos';
+--source include/start_slave.inc
+
+--connection server_1
+INSERT INTO t6 VALUES (4);
+SELECT * FROM t6 ORDER BY a;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+SELECT * FROM t6 ORDER BY a;
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP TABLE t6;
+SET DEBUG_SYNC= 'RESET';
+--disconnect con1
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_record_gtid_wakeup.inc b/mysql-test/suite/rpl/include/rpl_parallel_record_gtid_wakeup.inc
new file mode 100644
index 00000000000..0f94d8f9943
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_record_gtid_wakeup.inc
@@ -0,0 +1,72 @@
+--echo *** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep';
+
+--connection server_1
+# Inject two group commits. The bug was that record_gtid for a
+# non-transactional event group would commit its own transaction, which would
+# cause ha_commit_trans() to call wakeup_subsequent_commits() too early. This
+# in turn lead to access to freed group_commit_orderer object, losing a wakeup
+# and causing slave threads to hang.
+# We inject a small sleep in the corresponding record_gtid() to make the race
+# easier to hit.
+
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+
+# Group commit with cid=10010, two event groups.
+SET @old_server_id= @@SESSION.server_id;
+SET SESSION server_id= 100;
+SET @commit_id= 10010;
+ALTER TABLE t1 COMMENT "Hulubulu!";
+SET SESSION server_id= @old_server_id;
+INSERT INTO t3 VALUES (130, 0);
+
+# Group commit with cid=10011, one event group.
+SET @commit_id= 10011;
+INSERT INTO t3 VALUES (131, 0);
+
+SET SESSION debug_dbug=@old_dbug;
+
+SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+
+SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
+
+# Clean up.
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t1,t3;
+
+--source include/rpl_end.inc
+
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_retry_deadlock.inc b/mysql-test/suite/rpl/include/rpl_parallel_retry_deadlock.inc
new file mode 100644
index 00000000000..54ac859bb33
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_retry_deadlock.inc
@@ -0,0 +1,281 @@
+--echo *** MDEV-7326 Server deadlock in connection with parallel replication ***
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+--source include/stop_slave.inc
+# Test assumes that 'conservative' mode is in effect. i.e
+# Do not start parallel execution of this event group until all prior groups
+# have reached the commit phase. Refer 'rpl_parallel_start_waiting_for_prior'
+# debug simumation.
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t6 (a INT) ENGINE=MyISAM;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--connection server_1
+# 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_2
+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;
+
+# We use three transactions, each in a separate group commit.
+# T1 does mark_start_commit(), then gets a deadlock error.
+# T2 wakes up and starts running
+# T1 does unmark_start_commit()
+# T3 goes to wait for T2 to start its commit
+# T2 does mark_start_commit()
+# The bug was that at this point, T3 got deadlocked. Because T1 has unmarked(),
+# T3 did not yet see the count_committing_event_groups reach its target value
+# yet. But when T1 later re-did mark_start_commit(), it failed to send a wakeup
+# to T3.
+
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=3;
+SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
+--source include/start_slave.inc
+
+--connection server_1
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+# This debug_sync will linger on and be used to control T3 later.
+INSERT INTO t1 VALUES (foo(50,
+ "rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
+ "rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
+--save_master_pos
+--connection server_2
+# Wait for the debug_sync point for T3 to be set. But let the preparation
+# transaction remain hanging, so that T1 and T2 will be scheduled for the
+# remaining two worker threads.
+SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
+
+--connection server_1
+INSERT INTO t2 VALUES (foo(50,
+ "rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
+ "rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
+--save_master_pos
+
+--connection server_2
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
+# T1 has now done mark_start_commit(). It will later do a rollback and retry.
+
+--connection server_1
+# Use a MyISAM table for T2 and T3, so they do not trigger the
+# rpl_parallel_simulate_temp_err_xid DBUG insertion on XID event.
+INSERT INTO t1 VALUES (foo(51,
+ "rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
+ "rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
+
+--connection server_2
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
+# T2 has now started running, but has not yet done mark_start_commit()
+SET DEBUG_SYNC= "now SIGNAL t1_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
+# T1 has now done unmark_start_commit() in preparation for its retry.
+
+--connection server_1
+INSERT INTO t1 VALUES (52);
+SET BINLOG_FORMAT= @old_format;
+SELECT * FROM t2 WHERE a>=50 ORDER BY a;
+SELECT * FROM t1 WHERE a>=50 ORDER BY a;
+
+--connection server_2
+# Let the preparation transaction complete, so that the same worker thread
+# can continue with the transaction T3.
+SET DEBUG_SYNC= "now SIGNAL prep_cont";
+SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
+# T3 has now gone to wait for T2 to start committing
+SET DEBUG_SYNC= "now SIGNAL t2_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
+# T2 has now done mark_start_commit().
+# Let things run, and check that T3 does not get deadlocked.
+SET DEBUG_SYNC= "now SIGNAL t1_cont2";
+--sync_with_master
+
+--connection server_1
+--save_master_pos
+--connection server_2
+--sync_with_master
+SELECT * FROM t2 WHERE a>=50 ORDER BY a;
+SELECT * FROM t1 WHERE a>=50 ORDER BY a;
+SET DEBUG_SYNC="reset";
+
+# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC.
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+--source include/start_slave.inc
+
+
+--echo *** MDEV-7326 Server deadlock in connection with parallel replication ***
+# Similar to the previous test, but with T2 and T3 in the same GCO.
+# We use three transactions, T1 in one group commit and T2/T3 in another.
+# T1 does mark_start_commit(), then gets a deadlock error.
+# T2 wakes up and starts running
+# T1 does unmark_start_commit()
+# T3 goes to wait for T1 to start its commit
+# T2 does mark_start_commit()
+# The bug was that at this point, T3 got deadlocked. T2 increments the
+# count_committing_event_groups but does not signal T3, as they are in
+# the same GCO. Then later when T1 increments, it would also not signal
+# T3, because now the count_committing_event_groups is not equal to the
+# wait_count of T3 (it is one larger).
+
+--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=3;
+SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
+--source include/start_slave.inc
+
+--connection server_1
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+# This debug_sync will linger on and be used to control T3 later.
+INSERT INTO t1 VALUES (foo(60,
+ "rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
+ "rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
+--save_master_pos
+--connection server_2
+# Wait for the debug_sync point for T3 to be set. But let the preparation
+# transaction remain hanging, so that T1 and T2 will be scheduled for the
+# remaining two worker threads.
+SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
+
+--connection server_1
+INSERT INTO t2 VALUES (foo(60,
+ "rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
+ "rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
+--save_master_pos
+
+--connection server_2
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
+# T1 has now done mark_start_commit(). It will later do a rollback and retry.
+
+# Do T2 and T3 in a single group commit.
+# Use a MyISAM table for T2 and T3, so they do not trigger the
+# rpl_parallel_simulate_temp_err_xid DBUG insertion on XID event.
+--connection con_temp3
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+SET binlog_format=statement;
+send INSERT INTO t1 VALUES (foo(61,
+ "rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
+ "rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con_temp4
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send INSERT INTO t6 VALUES (62);
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con_temp3
+REAP;
+--connection con_temp4
+REAP;
+
+--connection server_1
+SET debug_sync='RESET';
+SET BINLOG_FORMAT= @old_format;
+SELECT * FROM t2 WHERE a>=60 ORDER BY a;
+SELECT * FROM t1 WHERE a>=60 ORDER BY a;
+SELECT * FROM t6 WHERE a>=60 ORDER BY a;
+
+--connection server_2
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
+# T2 has now started running, but has not yet done mark_start_commit()
+SET DEBUG_SYNC= "now SIGNAL t1_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
+# T1 has now done unmark_start_commit() in preparation for its retry.
+
+--connection server_2
+# Let the preparation transaction complete, so that the same worker thread
+# can continue with the transaction T3.
+SET DEBUG_SYNC= "now SIGNAL prep_cont";
+SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
+# T3 has now gone to wait for T2 to start committing
+SET DEBUG_SYNC= "now SIGNAL t2_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
+# T2 has now done mark_start_commit().
+# Let things run, and check that T3 does not get deadlocked.
+SET DEBUG_SYNC= "now SIGNAL t1_cont2";
+--sync_with_master
+
+--connection server_1
+--save_master_pos
+--connection server_2
+--sync_with_master
+SELECT * FROM t2 WHERE a>=60 ORDER BY a;
+SELECT * FROM t1 WHERE a>=60 ORDER BY a;
+SELECT * FROM t6 WHERE a>=60 ORDER BY a;
+SET DEBUG_SYNC="reset";
+
+# Clean up.
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP function foo;
+DROP TABLE t1,t2,t6;
+--disconnect con_temp3
+--disconnect con_temp4
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_rollback_assert.inc b/mysql-test/suite/rpl/include/rpl_parallel_rollback_assert.inc
new file mode 100644
index 00000000000..eec331b3d64
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_rollback_assert.inc
@@ -0,0 +1,62 @@
+--echo *** MDEV-8725: Assertion on ROLLBACK statement in the binary log ***
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--connection server_1
+# Inject an event group terminated by ROLLBACK, by mixing MyISAM and InnoDB
+# in a transaction. The bug was an assertion on the ROLLBACK due to
+# mark_start_commit() being already called.
+--disable_warnings
+BEGIN;
+INSERT INTO t2 VALUES (2000);
+INSERT INTO t1 VALUES (2000);
+INSERT INTO t2 VALUES (2001);
+ROLLBACK;
+--enable_warnings
+SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
+SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/sync_with_master_gtid.inc
+
+--connection server_1
+INSERT INTO t2 VALUES (2020);
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
+let $rows_in_t1= `SELECT COUNT(*) FROM t1 WHERE a>=2000 ORDER BY a`;
+if ($rows_in_t1 == 0)
+{
+--query_vertical SHOW SLAVE STATUS
+}
+SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
+
+# Clean up.
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t1,t2;
+
+--source include/rpl_end.inc
+
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_single_grpcmt.inc b/mysql-test/suite/rpl/include/rpl_parallel_single_grpcmt.inc
new file mode 100644
index 00000000000..cf4c547b73b
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_single_grpcmt.inc
@@ -0,0 +1,170 @@
+--echo *** Test that group-committed transactions on the master can replicate in parallel on the slave. ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+# Test various aspects of parallel replication.
+
+--connection server_1
+# 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_2
+--source include/stop_slave.inc
+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;
+
+# We need to restart all parallel threads for the new global setting to
+# be copied to the session-level values.
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+# Create some sentinel rows so that the rows inserted in parallel fall into
+# separate gaps and do not cause gap lock conflicts.
+INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7);
+--save_master_pos
+--connection server_2
+--sync_with_master
+
+
+# We want to test that the transactions can execute out-of-order on
+# the slave, but still end up committing in-order, and in a single
+# group commit.
+#
+# The idea is to group-commit three transactions together on the master:
+# A, B, and C. On the slave, C will execute the insert first, then A,
+# and then B. But B manages to complete before A has time to commit, so
+# all three end up committing together.
+#
+# So we start by setting up some row locks that will block transactions
+# A and B from executing, allowing C to run first.
+
+--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
+BEGIN;
+INSERT INTO t3 VALUES (2,102);
+--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
+BEGIN;
+INSERT INTO t3 VALUES (4,104);
+
+# On the master, queue three INSERT transactions as a single group commit.
+--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+SET binlog_format=statement;
+send INSERT INTO t3 VALUES (2, foo(12,
+ 'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+ ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+SET binlog_format=statement;
+send INSERT INTO t3 VALUES (4, foo(14,
+ 'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+ ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+
+--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+SET binlog_format=statement;
+send INSERT INTO t3 VALUES (6, foo(16,
+ 'group_commit_waiting_for_prior SIGNAL slave_queued3',
+ ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con_temp3
+REAP;
+--connection con_temp4
+REAP;
+--connection con_temp5
+REAP;
+SET debug_sync='RESET';
+
+--connection server_1
+SELECT * FROM t3 ORDER BY a;
+--let $binlog_file= master-bin.000001
+--source include/show_binlog_events.inc
+
+# First, wait until insert 3 is ready to queue up for group commit, but is
+# waiting for insert 2 to commit before it can do so itself.
+--connection server_2
+SET debug_sync='now WAIT_FOR slave_queued3';
+
+# Next, let insert 1 proceed, and allow it to queue up as the group commit
+# leader, but let it wait for insert 2 to also queue up before proceeding.
+--connection con_temp1
+ROLLBACK;
+--connection server_2
+SET debug_sync='now WAIT_FOR slave_queued1';
+
+# Now let insert 2 proceed and queue up.
+--connection con_temp2
+ROLLBACK;
+--connection server_2
+SET debug_sync='now WAIT_FOR slave_queued2';
+# And finally, we can let insert 1 proceed and do the group commit with all
+# three insert transactions together.
+SET debug_sync='now SIGNAL slave_cont1';
+
+# Wait for the commit to complete and check that all three transactions
+# group-committed together (will be seen in the binlog as all three having
+# cid=# on their GTID event).
+--let $wait_condition= SELECT COUNT(*) = 3 FROM t3 WHERE a IN (2,4,6)
+--source include/wait_condition.inc
+SELECT * FROM t3 ORDER BY a;
+--let $binlog_file= slave-bin.000001
+--source include/show_binlog_events.inc
+
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP function foo;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+
+--disable_connect_log
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_slave_bgc_kill.inc b/mysql-test/suite/rpl/include/rpl_parallel_slave_bgc_kill.inc
new file mode 100644
index 00000000000..a78dbad052f
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_slave_bgc_kill.inc
@@ -0,0 +1,454 @@
+--echo *** Test killing slave threads at various wait points ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+# Test various aspects of parallel replication.
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--connection server_1
+# 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_2
+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;
+
+--echo *** 1. Test killing transaction waiting in commit for previous transaction to commit ***
+
+# Set up three transactions on the master that will be group-committed
+# together so they can be replicated in parallel on the slave.
+--connection con_temp3
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send INSERT INTO t3 VALUES (31, foo(31,
+ 'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+ 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con_temp4
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+# This insert is just so we can get T2 to wait while a query is running that we
+# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
+INSERT INTO t3 VALUES (32, foo(32,
+ 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+ ''));
+# This insert sets up debug_sync points so that T2 will tell when it is at its
+# wait point where we want to kill it - and when it has been killed.
+INSERT INTO t3 VALUES (33, foo(33,
+ 'group_commit_waiting_for_prior SIGNAL t2_waiting',
+ 'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+send COMMIT;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+
+--connection con_temp5
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+send INSERT INTO t3 VALUES (34, foo(34,
+ '',
+ ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con_temp3
+REAP;
+--connection con_temp4
+REAP;
+--connection con_temp5
+REAP;
+
+--connection server_1
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+SET debug_sync='RESET';
+
+--connection server_2
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Query execution was interrupted");
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+CALL mtr.add_suppression("Slave: Connection was killed");
+SET sql_log_bin=1;
+# Wait until T2 is inside executing its insert of 32, then find it in SHOW
+# PROCESSLIST to know its thread id for KILL later.
+SET debug_sync='now WAIT_FOR t2_query';
+--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(32%' AND INFO NOT LIKE '%LIKE%'`
+SET debug_sync='now SIGNAL t2_cont';
+
+# Wait until T2 has entered its wait for T1 to commit, and T1 has
+# progressed into its commit phase.
+SET debug_sync='now WAIT_FOR t1_ready';
+
+# Now kill the transaction T2.
+--replace_result $thd_id THD_ID
+eval KILL $thd_id;
+
+# Wait until T2 has reacted on the kill.
+SET debug_sync='now WAIT_FOR t2_killed';
+
+# Now we can allow T1 to proceed.
+SET debug_sync='now SIGNAL t1_cont';
+
+--let $slave_sql_errno= 1317,1927,1964
+--source include/wait_for_slave_sql_error.inc
+STOP SLAVE IO_THREAD;
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+
+# Now we have to disable the debug_sync statements, so they do not trigger
+# when the events are retried.
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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_1
+INSERT INTO t3 VALUES (39,0);
+--save_master_pos
+
+--connection server_2
+--source include/start_slave.inc
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+# Restore the foo() function.
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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;
+
+
+--connection server_2
+# Respawn all worker threads to clear any left-over debug_sync or other stuff.
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+--source include/start_slave.inc
+
+
+--echo *** 2. Same as (1), but without restarting IO thread after kill of SQL threads ***
+
+# Set up three transactions on the master that will be group-committed
+# together so they can be replicated in parallel on the slave.
+--connection con_temp3
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send INSERT INTO t3 VALUES (41, foo(41,
+ 'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+ 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con_temp4
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+# This insert is just so we can get T2 to wait while a query is running that we
+# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
+INSERT INTO t3 VALUES (42, foo(42,
+ 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+ ''));
+# This insert sets up debug_sync points so that T2 will tell when it is at its
+# wait point where we want to kill it - and when it has been killed.
+INSERT INTO t3 VALUES (43, foo(43,
+ 'group_commit_waiting_for_prior SIGNAL t2_waiting',
+ 'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+send COMMIT;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+
+--connection con_temp5
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+send INSERT INTO t3 VALUES (44, foo(44,
+ '',
+ ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con_temp3
+REAP;
+--connection con_temp4
+REAP;
+--connection con_temp5
+REAP;
+
+--connection server_1
+SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
+SET debug_sync='RESET';
+
+--connection server_2
+# Wait until T2 is inside executing its insert of 42, then find it in SHOW
+# PROCESSLIST to know its thread id for KILL later.
+SET debug_sync='now WAIT_FOR t2_query';
+--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(42%' AND INFO NOT LIKE '%LIKE%'`
+SET debug_sync='now SIGNAL t2_cont';
+
+# Wait until T2 has entered its wait for T1 to commit, and T1 has
+# progressed into its commit phase.
+SET debug_sync='now WAIT_FOR t1_ready';
+
+# Now kill the transaction T2.
+--replace_result $thd_id THD_ID
+eval KILL $thd_id;
+
+# Wait until T2 has reacted on the kill.
+SET debug_sync='now WAIT_FOR t2_killed';
+
+# Now we can allow T1 to proceed.
+SET debug_sync='now SIGNAL t1_cont';
+
+--let $slave_sql_errno= 1317,1927,1964
+--source include/wait_for_slave_sql_error.inc
+
+# Now we have to disable the debug_sync statements, so they do not trigger
+# when the events are retried.
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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_1
+INSERT INTO t3 VALUES (49,0);
+--save_master_pos
+
+--connection server_2
+START SLAVE SQL_THREAD;
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
+# Restore the foo() function.
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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;
+
+
+--connection server_2
+# Respawn all worker threads to clear any left-over debug_sync or other stuff.
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+--source include/start_slave.inc
+
+
+--echo *** 3. Same as (2), but not using gtid mode ***
+
+--connection server_2
+--source include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=no;
+--source include/start_slave.inc
+
+--connection server_1
+# Set up three transactions on the master that will be group-committed
+# together so they can be replicated in parallel on the slave.
+--connection con_temp3
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send INSERT INTO t3 VALUES (51, foo(51,
+ 'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+ 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con_temp4
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+# This insert is just so we can get T2 to wait while a query is running that we
+# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
+INSERT INTO t3 VALUES (52, foo(52,
+ 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+ ''));
+# This insert sets up debug_sync points so that T2 will tell when it is at its
+# wait point where we want to kill it - and when it has been killed.
+INSERT INTO t3 VALUES (53, foo(53,
+ 'group_commit_waiting_for_prior SIGNAL t2_waiting',
+ 'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+send COMMIT;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+
+--connection con_temp5
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+send INSERT INTO t3 VALUES (54, foo(54,
+ '',
+ ''));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con_temp3
+REAP;
+--connection con_temp4
+REAP;
+--connection con_temp5
+REAP;
+
+--connection server_1
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+SET debug_sync='RESET';
+
+--connection server_2
+# Wait until T2 is inside executing its insert of 52, then find it in SHOW
+# PROCESSLIST to know its thread id for KILL later.
+SET debug_sync='now WAIT_FOR t2_query';
+--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(52%' AND INFO NOT LIKE '%LIKE%'`
+SET debug_sync='now SIGNAL t2_cont';
+
+# Wait until T2 has entered its wait for T1 to commit, and T1 has
+# progressed into its commit phase.
+SET debug_sync='now WAIT_FOR t1_ready';
+
+# Now kill the transaction T2.
+--replace_result $thd_id THD_ID
+eval KILL $thd_id;
+
+# Wait until T2 has reacted on the kill.
+SET debug_sync='now WAIT_FOR t2_killed';
+
+# Now we can allow T1 to proceed.
+SET debug_sync='now SIGNAL t1_cont';
+
+--let $slave_sql_errno= 1317,1927,1964
+--source include/wait_for_slave_sql_error.inc
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+
+# Now we have to disable the debug_sync statements, so they do not trigger
+# when the events are retried.
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+--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_1
+INSERT INTO t3 VALUES (59,0);
+--save_master_pos
+
+--connection server_2
+START SLAVE SQL_THREAD;
+--sync_with_master
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP function foo;
+DROP TABLE t1,t2,t3;
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_stop_on_con_kill.inc b/mysql-test/suite/rpl/include/rpl_parallel_stop_on_con_kill.inc
new file mode 100644
index 00000000000..63c483ea6ad
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_stop_on_con_kill.inc
@@ -0,0 +1,129 @@
+--echo *** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (201,0), (202,0);
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/sync_with_master_gtid.inc
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_mdev8031';
+
+--connection server_1
+# We artificially create a situation that hopefully resembles the original
+# bug which was only seen "in the wild", and only once.
+# Setup a fake group commit with lots of conflicts that will lead to deadloc
+# kill. The slave DBUG injection causes the slave to be deadlock killed at
+# a particular point during the retry, and then later do a small sleep at
+# another critical point where the prior transaction then has a chance to
+# complete. Finally an extra KILL check catches an unhandled, lingering
+# deadlock kill. So rather artificial, but at least it exercises the
+# relevant code paths.
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+
+SET @commit_id= 10200;
+INSERT INTO t3 VALUES (203, 1);
+INSERT INTO t3 VALUES (204, 1);
+INSERT INTO t3 VALUES (205, 1);
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=205;
+UPDATE t3 SET b=b+1 WHERE a=205;
+SET SESSION debug_dbug=@old_dbug;
+
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+--source include/start_slave.inc
+
+
+--echo *** Check getting deadlock killed inside open_binlog() during retry. ***
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill';
+SET @old_max= @@GLOBAL.max_relay_log_size;
+SET GLOBAL max_relay_log_size= 4096;
+
+--connection server_1
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+
+--let $large= `SELECT REPEAT("*", 8192)`
+SET @commit_id= 10210;
+--echo Omit long queries that cause relaylog rotations and transaction retries...
+--disable_query_log
+eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=205 /* $large */;
+eval UPDATE t3 SET b=b+1 WHERE a=205 /* $large */;
+--enable_query_log
+SET SESSION debug_dbug=@old_dbug;
+
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+
+# Cleanup
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_debg;
+SET GLOBAL max_relay_log_size= @old_max;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t3;
+
+--source include/rpl_end.inc
+
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_stop_slave.inc b/mysql-test/suite/rpl/include/rpl_parallel_stop_slave.inc
new file mode 100644
index 00000000000..4eeddc927e0
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_stop_slave.inc
@@ -0,0 +1,114 @@
+--echo *** Test STOP SLAVE in parallel mode ***
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
+--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--source include/stop_slave.inc
+
+--connection server_1
+# Set up a couple of transactions. The first will be blocked halfway
+# through on a lock, and while it is blocked we initiate STOP SLAVE.
+# We then test that the halfway-initiated transaction is allowed to
+# complete, but no subsequent ones.
+# We have to use statement-based mode and set
+# binlog_direct_non_transactional_updates=0; otherwise the binlog will
+# be split into two event groups, one for the MyISAM part and one for the
+# InnoDB part.
+SET binlog_direct_non_transactional_updates=0;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction");
+SET sql_log_bin=1;
+BEGIN;
+INSERT INTO t2 VALUES (20);
+--disable_warnings
+INSERT INTO t1 VALUES (20);
+--enable_warnings
+INSERT INTO t2 VALUES (21);
+INSERT INTO t3 VALUES (20, 20);
+COMMIT;
+INSERT INTO t3 VALUES(21, 21);
+INSERT INTO t3 VALUES(22, 22);
+--save_master_pos
+
+# Start a connection that will block the replicated transaction halfway.
+--connection con_temp1
+BEGIN;
+INSERT INTO t2 VALUES (21);
+
+--connection server_2
+START SLAVE;
+# Wait for the MyISAM change to be visible, after which replication will wait
+# for con_temp1 to roll back.
+--let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE a=20
+--source include/wait_condition.inc
+
+--connection con_temp2
+# Initiate slave stop. It will have to wait for the current event group
+# to complete.
+# The dbug injection causes debug_sync to signal 'wait_for_done_waiting'
+# when the SQL driver thread is ready.
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
+send STOP SLAVE;
+
+--connection con_temp1
+SET debug_sync='now WAIT_FOR wait_for_done_waiting';
+ROLLBACK;
+
+--connection con_temp2
+reap;
+SET GLOBAL debug_dbug=@old_dbug;
+SET debug_sync='RESET';
+
+--connection server_2
+--source include/wait_for_slave_to_stop.inc
+# We should see the first transaction applied, but not the two others.
+SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
+SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
+SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
+
+--source include/start_slave.inc
+--sync_with_master
+SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
+SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
+SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
+
+--connection server_2
+# Respawn all worker threads to clear any left-over debug_sync or other stuff.
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+--disconnect con_temp1
+--disconnect con_temp2
+
+--connection server_1
+DROP TABLE t1,t2,t3;
+SET DEBUG_SYNC= 'RESET';
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_wrong_binlog_order.inc b/mysql-test/suite/rpl/include/rpl_parallel_wrong_binlog_order.inc
new file mode 100644
index 00000000000..093693d453e
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_wrong_binlog_order.inc
@@ -0,0 +1,91 @@
+--echo *** MDEV-6775: Wrong binlog order in parallel replication ***
+
+# A bit tricky bug to reproduce. On the master, we binlog in statement-mode
+# two transactions, an UPDATE followed by a DELETE. On the slave, we replicate
+# with binlog-mode set to ROW, which means the DELETE, which modifies no rows,
+# is not binlogged. Then we inject a wait in the group commit code on the
+# slave, shortly before the actual commit of the UPDATE. The bug was that the
+# DELETE could wake up from wait_for_prior_commit() before the commit of the
+# UPDATE. So the test could see the slave position updated to after DELETE,
+# while the UPDATE was still not visible.
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/master-slave.inc
+
+--connection server_2
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6);
+--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
+--source include/save_master_gtid.inc
+
+--connection server_2
+--source include/sync_with_master_gtid.inc
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log";
+SET @old_format=@@GLOBAL.binlog_format;
+SET GLOBAL binlog_format=ROW;
+# Re-spawn the worker threads to be sure they pick up the new binlog format
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+
+--connection con1
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send UPDATE t4 SET b=NULL WHERE a=6;
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con2
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send DELETE FROM t4 WHERE b <= 3;
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con1
+REAP;
+SET binlog_format= @old_format;
+--connection con2
+REAP;
+SET binlog_format= @old_format;
+SET debug_sync='RESET';
+--save_master_pos
+SELECT * FROM t4 ORDER BY a;
+
+--connection server_2
+--source include/start_slave.inc
+SET debug_sync= 'now WAIT_FOR waiting';
+--sync_with_master
+SELECT * FROM t4 ORDER BY a;
+SET debug_sync= 'now SIGNAL cont';
+
+# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC.
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL binlog_format= @old_format;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+
+--connection server_1
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+--disconnect con1
+--disconnect con2
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/include/rpl_parallel_wrong_exec_master_pos.inc b/mysql-test/suite/rpl/include/rpl_parallel_wrong_exec_master_pos.inc
new file mode 100644
index 00000000000..672ade57ca3
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_parallel_wrong_exec_master_pos.inc
@@ -0,0 +1,56 @@
+--echo *** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t5 (a INT PRIMARY KEY, b INT);
+INSERT INTO t5 VALUES (1,1);
+INSERT INTO t5 VALUES (2,2), (3,8);
+INSERT INTO t5 VALUES (4,16);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+let $io_file= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1);
+let $io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1);
+let $sql_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1);
+let $sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+--disable_query_log
+eval SELECT IF('$io_file' = '$sql_file', "OK", "Not ok, $io_file <> $sql_file") AS test_check;
+eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS test_check;
+--enable_query_log
+
+--connection server_1
+FLUSH LOGS;
+--source include/wait_for_binlog_checkpoint.inc
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+let $io_file= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1);
+let $io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1);
+let $sql_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1);
+let $sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+--disable_query_log
+eval SELECT IF('$io_file' = '$sql_file', "OK", "Not ok, $io_file <> $sql_file") AS test_check;
+eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS test_check;
+--enable_query_log
+
+# Clean up.
+--connection server_2
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t5;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_delayed_slave.result b/mysql-test/suite/rpl/r/rpl_delayed_slave.result
index bcfd49934b4..e7daa3328ce 100644
--- a/mysql-test/suite/rpl/r/rpl_delayed_slave.result
+++ b/mysql-test/suite/rpl/r/rpl_delayed_slave.result
@@ -185,7 +185,7 @@ DROP FUNCTION delay_on_slave;
connection slave;
SELECT @@GLOBAL.slave_parallel_mode;
@@GLOBAL.slave_parallel_mode
-conservative
+optimistic
SELECT @@GLOBAL.slave_parallel_threads;
@@GLOBAL.slave_parallel_threads
0
diff --git a/mysql-test/suite/rpl/r/rpl_mdev6386.result b/mysql-test/suite/rpl/r/rpl_mdev6386.result
index 91ba9569343..d0e5144857a 100644
--- a/mysql-test/suite/rpl/r/rpl_mdev6386.result
+++ b/mysql-test/suite/rpl/r/rpl_mdev6386.result
@@ -7,6 +7,7 @@ connection slave;
connection slave;
include/stop_slave.inc
SET sql_log_bin= 0;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
INSERT INTO t1 VALUES (1, 2);
SET sql_log_bin= 1;
CHANGE MASTER TO master_use_gtid= current_pos;
diff --git a/mysql-test/suite/rpl/r/rpl_parallel.result b/mysql-test/suite/rpl/r/rpl_parallel.result
deleted file mode 100644
index 9258deadaca..00000000000
--- a/mysql-test/suite/rpl/r/rpl_parallel.result
+++ /dev/null
@@ -1,1690 +0,0 @@
-include/master-slave.inc
-[connection master]
-connection server_2;
-SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
-SET GLOBAL slave_parallel_threads=10;
-ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=10;
-SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
-OK
-CHANGE MASTER TO master_use_gtid=slave_pos;
-include/start_slave.inc
-SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
-OK
-include/stop_slave.inc
-SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
-OK
-include/start_slave.inc
-SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
-IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
-OK
-*** Test long-running query in domain 1 can run in parallel with short queries in domain 0 ***
-connection server_1;
-ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
-CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
-CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (1);
-INSERT INTO t2 VALUES (1);
-connection server_2;
-connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
-LOCK TABLE t1 WRITE;
-connection server_1;
-SET gtid_domain_id=1;
-INSERT INTO t1 VALUES (2);
-SET gtid_domain_id=0;
-INSERT INTO t2 VALUES (2);
-INSERT INTO t2 VALUES (3);
-BEGIN;
-INSERT INTO t2 VALUES (4);
-INSERT INTO t2 VALUES (5);
-COMMIT;
-INSERT INTO t2 VALUES (6);
-connection server_2;
-SELECT * FROM t2 ORDER by a;
-a
-1
-2
-3
-4
-5
-6
-connection con_temp1;
-SELECT * FROM t1;
-a
-1
-UNLOCK TABLES;
-connection server_2;
-SELECT * FROM t1 ORDER BY a;
-a
-1
-2
-*** Test two transactions in different domains committed in opposite order on slave but in a single group commit. ***
-connection server_2;
-include/stop_slave.inc
-connection server_1;
-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;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format='statement';
-SET gtid_domain_id=1;
-INSERT INTO t2 VALUES (foo(10,
-'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'));
-connection server_2;
-FLUSH LOGS;
-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;
-SET @old_format=@@GLOBAL.binlog_format;
-SET GLOBAL binlog_format=statement;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-SET debug_sync='now WAIT_FOR ready1';
-connection server_1;
-SET gtid_domain_id=2;
-INSERT INTO t2 VALUES (foo(11,
-'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'));
-SET gtid_domain_id=0;
-SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
-a
-10
-11
-connection server_2;
-SET debug_sync='now WAIT_FOR ready3';
-SET debug_sync='now SIGNAL cont3';
-SET debug_sync='now WAIT_FOR ready4';
-SET debug_sync='now SIGNAL cont1';
-SET debug_sync='now WAIT_FOR ready2';
-SET debug_sync='now SIGNAL cont4';
-SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
-a
-10
-11
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002
-slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(11,
-'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'))
-slave-bin.000002 # Xid # # COMMIT /* XID */
-slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(10,
-'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
-'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'))
-slave-bin.000002 # Xid # # COMMIT /* XID */
-FLUSH LOGS;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET debug_sync='RESET';
-include/start_slave.inc
-*** Test that group-committed transactions on the master can replicate in parallel on the slave. ***
-connection server_1;
-SET debug_sync='RESET';
-FLUSH LOGS;
-CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
-INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7);
-connection server_2;
-connection con_temp1;
-BEGIN;
-INSERT INTO t3 VALUES (2,102);
-connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
-BEGIN;
-INSERT INTO t3 VALUES (4,104);
-connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (2, foo(12,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (4, foo(14,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (6, foo(16,
-'group_commit_waiting_for_prior SIGNAL slave_queued3',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-SET debug_sync='RESET';
-connection server_1;
-SELECT * FROM t3 ORDER BY a;
-a b
-1 1
-2 12
-3 3
-4 14
-5 5
-6 16
-7 7
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000002 # Binlog_checkpoint # # master-bin.000002
-master-bin.000002 # Gtid # # GTID #-#-#
-master-bin.000002 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
-master-bin.000002 # Gtid # # BEGIN GTID #-#-#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
-master-bin.000002 # Xid # # COMMIT /* XID */
-master-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
-''))
-master-bin.000002 # Xid # # COMMIT /* XID */
-master-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
-''))
-master-bin.000002 # Xid # # COMMIT /* XID */
-master-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
-master-bin.000002 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
-'group_commit_waiting_for_prior SIGNAL slave_queued3',
-''))
-master-bin.000002 # Xid # # COMMIT /* XID */
-connection server_2;
-SET debug_sync='now WAIT_FOR slave_queued3';
-connection con_temp1;
-ROLLBACK;
-connection server_2;
-SET debug_sync='now WAIT_FOR slave_queued1';
-connection con_temp2;
-ROLLBACK;
-connection server_2;
-SET debug_sync='now WAIT_FOR slave_queued2';
-SET debug_sync='now SIGNAL slave_cont1';
-SELECT * FROM t3 ORDER BY a;
-a b
-1 1
-2 12
-3 3
-4 14
-5 5
-6 16
-7 7
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-slave-bin.000003 # Binlog_checkpoint # # slave-bin.000003
-slave-bin.000003 # Gtid # # GTID #-#-#
-slave-bin.000003 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
-slave-bin.000003 # Xid # # COMMIT /* XID */
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
-''))
-slave-bin.000003 # Xid # # COMMIT /* XID */
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
-'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
-''))
-slave-bin.000003 # Xid # # COMMIT /* XID */
-slave-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
-slave-bin.000003 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
-'group_commit_waiting_for_prior SIGNAL slave_queued3',
-''))
-slave-bin.000003 # Xid # # COMMIT /* XID */
-*** Test STOP SLAVE in parallel mode ***
-connection server_2;
-include/stop_slave.inc
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-connection server_1;
-SET binlog_direct_non_transactional_updates=0;
-SET sql_log_bin=0;
-CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction");
-SET sql_log_bin=1;
-BEGIN;
-INSERT INTO t2 VALUES (20);
-INSERT INTO t1 VALUES (20);
-INSERT INTO t2 VALUES (21);
-INSERT INTO t3 VALUES (20, 20);
-COMMIT;
-INSERT INTO t3 VALUES(21, 21);
-INSERT INTO t3 VALUES(22, 22);
-SET binlog_format=@old_format;
-connection con_temp1;
-BEGIN;
-INSERT INTO t2 VALUES (21);
-connection server_2;
-START SLAVE;
-connection con_temp2;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
-STOP SLAVE;
-connection con_temp1;
-SET debug_sync='now WAIT_FOR wait_for_done_waiting';
-ROLLBACK;
-connection con_temp2;
-SET GLOBAL debug_dbug=@old_dbug;
-SET debug_sync='RESET';
-connection server_2;
-include/wait_for_slave_to_stop.inc
-SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
-a
-20
-SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
-a
-20
-21
-SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
-a b
-20 20
-include/start_slave.inc
-SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
-a
-20
-SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
-a
-20
-21
-SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
-a b
-20 20
-21 21
-22 22
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** Test killing slave threads at various wait points ***
-*** 1. Test killing transaction waiting in commit for previous transaction to commit ***
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (31, foo(31,
-'commit_before_prepare_ordered WAIT_FOR t2_waiting',
-'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-INSERT INTO t3 VALUES (32, foo(32,
-'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
-''));
-INSERT INTO t3 VALUES (33, foo(33,
-'group_commit_waiting_for_prior SIGNAL t2_waiting',
-'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-COMMIT;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (34, foo(34,
-'',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-a b
-31 31
-32 32
-33 33
-34 34
-SET debug_sync='RESET';
-connection server_2;
-SET sql_log_bin=0;
-CALL mtr.add_suppression("Query execution was interrupted");
-CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
-CALL mtr.add_suppression("Slave: Connection was killed");
-SET sql_log_bin=1;
-SET debug_sync='now WAIT_FOR t2_query';
-SET debug_sync='now SIGNAL t2_cont';
-SET debug_sync='now WAIT_FOR t1_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t2_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-STOP SLAVE IO_THREAD;
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-a b
-31 31
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-INSERT INTO t3 VALUES (39,0);
-connection server_2;
-include/start_slave.inc
-SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
-a b
-31 31
-32 32
-33 33
-34 34
-39 0
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** 2. Same as (1), but without restarting IO thread after kill of SQL threads ***
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (41, foo(41,
-'commit_before_prepare_ordered WAIT_FOR t2_waiting',
-'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-INSERT INTO t3 VALUES (42, foo(42,
-'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
-''));
-INSERT INTO t3 VALUES (43, foo(43,
-'group_commit_waiting_for_prior SIGNAL t2_waiting',
-'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-COMMIT;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (44, foo(44,
-'',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
-a b
-41 41
-42 42
-43 43
-44 44
-SET debug_sync='RESET';
-connection server_2;
-SET debug_sync='now WAIT_FOR t2_query';
-SET debug_sync='now SIGNAL t2_cont';
-SET debug_sync='now WAIT_FOR t1_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t2_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-INSERT INTO t3 VALUES (49,0);
-connection server_2;
-START SLAVE SQL_THREAD;
-SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
-a b
-41 41
-42 42
-43 43
-44 44
-49 0
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** 3. Same as (2), but not using gtid mode ***
-connection server_2;
-include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=no;
-include/start_slave.inc
-connection server_1;
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (51, foo(51,
-'commit_before_prepare_ordered WAIT_FOR t2_waiting',
-'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-SET binlog_format=statement;
-BEGIN;
-INSERT INTO t3 VALUES (52, foo(52,
-'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
-''));
-INSERT INTO t3 VALUES (53, foo(53,
-'group_commit_waiting_for_prior SIGNAL t2_waiting',
-'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
-COMMIT;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (54, foo(54,
-'',
-''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-a b
-51 51
-52 52
-53 53
-54 54
-SET debug_sync='RESET';
-connection server_2;
-SET debug_sync='now WAIT_FOR t2_query';
-SET debug_sync='now SIGNAL t2_cont';
-SET debug_sync='now WAIT_FOR t1_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t2_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-a b
-51 51
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-INSERT INTO t3 VALUES (59,0);
-connection server_2;
-START SLAVE SQL_THREAD;
-SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
-a b
-51 51
-52 52
-53 53
-54 54
-59 0
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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
-CHANGE MASTER TO master_use_gtid=slave_pos;
-include/start_slave.inc
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=4;
-include/start_slave.inc
-*** 4. Test killing thread that is waiting to start transaction until previous transaction commits ***
-connection server_1;
-SET binlog_format=statement;
-SET gtid_domain_id=2;
-BEGIN;
-INSERT INTO t3 VALUES (70, foo(70,
-'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', ''));
-INSERT INTO t3 VALUES (60, foo(60,
-'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2',
-'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-connection server_2;
-SET debug_sync='now WAIT_FOR d2_query';
-connection server_1;
-SET gtid_domain_id=1;
-BEGIN;
-INSERT INTO t3 VALUES (61, foo(61,
-'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting',
-'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed'));
-INSERT INTO t3 VALUES (62, foo(62,
-'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2',
-'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-connection server_2;
-SET debug_sync='now WAIT_FOR d1_query';
-connection server_1;
-SET gtid_domain_id=0;
-INSERT INTO t3 VALUES (63, foo(63,
-'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2',
-'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont'));
-connection server_2;
-SET debug_sync='now WAIT_FOR d0_query';
-connection server_1;
-SET gtid_domain_id=3;
-BEGIN;
-INSERT INTO t3 VALUES (68, foo(68,
-'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', ''));
-INSERT INTO t3 VALUES (69, foo(69,
-'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2',
-'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont'));
-COMMIT;
-SET gtid_domain_id=0;
-connection server_2;
-SET debug_sync='now WAIT_FOR d3_query';
-SET debug_sync='now SIGNAL d2_cont2';
-SET debug_sync='now WAIT_FOR d2_done';
-SET debug_sync='now SIGNAL d1_cont2';
-SET debug_sync='now WAIT_FOR d1_done';
-SET debug_sync='now SIGNAL d0_cont2';
-SET debug_sync='now WAIT_FOR d0_done';
-SET debug_sync='now SIGNAL d3_cont2';
-SET debug_sync='now WAIT_FOR d3_done';
-connection con_temp3;
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (64, foo(64,
-'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', ''));
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2';
-INSERT INTO t3 VALUES (65, foo(65, '', ''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
-INSERT INTO t3 VALUES (66, foo(66, '', ''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued3';
-connection con_temp5;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4';
-INSERT INTO t3 VALUES (67, foo(67, '', ''));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued4';
-SET debug_sync='now SIGNAL master_cont2';
-connection con_temp3;
-connection con_temp4;
-connection con_temp5;
-connection server_1;
-SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
-a b
-60 60
-61 61
-62 62
-63 63
-64 64
-65 65
-66 66
-67 67
-68 68
-69 69
-70 70
-SET debug_sync='RESET';
-connection server_2;
-SET debug_sync='now SIGNAL d0_cont';
-SET debug_sync='now WAIT_FOR t1_waiting';
-SET debug_sync='now SIGNAL d3_cont';
-SET debug_sync='now WAIT_FOR t2_waiting';
-SET debug_sync='now SIGNAL d1_cont';
-SET debug_sync='now WAIT_FOR t3_waiting';
-SET debug_sync='now SIGNAL d2_cont';
-SET debug_sync='now WAIT_FOR t4_waiting';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR t3_killed';
-SET debug_sync='now SIGNAL t1_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-STOP SLAVE IO_THREAD;
-SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a;
-a b
-60 60
-61 61
-62 62
-63 63
-64 64
-68 68
-69 69
-70 70
-SET debug_sync='RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
-RETURNS INT DETERMINISTIC
-BEGIN
-RETURN x;
-END
-||
-SET sql_log_bin=1;
-connection server_1;
-UPDATE t3 SET b=b+1 WHERE a=60;
-connection server_2;
-include/start_slave.inc
-SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
-a b
-60 61
-61 61
-62 62
-63 63
-64 64
-65 65
-66 66
-67 67
-68 68
-69 69
-70 70
-SET sql_log_bin=0;
-DROP FUNCTION foo;
-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;
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** 5. Test killing thread that is waiting for queue of max length to shorten ***
-SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued;
-SET GLOBAL slave_parallel_max_queued=9000;
-connection server_1;
-SET binlog_format=statement;
-INSERT INTO t3 VALUES (80, foo(0,
-'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', ''));
-connection server_2;
-SET debug_sync='now WAIT_FOR query_waiting';
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max";
-connection server_1;
-SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
-a b
-80 0
-81 10000
-connection server_2;
-SET debug_sync='now WAIT_FOR wait_queue_ready';
-KILL THD_ID;
-SET debug_sync='now WAIT_FOR wait_queue_killed';
-SET debug_sync='now SIGNAL query_cont';
-include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
-STOP SLAVE IO_THREAD;
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_max_queued= @old_max_queued;
-connection server_1;
-INSERT INTO t3 VALUES (82,0);
-SET binlog_format=@old_format;
-connection server_2;
-SET debug_sync='RESET';
-include/start_slave.inc
-SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
-a b
-80 0
-81 10000
-82 0
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL binlog_format=@old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL replicate_ignore_table="test.t3";
-SET GLOBAL slave_parallel_threads=2;
-include/start_slave.inc
-connection server_1;
-INSERT INTO t3 VALUES (100, rand());
-INSERT INTO t3 VALUES (101, rand());
-connection server_2;
-connection server_1;
-INSERT INTO t3 VALUES (102, rand());
-INSERT INTO t3 VALUES (103, rand());
-INSERT INTO t3 VALUES (104, rand());
-INSERT INTO t3 VALUES (105, rand());
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL replicate_ignore_table="";
-include/start_slave.inc
-connection server_1;
-INSERT INTO t3 VALUES (106, rand());
-INSERT INTO t3 VALUES (107, rand());
-connection server_2;
-SELECT * FROM t3 WHERE a >= 100 ORDER BY a;
-a b
-106 #
-107 #
-*** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-connection server_1;
-INSERT INTO t3 VALUES (110, 1);
-connection server_2;
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-a b
-110 1
-SET sql_log_bin=0;
-INSERT INTO t3 VALUES (111, 666);
-SET sql_log_bin=1;
-connection server_1;
-connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-INSERT INTO t3 VALUES (111, 2);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-INSERT INTO t3 VALUES (112, 3);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET debug_sync='RESET';
-connection server_2;
-include/wait_for_slave_sql_error.inc [errno=1062]
-include/wait_for_slave_sql_to_stop.inc
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-a b
-110 1
-111 666
-SET sql_log_bin=0;
-DELETE FROM t3 WHERE a=111 AND b=666;
-SET sql_log_bin=1;
-START SLAVE SQL_THREAD;
-SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
-a b
-110 1
-111 2
-112 3
-***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts ***
-connection server_2;
-include/stop_slave.inc
-connection server_1;
-CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-connection con1;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-UPDATE t4 SET b=NULL WHERE a=6;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 3;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET debug_sync='RESET';
-connection server_2;
-include/start_slave.inc
-include/stop_slave.inc
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 NULL
-connection server_1;
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-connection con1;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-INSERT INTO t4 VALUES (7, NULL);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 3;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET debug_sync='RESET';
-connection server_2;
-include/start_slave.inc
-include/stop_slave.inc
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 6
-7 NULL
-connection server_1;
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
-connection con1;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-UPDATE t4 SET b=NULL WHERE a=6;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format='statement';
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 1;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-connection con2;
-SET @old_format=@@GLOBAL.binlog_format;
-SET debug_sync='RESET';
-connection server_2;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
-include/start_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-2 2
-3 NULL
-4 4
-5 NULL
-6 NULL
-SET @last_gtid= 'GTID';
-SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
-CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
-AS result;
-result
-GTID found ok
-SELECT "ROW FOUND" AS `Is the row found?`
- FROM mysql.gtid_slave_pos
-WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
-Is the row found?
-ROW FOUND
-*** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=1;
-SET DEBUG_SYNC= 'RESET';
-include/start_slave.inc
-connection server_1;
-CREATE TABLE t5 (a INT PRIMARY KEY, b INT);
-INSERT INTO t5 VALUES (1,1);
-INSERT INTO t5 VALUES (2,2), (3,8);
-INSERT INTO t5 VALUES (4,16);
-connection server_2;
-test_check
-OK
-test_check
-OK
-connection server_1;
-FLUSH LOGS;
-connection server_2;
-test_check
-OK
-test_check
-OK
-*** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error ***
-connection server_1;
-CREATE TABLE t6 (a INT) ENGINE=MyISAM;
-CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1;
-connection con1;
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont';
-INSERT INTO t6 VALUES (1), (2), (3);
-connection server_1;
-SET debug_sync='now WAIT_FOR ready';
-KILL QUERY CONID;
-SET debug_sync='now SIGNAL cont';
-connection con1;
-ERROR 70100: Query execution was interrupted
-SET binlog_format= @old_format;
-SET debug_sync='RESET';
-connection server_1;
-SET debug_sync='RESET';
-connection server_2;
-include/wait_for_slave_sql_error.inc [errno=1317]
-STOP SLAVE IO_THREAD;
-SET GLOBAL gtid_slave_pos= 'AFTER_ERROR_GTID_POS';
-include/start_slave.inc
-connection server_1;
-INSERT INTO t6 VALUES (4);
-SELECT * FROM t6 ORDER BY a;
-a
-1
-4
-connection server_2;
-SELECT * FROM t6 ORDER BY a;
-a
-4
-*** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 ***
-connection server_1;
-INSERT INTO t2 VALUES (31);
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads= 0;
-include/start_slave.inc
-SET sql_log_bin= 0;
-INSERT INTO t2 VALUES (32);
-SET sql_log_bin= 1;
-connection server_1;
-INSERT INTO t2 VALUES (32);
-FLUSH LOGS;
-INSERT INTO t2 VALUES (33);
-INSERT INTO t2 VALUES (34);
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-a
-31
-32
-33
-34
-include/save_master_gtid.inc
-connection server_2;
-include/wait_for_slave_sql_error.inc [errno=1062]
-connection server_2;
-include/stop_slave_io.inc
-SET GLOBAL slave_parallel_threads=10;
-START SLAVE;
-include/wait_for_slave_sql_error.inc [errno=1062]
-START SLAVE SQL_THREAD;
-include/wait_for_slave_sql_error.inc [errno=1062]
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-a
-31
-32
-SET sql_slave_skip_counter= 1;
-ERROR HY000: When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position
-include/stop_slave_io.inc
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
-a
-31
-32
-33
-34
-*** MDEV-6775: Wrong binlog order in parallel replication ***
-connection server_1;
-DELETE FROM t4;
-INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6);
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log";
-SET @old_format=@@GLOBAL.binlog_format;
-SET GLOBAL binlog_format=ROW;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-connection con1;
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-UPDATE t4 SET b=NULL WHERE a=6;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con2;
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-DELETE FROM t4 WHERE b <= 3;
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con1;
-SET binlog_format= @old_format;
-connection con2;
-SET binlog_format= @old_format;
-SET debug_sync='RESET';
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 NULL
-connection server_2;
-include/start_slave.inc
-SET debug_sync= 'now WAIT_FOR waiting';
-SELECT * FROM t4 ORDER BY a;
-a b
-1 NULL
-3 NULL
-4 4
-5 NULL
-6 NULL
-SET debug_sync= 'now SIGNAL cont';
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL binlog_format= @old_format;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-7237: Parallel replication: incorrect relaylog position after stop/start the slave ***
-connection server_1;
-INSERT INTO t2 VALUES (40);
-connection server_2;
-include/stop_slave.inc
-CHANGE MASTER TO master_use_gtid=no;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,rpl_parallel_scheduled_gtid_0_x_100";
-SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-connection server_1;
-INSERT INTO t2 VALUES (41);
-INSERT INTO t2 VALUES (42);
-SET @old_format= @@binlog_format;
-SET binlog_format= statement;
-DELETE FROM t2 WHERE a=40;
-SET binlog_format= @old_format;
-INSERT INTO t2 VALUES (43);
-INSERT INTO t2 VALUES (44);
-FLUSH LOGS;
-INSERT INTO t2 VALUES (45);
-SET gtid_seq_no=100;
-INSERT INTO t2 VALUES (46);
-connection con_temp2;
-BEGIN;
-SELECT * FROM t2 WHERE a=40 FOR UPDATE;
-a
-40
-connection server_2;
-include/start_slave.inc
-SET debug_sync= 'now WAIT_FOR scheduled_gtid_0_x_100';
-STOP SLAVE;
-connection con_temp2;
-SET debug_sync= 'now WAIT_FOR wait_for_done_waiting';
-ROLLBACK;
-connection server_2;
-include/wait_for_slave_sql_to_stop.inc
-SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
-a
-41
-42
-include/start_slave.inc
-SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
-a
-41
-42
-43
-44
-45
-46
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET DEBUG_SYNC= 'RESET';
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-CHANGE MASTER TO master_use_gtid=slave_pos;
-include/start_slave.inc
-*** MDEV-7326 Server deadlock in connection with parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=3;
-SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
-include/start_slave.inc
-connection server_1;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format= STATEMENT;
-INSERT INTO t1 VALUES (foo(50,
-"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
-"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
-connection server_1;
-INSERT INTO t2 VALUES (foo(50,
-"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
-"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
-connection server_1;
-INSERT INTO t1 VALUES (foo(51,
-"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
-"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
-SET DEBUG_SYNC= "now SIGNAL t1_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
-connection server_1;
-INSERT INTO t1 VALUES (52);
-SET BINLOG_FORMAT= @old_format;
-SELECT * FROM t2 WHERE a>=50 ORDER BY a;
-a
-50
-SELECT * FROM t1 WHERE a>=50 ORDER BY a;
-a
-50
-51
-52
-connection server_2;
-SET DEBUG_SYNC= "now SIGNAL prep_cont";
-SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
-SET DEBUG_SYNC= "now SIGNAL t2_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
-SET DEBUG_SYNC= "now SIGNAL t1_cont2";
-connection server_1;
-connection server_2;
-SELECT * FROM t2 WHERE a>=50 ORDER BY a;
-a
-50
-SELECT * FROM t1 WHERE a>=50 ORDER BY a;
-a
-50
-51
-52
-SET DEBUG_SYNC="reset";
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-7326 Server deadlock in connection with parallel replication ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=3;
-SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
-include/start_slave.inc
-connection server_1;
-SET @old_format= @@SESSION.binlog_format;
-SET binlog_format= STATEMENT;
-INSERT INTO t1 VALUES (foo(60,
-"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
-"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
-connection server_1;
-INSERT INTO t2 VALUES (foo(60,
-"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
-"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
-connection con_temp3;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
-SET binlog_format=statement;
-INSERT INTO t1 VALUES (foo(61,
-"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
-"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued1';
-connection con_temp4;
-SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
-INSERT INTO t6 VALUES (62);
-connection server_1;
-SET debug_sync='now WAIT_FOR master_queued2';
-SET debug_sync='now SIGNAL master_cont1';
-connection con_temp3;
-connection con_temp4;
-connection server_1;
-SET debug_sync='RESET';
-SET BINLOG_FORMAT= @old_format;
-SELECT * FROM t2 WHERE a>=60 ORDER BY a;
-a
-60
-SELECT * FROM t1 WHERE a>=60 ORDER BY a;
-a
-60
-61
-SELECT * FROM t6 WHERE a>=60 ORDER BY a;
-a
-62
-connection server_2;
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
-SET DEBUG_SYNC= "now SIGNAL t1_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
-connection server_2;
-SET DEBUG_SYNC= "now SIGNAL prep_cont";
-SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
-SET DEBUG_SYNC= "now SIGNAL t2_cont1";
-SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
-SET DEBUG_SYNC= "now SIGNAL t1_cont2";
-connection server_1;
-connection server_2;
-SELECT * FROM t2 WHERE a>=60 ORDER BY a;
-a
-60
-SELECT * FROM t1 WHERE a>=60 ORDER BY a;
-a
-60
-61
-SELECT * FROM t6 WHERE a>=60 ORDER BY a;
-a
-62
-SET DEBUG_SYNC="reset";
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=0;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=1;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
-connection server_1;
-INSERT INTO t2 VALUES (101);
-INSERT INTO t2 VALUES (102);
-INSERT INTO t2 VALUES (103);
-INSERT INTO t2 VALUES (104);
-INSERT INTO t2 VALUES (105);
-SET gtid_seq_no=1000;
-INSERT INTO t2 VALUES (106);
-INSERT INTO t2 VALUES (107);
-INSERT INTO t2 VALUES (108);
-INSERT INTO t2 VALUES (109);
-INSERT INTO t2 VALUES (110);
-INSERT INTO t2 VALUES (111);
-INSERT INTO t2 VALUES (112);
-INSERT INTO t2 VALUES (113);
-INSERT INTO t2 VALUES (114);
-INSERT INTO t2 VALUES (115);
-INSERT INTO t2 VALUES (116);
-INSERT INTO t2 VALUES (117);
-INSERT INTO t2 VALUES (118);
-INSERT INTO t2 VALUES (119);
-INSERT INTO t2 VALUES (120);
-INSERT INTO t2 VALUES (121);
-INSERT INTO t2 VALUES (122);
-INSERT INTO t2 VALUES (123);
-INSERT INTO t2 VALUES (124);
-INSERT INTO t2 VALUES (125);
-INSERT INTO t2 VALUES (126);
-INSERT INTO t2 VALUES (127);
-INSERT INTO t2 VALUES (128);
-INSERT INTO t2 VALUES (129);
-INSERT INTO t2 VALUES (130);
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
-a
-101
-102
-103
-104
-105
-107
-108
-109
-110
-111
-112
-113
-114
-115
-116
-117
-118
-119
-120
-121
-122
-123
-124
-125
-126
-127
-128
-129
-130
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-SET GLOBAL slave_parallel_threads=10;
-include/start_slave.inc
-*** MDEV-6676 - test syntax of @@slave_parallel_mode ***
-connection server_2;
-Parallel_Mode = 'conservative'
-include/stop_slave.inc
-SET GLOBAL slave_parallel_mode='aggressive';
-Parallel_Mode = 'aggressive'
-SET GLOBAL slave_parallel_mode='conservative';
-Parallel_Mode = 'conservative'
-*** MDEV-6676 - test that empty parallel_mode does not replicate in parallel ***
-connection server_1;
-INSERT INTO t2 VALUES (1040);
-include/save_master_gtid.inc
-connection server_2;
-SET GLOBAL slave_parallel_mode='none';
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply";
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
-a
-1040
-include/stop_slave.inc
-SET GLOBAL debug_dbug=@old_dbug;
-*** MDEV-6676 - test disabling domain-based parallel replication ***
-connection server_1;
-SET gtid_domain_id = 1;
-INSERT INTO t2 VALUES (1041);
-INSERT INTO t2 VALUES (1042);
-INSERT INTO t2 VALUES (1043);
-INSERT INTO t2 VALUES (1044);
-INSERT INTO t2 VALUES (1045);
-INSERT INTO t2 VALUES (1046);
-DELETE FROM t2 WHERE a >= 1041;
-SET gtid_domain_id = 2;
-INSERT INTO t2 VALUES (1041);
-INSERT INTO t2 VALUES (1042);
-INSERT INTO t2 VALUES (1043);
-INSERT INTO t2 VALUES (1044);
-INSERT INTO t2 VALUES (1045);
-INSERT INTO t2 VALUES (1046);
-SET gtid_domain_id = 0;
-include/save_master_gtid.inc
-connection server_2;
-SET GLOBAL slave_parallel_mode=minimal;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
-a
-1040
-1041
-1042
-1043
-1044
-1045
-1046
-*** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang ***
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_mode='conservative';
-SET GLOBAL slave_parallel_threads=10;
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep';
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @commit_id= 10000;
-ANALYZE TABLE t2;
-Table Op Msg_type Msg_text
-test.t2 analyze status Engine-independent statistics collected
-test.t2 analyze status OK
-INSERT INTO t3 VALUES (120, 0);
-SET @commit_id= 10001;
-INSERT INTO t3 VALUES (121, 0);
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
-a b
-120 0
-121 0
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
-a b
-120 0
-121 0
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
-include/start_slave.inc
-*** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. ***
-connection server_2;
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep';
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @old_server_id= @@SESSION.server_id;
-SET SESSION server_id= 100;
-SET @commit_id= 10010;
-ALTER TABLE t1 COMMENT "Hulubulu!";
-SET SESSION server_id= @old_server_id;
-INSERT INTO t3 VALUES (130, 0);
-SET @commit_id= 10011;
-INSERT INTO t3 VALUES (131, 0);
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
-a b
-130 0
-131 0
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
-a b
-130 0
-131 0
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
-include/start_slave.inc
-*** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) ***
-connection server_1;
-INSERT INTO t3 VALUES (201,0), (202,0);
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_mdev8031';
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @commit_id= 10200;
-INSERT INTO t3 VALUES (203, 1);
-INSERT INTO t3 VALUES (204, 1);
-INSERT INTO t3 VALUES (205, 1);
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=201;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=202;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=204;
-UPDATE t3 SET b=b+1 WHERE a=203;
-UPDATE t3 SET b=b+1 WHERE a=205;
-UPDATE t3 SET b=b+1 WHERE a=205;
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 3
-202 4
-203 4
-204 4
-205 3
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 3
-202 4
-203 4
-204 4
-205 3
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_dbug;
-include/start_slave.inc
-*** Check getting deadlock killed inside open_binlog() during retry. ***
-connection server_2;
-include/stop_slave.inc
-SET @old_dbug= @@GLOBAL.debug_dbug;
-SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill';
-SET @old_max= @@GLOBAL.max_relay_log_size;
-SET GLOBAL max_relay_log_size= 4096;
-connection server_1;
-SET @old_dbug= @@SESSION.debug_dbug;
-SET SESSION debug_dbug="+d,binlog_force_commit_id";
-SET @commit_id= 10210;
-Omit long queries that cause relaylog rotations and transaction retries...
-SET SESSION debug_dbug=@old_dbug;
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 6
-202 8
-203 7
-204 7
-205 5
-include/save_master_gtid.inc
-connection server_2;
-include/start_slave.inc
-include/sync_with_master_gtid.inc
-SELECT * FROM t3 WHERE a>=200 ORDER BY a;
-a b
-201 6
-202 8
-203 7
-204 7
-205 5
-include/stop_slave.inc
-SET GLOBAL debug_dbug= @old_debg;
-SET GLOBAL max_relay_log_size= @old_max;
-include/start_slave.inc
-*** MDEV-8725: Assertion on ROLLBACK statement in the binary log ***
-connection server_1;
-BEGIN;
-INSERT INTO t2 VALUES (2000);
-INSERT INTO t1 VALUES (2000);
-INSERT INTO t2 VALUES (2001);
-ROLLBACK;
-SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
-a
-2000
-SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
-a
-include/save_master_gtid.inc
-connection server_2;
-include/sync_with_master_gtid.inc
-SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
-a
-2000
-SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
-a
-connection server_2;
-include/stop_slave.inc
-SET GLOBAL slave_parallel_threads=@old_parallel_threads;
-include/start_slave.inc
-SET DEBUG_SYNC= 'RESET';
-connection server_1;
-DROP function foo;
-DROP TABLE t1,t2,t3,t4,t5,t6;
-SET DEBUG_SYNC= 'RESET';
-include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_analyze_table_hang.result b/mysql-test/suite/rpl/r/rpl_parallel_analyze_table_hang.result
new file mode 100644
index 00000000000..3c3cd2601e8
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_analyze_table_hang.result
@@ -0,0 +1,51 @@
+*** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep';
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @commit_id= 10000;
+ANALYZE TABLE t2;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+INSERT INTO t3 VALUES (120, 0);
+SET @commit_id= 10001;
+INSERT INTO t3 VALUES (121, 0);
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
+a b
+120 0
+121 0
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a >= 120 ORDER BY a;
+a b
+120 0
+121 0
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+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 t2,t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_conflicts.result b/mysql-test/suite/rpl/r/rpl_parallel_conflicts.result
index b15de6fc215..09597ba81c1 100644
--- a/mysql-test/suite/rpl/r/rpl_parallel_conflicts.result
+++ b/mysql-test/suite/rpl/r/rpl_parallel_conflicts.result
@@ -8,6 +8,12 @@ CREATE TABLE t7 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
CREATE TABLE t8 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
connection server_2;
include/stop_slave.inc
+SET @old_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode='conservative';
+SET @old_threads= @@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=40;
+SET @old_transaction_retries= @@GLOBAL.slave_transaction_retries;
+SET GLOBAL slave_transaction_retries=5;
connection server_1;
INSERT INTO t7 VALUES (1,1), (2,2), (3,3), (4,4), (5,5);
SET @old_dbug= @@SESSION.debug_dbug;
@@ -325,6 +331,9 @@ a b
104 4
include/stop_slave.inc
SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_mode;
+SET GLOBAL slave_parallel_threads=@old_threads;
+SET GLOBAL slave_transaction_retries=@old_transaction_retries;
include/start_slave.inc
SET DEBUG_SYNC= 'RESET';
connection server_1;
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_deadlock_corrupt_binlog.result b/mysql-test/suite/rpl/r/rpl_parallel_deadlock_corrupt_binlog.result
new file mode 100644
index 00000000000..74d1d53b67c
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_deadlock_corrupt_binlog.result
@@ -0,0 +1,93 @@
+*** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=1;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
+connection server_1;
+INSERT INTO t2 VALUES (101);
+INSERT INTO t2 VALUES (102);
+INSERT INTO t2 VALUES (103);
+INSERT INTO t2 VALUES (104);
+INSERT INTO t2 VALUES (105);
+SET gtid_seq_no=1000;
+INSERT INTO t2 VALUES (106);
+INSERT INTO t2 VALUES (107);
+INSERT INTO t2 VALUES (108);
+INSERT INTO t2 VALUES (109);
+INSERT INTO t2 VALUES (110);
+INSERT INTO t2 VALUES (111);
+INSERT INTO t2 VALUES (112);
+INSERT INTO t2 VALUES (113);
+INSERT INTO t2 VALUES (114);
+INSERT INTO t2 VALUES (115);
+INSERT INTO t2 VALUES (116);
+INSERT INTO t2 VALUES (117);
+INSERT INTO t2 VALUES (118);
+INSERT INTO t2 VALUES (119);
+INSERT INTO t2 VALUES (120);
+INSERT INTO t2 VALUES (121);
+INSERT INTO t2 VALUES (122);
+INSERT INTO t2 VALUES (123);
+INSERT INTO t2 VALUES (124);
+INSERT INTO t2 VALUES (125);
+INSERT INTO t2 VALUES (126);
+INSERT INTO t2 VALUES (127);
+INSERT INTO t2 VALUES (128);
+INSERT INTO t2 VALUES (129);
+INSERT INTO t2 VALUES (130);
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
+a
+101
+102
+103
+104
+105
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t2;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_domain.result b/mysql-test/suite/rpl/r/rpl_parallel_domain.result
new file mode 100644
index 00000000000..69b9678d149
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_domain.result
@@ -0,0 +1,71 @@
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
+OK
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
+OK
+include/stop_slave.inc
+SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*)))
+OK
+include/start_slave.inc
+SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user";
+IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*)))
+OK
+*** Test long-running query in domain 1 can run in parallel with short queries in domain 0 ***
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1);
+connection server_2;
+connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+LOCK TABLE t1 WRITE;
+connection server_1;
+SET gtid_domain_id=1;
+INSERT INTO t1 VALUES (2);
+SET gtid_domain_id=0;
+INSERT INTO t2 VALUES (2);
+INSERT INTO t2 VALUES (3);
+BEGIN;
+INSERT INTO t2 VALUES (4);
+INSERT INTO t2 VALUES (5);
+COMMIT;
+INSERT INTO t2 VALUES (6);
+connection server_2;
+SELECT * FROM t2 ORDER by a;
+a
+1
+2
+3
+4
+5
+6
+connection con_temp1;
+SELECT * FROM t1;
+a
+1
+UNLOCK TABLES;
+connection server_2;
+SELECT * FROM t1 ORDER BY a;
+a
+1
+2
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1,t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_domain_slave_single_grp.result b/mysql-test/suite/rpl/r/rpl_parallel_domain_slave_single_grp.result
new file mode 100644
index 00000000000..613aac64487
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_domain_slave_single_grp.result
@@ -0,0 +1,101 @@
+*** Test two transactions in different domains committed in opposite order on slave but in a single group commit. ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1);
+connection server_2;
+include/stop_slave.inc
+connection server_1;
+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;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format='statement';
+SET gtid_domain_id=1;
+INSERT INTO t2 VALUES (foo(10,
+'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'));
+connection server_2;
+FLUSH LOGS;
+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;
+SET @old_format=@@GLOBAL.binlog_format;
+SET GLOBAL binlog_format=statement;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+SET debug_sync='now WAIT_FOR ready1';
+connection server_1;
+SET gtid_domain_id=2;
+INSERT INTO t2 VALUES (foo(11,
+'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'));
+SET gtid_domain_id=0;
+SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
+a
+10
+11
+connection server_2;
+SET debug_sync='now WAIT_FOR ready3';
+SET debug_sync='now SIGNAL cont3';
+SET debug_sync='now WAIT_FOR ready4';
+SET debug_sync='now SIGNAL cont1';
+SET debug_sync='now WAIT_FOR ready2';
+SET debug_sync='now SIGNAL cont4';
+SELECT * FROM t2 WHERE a >= 10 ORDER BY a;
+a
+10
+11
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002
+slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(11,
+'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4'))
+slave-bin.000002 # Xid # # COMMIT /* XID */
+slave-bin.000002 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000002 # Query # # use `test`; INSERT INTO t2 VALUES (foo(10,
+'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1',
+'commit_after_release_LOCK_prepare_ordered SIGNAL ready2'))
+slave-bin.000002 # Xid # # COMMIT /* XID */
+FLUSH LOGS;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL binlog_format=@old_format;
+connection server_1;
+DROP function foo;
+DROP TABLE t1,t2;
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL binlog_format=@old_format;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_free_deferred_event.result b/mysql-test/suite/rpl/r/rpl_parallel_free_deferred_event.result
new file mode 100644
index 00000000000..6718561a321
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_free_deferred_event.result
@@ -0,0 +1,44 @@
+*** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL replicate_ignore_table="test.t3";
+SET GLOBAL slave_parallel_threads=2;
+include/start_slave.inc
+connection server_1;
+INSERT INTO t3 VALUES (100, rand());
+INSERT INTO t3 VALUES (101, rand());
+connection server_2;
+connection server_1;
+INSERT INTO t3 VALUES (102, rand());
+INSERT INTO t3 VALUES (103, rand());
+INSERT INTO t3 VALUES (104, rand());
+INSERT INTO t3 VALUES (105, rand());
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL replicate_ignore_table="";
+include/start_slave.inc
+connection server_1;
+INSERT INTO t3 VALUES (106, rand());
+INSERT INTO t3 VALUES (107, rand());
+connection server_2;
+SELECT * FROM t3 WHERE a >= 100 ORDER BY a;
+a b
+106 #
+107 #
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_gco_wait_kill.result b/mysql-test/suite/rpl/r/rpl_parallel_gco_wait_kill.result
new file mode 100644
index 00000000000..4472550c4f2
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_gco_wait_kill.result
@@ -0,0 +1,257 @@
+*** Test killing thread that is waiting to start transaction until previous transaction commits ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Query execution was interrupted");
+CALL mtr.add_suppression("Slave: Connection was killed");
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET sql_log_bin=1;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode= 'conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+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 server_2;
+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 GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=4;
+include/start_slave.inc
+connection server_1;
+SET gtid_domain_id=2;
+BEGIN;
+INSERT INTO t3 VALUES (70, foo(70,
+'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', ''));
+INSERT INTO t3 VALUES (60, foo(60,
+'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2',
+'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+connection server_2;
+SET debug_sync='now WAIT_FOR d2_query';
+connection server_1;
+SET gtid_domain_id=1;
+BEGIN;
+INSERT INTO t3 VALUES (61, foo(61,
+'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting',
+'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed'));
+INSERT INTO t3 VALUES (62, foo(62,
+'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2',
+'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+connection server_2;
+SET debug_sync='now WAIT_FOR d1_query';
+connection server_1;
+SET gtid_domain_id=0;
+INSERT INTO t3 VALUES (63, foo(63,
+'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2',
+'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont'));
+connection server_2;
+SET debug_sync='now WAIT_FOR d0_query';
+connection server_1;
+SET gtid_domain_id=3;
+BEGIN;
+INSERT INTO t3 VALUES (68, foo(68,
+'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', ''));
+INSERT INTO t3 VALUES (69, foo(69,
+'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2',
+'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont'));
+COMMIT;
+SET gtid_domain_id=0;
+connection server_2;
+SET debug_sync='now WAIT_FOR d3_query';
+SET debug_sync='now SIGNAL d2_cont2';
+SET debug_sync='now WAIT_FOR d2_done';
+SET debug_sync='now SIGNAL d1_cont2';
+SET debug_sync='now WAIT_FOR d1_done';
+SET debug_sync='now SIGNAL d0_cont2';
+SET debug_sync='now WAIT_FOR d0_done';
+SET debug_sync='now SIGNAL d3_cont2';
+SET debug_sync='now WAIT_FOR d3_done';
+connection con_temp3;
+INSERT INTO t3 VALUES (64, foo(64,
+'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', ''));
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2';
+INSERT INTO t3 VALUES (65, foo(65, '', ''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (66, foo(66, '', ''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4';
+INSERT INTO t3 VALUES (67, foo(67, '', ''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued4';
+SET debug_sync='now SIGNAL master_cont2';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
+a b
+60 60
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+70 70
+SET debug_sync='RESET';
+connection server_2;
+SET debug_sync='now SIGNAL d0_cont';
+SET debug_sync='now WAIT_FOR t1_waiting';
+SET debug_sync='now SIGNAL d3_cont';
+SET debug_sync='now WAIT_FOR t2_waiting';
+SET debug_sync='now SIGNAL d1_cont';
+SET debug_sync='now WAIT_FOR t3_waiting';
+SET debug_sync='now SIGNAL d2_cont';
+SET debug_sync='now WAIT_FOR t4_waiting';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t3_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+STOP SLAVE IO_THREAD;
+SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a;
+a b
+60 60
+61 61
+62 62
+63 63
+64 64
+68 68
+69 69
+70 70
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+UPDATE t3 SET b=b+1 WHERE a=60;
+connection server_2;
+include/start_slave.inc
+SELECT * FROM t3 WHERE a >= 60 ORDER BY a;
+a b
+60 61
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+70 70
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** 5. Test killing thread that is waiting for queue of max length to shorten ***
+SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued;
+SET GLOBAL slave_parallel_max_queued=9000;
+connection server_1;
+INSERT INTO t3 VALUES (80, foo(0,
+'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', ''));
+connection server_2;
+SET debug_sync='now WAIT_FOR query_waiting';
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max";
+connection server_1;
+SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
+a b
+80 0
+81 10000
+connection server_2;
+SET debug_sync='now WAIT_FOR wait_queue_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR wait_queue_killed';
+SET debug_sync='now SIGNAL query_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+STOP SLAVE IO_THREAD;
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_max_queued= @old_max_queued;
+connection server_1;
+INSERT INTO t3 VALUES (82,0);
+connection server_2;
+SET debug_sync='RESET';
+include/start_slave.inc
+SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
+a b
+80 0
+81 10000
+82 0
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP function foo;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_gtid_slave_pos_update_fail.result b/mysql-test/suite/rpl/r/rpl_parallel_gtid_slave_pos_update_fail.result
new file mode 100644
index 00000000000..2e7e7f547af
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_gtid_slave_pos_update_fail.result
@@ -0,0 +1,65 @@
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection server_2;
+include/stop_slave.inc
+connection con1;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+UPDATE t4 SET b=NULL WHERE a=6;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 1;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
+include/start_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+2 2
+3 NULL
+4 4
+5 NULL
+6 NULL
+SET @last_gtid= 'GTID';
+SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
+CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
+AS result;
+result
+GTID found ok
+SELECT "ROW FOUND" AS `Is the row found?`
+ FROM mysql.gtid_slave_pos
+WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
+Is the row found?
+ROW FOUND
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+disconnect con2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_ignore_error_on_rotate.result b/mysql-test/suite/rpl/r/rpl_parallel_ignore_error_on_rotate.result
new file mode 100644
index 00000000000..d00740dba3d
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_ignore_error_on_rotate.result
@@ -0,0 +1,74 @@
+*** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+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=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+SET gtid_domain_id=1;
+INSERT INTO t2 VALUES (1);
+SET gtid_domain_id=0;
+SET gtid_domain_id=2;
+INSERT INTO t2 VALUES (2);
+SET gtid_domain_id=0;
+INSERT INTO t2 VALUES (31);
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads= 0;
+include/start_slave.inc
+SET sql_log_bin= 0;
+INSERT INTO t2 VALUES (32);
+SET sql_log_bin= 1;
+connection server_1;
+INSERT INTO t2 VALUES (32);
+FLUSH LOGS;
+INSERT INTO t2 VALUES (33);
+INSERT INTO t2 VALUES (34);
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+a
+31
+32
+33
+34
+include/save_master_gtid.inc
+connection server_2;
+include/wait_for_slave_sql_error.inc [errno=1062]
+connection server_2;
+include/stop_slave_io.inc
+SET GLOBAL slave_parallel_threads=10;
+START SLAVE;
+include/wait_for_slave_sql_error.inc [errno=1062]
+START SLAVE SQL_THREAD;
+include/wait_for_slave_sql_error.inc [errno=1062]
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+a
+31
+32
+SET sql_slave_skip_counter= 1;
+ERROR HY000: When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position
+include/stop_slave_io.inc
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 30 ORDER BY a;
+a
+31
+32
+33
+34
+connection server_2;
+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 t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_incorrect_relay_pos.result b/mysql-test/suite/rpl/r/rpl_parallel_incorrect_relay_pos.result
new file mode 100644
index 00000000000..6ca7f2b68e8
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_incorrect_relay_pos.result
@@ -0,0 +1,75 @@
+*** MDEV-7237: Parallel replication: incorrect relaylog position after stop/start the slave ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (40);
+connection server_2;
+connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=no;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_scheduled_gtid_0_x_100";
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+connection server_1;
+INSERT INTO t2 VALUES (41);
+INSERT INTO t2 VALUES (42);
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+DELETE FROM t2 WHERE a=40;
+SET binlog_format= @old_format;
+INSERT INTO t2 VALUES (43);
+INSERT INTO t2 VALUES (44);
+FLUSH LOGS;
+INSERT INTO t2 VALUES (45);
+SET gtid_seq_no=100;
+INSERT INTO t2 VALUES (46);
+connection con_temp2;
+BEGIN;
+SELECT * FROM t2 WHERE a=40 FOR UPDATE;
+a
+40
+connection server_2;
+include/start_slave.inc
+SET debug_sync= 'now WAIT_FOR scheduled_gtid_0_x_100';
+STOP SLAVE;
+connection con_temp2;
+SET debug_sync= 'now WAIT_FOR wait_for_done_waiting';
+ROLLBACK;
+connection server_2;
+include/wait_for_slave_sql_to_stop.inc
+SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
+a
+41
+42
+include/start_slave.inc
+SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
+a
+41
+42
+43
+44
+45
+46
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET DEBUG_SYNC= 'RESET';
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_innodb_lock_conflict.result b/mysql-test/suite/rpl/r/rpl_parallel_innodb_lock_conflict.result
new file mode 100644
index 00000000000..1411db16af6
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_innodb_lock_conflict.result
@@ -0,0 +1,79 @@
+***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+SET sql_log_bin=1;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection con1;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+UPDATE t4 SET b=NULL WHERE a=6;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 3;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+include/start_slave.inc
+include/stop_slave.inc
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 NULL
+connection server_1;
+DELETE FROM t4;
+INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
+connection con1;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t4 VALUES (7, NULL);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 3;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+include/start_slave.inc
+include/stop_slave.inc
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 6
+7 NULL
+connection server_2;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+disconnect con1;
+disconnect con2;
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_mdev6589.result b/mysql-test/suite/rpl/r/rpl_parallel_mdev6589.result
index e05e824eed3..47cdb3496da 100644
--- a/mysql-test/suite/rpl/r/rpl_parallel_mdev6589.result
+++ b/mysql-test/suite/rpl/r/rpl_parallel_mdev6589.result
@@ -92,6 +92,7 @@ MASTER_GTID_WAIT('WAIT_POS')
0
connection con_temp1;
COMMIT;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
SET sql_log_bin=1;
connection server_2;
include/wait_for_slave_sql_error.inc [errno=1062]
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_missed_error_handling.result b/mysql-test/suite/rpl/r/rpl_parallel_missed_error_handling.result
new file mode 100644
index 00000000000..e9d04c02d7a
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_missed_error_handling.result
@@ -0,0 +1,65 @@
+*** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+INSERT INTO t3 VALUES (110, 1);
+connection server_2;
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+a b
+110 1
+SET sql_log_bin=0;
+INSERT INTO t3 VALUES (111, 666);
+SET sql_log_bin=1;
+connection server_1;
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (111, 2);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+INSERT INTO t3 VALUES (112, 3);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+connection con2;
+SET debug_sync='RESET';
+connection server_2;
+include/wait_for_slave_sql_error.inc [errno=1062]
+include/wait_for_slave_sql_to_stop.inc
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+a b
+110 1
+111 666
+SET sql_log_bin=0;
+DELETE FROM t3 WHERE a=111 AND b=666;
+SET sql_log_bin=1;
+START SLAVE SQL_THREAD;
+SELECT * FROM t3 WHERE a >= 110 ORDER BY a;
+a b
+110 1
+111 2
+112 3
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+disconnect con1;
+disconnect con2;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_mode.result b/mysql-test/suite/rpl/r/rpl_parallel_mode.result
new file mode 100644
index 00000000000..313290b1fd2
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_mode.result
@@ -0,0 +1,75 @@
+*** MDEV-6676 - test syntax of @@slave_parallel_mode ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+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=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+connection server_2;
+Parallel_Mode = 'optimistic'
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='aggressive';
+Parallel_Mode = 'aggressive'
+SET GLOBAL slave_parallel_mode='conservative';
+Parallel_Mode = 'conservative'
+*** MDEV-6676 - test that empty parallel_mode does not replicate in parallel ***
+connection server_1;
+INSERT INTO t2 VALUES (1040);
+include/save_master_gtid.inc
+connection server_2;
+SET GLOBAL slave_parallel_mode='none';
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply";
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
+a
+1040
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+*** MDEV-6676 - test disabling domain-based parallel replication ***
+connection server_1;
+SET gtid_domain_id = 1;
+INSERT INTO t2 VALUES (1041);
+INSERT INTO t2 VALUES (1042);
+INSERT INTO t2 VALUES (1043);
+INSERT INTO t2 VALUES (1044);
+INSERT INTO t2 VALUES (1045);
+INSERT INTO t2 VALUES (1046);
+DELETE FROM t2 WHERE a >= 1041;
+SET gtid_domain_id = 2;
+INSERT INTO t2 VALUES (1041);
+INSERT INTO t2 VALUES (1042);
+INSERT INTO t2 VALUES (1043);
+INSERT INTO t2 VALUES (1044);
+INSERT INTO t2 VALUES (1045);
+INSERT INTO t2 VALUES (1046);
+SET gtid_domain_id = 0;
+include/save_master_gtid.inc
+connection server_2;
+SET GLOBAL slave_parallel_mode=minimal;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a >= 1040 ORDER BY a;
+a
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+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 t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_partial_binlog_trans.result b/mysql-test/suite/rpl/r/rpl_parallel_partial_binlog_trans.result
new file mode 100644
index 00000000000..ab1cac692a0
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_partial_binlog_trans.result
@@ -0,0 +1,51 @@
+*** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t6 (a INT) ENGINE=MyISAM;
+CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1;
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection con1;
+SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont';
+INSERT INTO t6 VALUES (1), (2), (3);
+connection server_1;
+SET debug_sync='now WAIT_FOR ready';
+KILL QUERY CONID;
+SET debug_sync='now SIGNAL cont';
+connection con1;
+ERROR 70100: Query execution was interrupted
+SET debug_sync='RESET';
+connection server_1;
+SET debug_sync='RESET';
+connection server_2;
+include/wait_for_slave_sql_error.inc [errno=1317]
+STOP SLAVE IO_THREAD;
+SET GLOBAL gtid_slave_pos= 'AFTER_ERROR_GTID_POS';
+include/start_slave.inc
+connection server_1;
+INSERT INTO t6 VALUES (4);
+SELECT * FROM t6 ORDER BY a;
+a
+1
+4
+connection server_2;
+SELECT * FROM t6 ORDER BY a;
+a
+4
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t6;
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_record_gtid_wakeup.result b/mysql-test/suite/rpl/r/rpl_parallel_record_gtid_wakeup.result
new file mode 100644
index 00000000000..cbe53e4f623
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_record_gtid_wakeup.result
@@ -0,0 +1,48 @@
+*** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep';
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @old_server_id= @@SESSION.server_id;
+SET SESSION server_id= 100;
+SET @commit_id= 10010;
+ALTER TABLE t1 COMMENT "Hulubulu!";
+SET SESSION server_id= @old_server_id;
+INSERT INTO t3 VALUES (130, 0);
+SET @commit_id= 10011;
+INSERT INTO t3 VALUES (131, 0);
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
+a b
+130 0
+131 0
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a >= 130 ORDER BY a;
+a b
+130 0
+131 0
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1,t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry_deadlock.result b/mysql-test/suite/rpl/r/rpl_parallel_retry_deadlock.result
new file mode 100644
index 00000000000..1f5a23db848
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_retry_deadlock.result
@@ -0,0 +1,192 @@
+*** MDEV-7326 Server deadlock in connection with parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t6 (a INT) ENGINE=MyISAM;
+connection server_2;
+connection server_1;
+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 server_2;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=3;
+SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
+include/start_slave.inc
+connection server_1;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+INSERT INTO t1 VALUES (foo(50,
+"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
+"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
+connection server_1;
+INSERT INTO t2 VALUES (foo(50,
+"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
+"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
+connection server_1;
+INSERT INTO t1 VALUES (foo(51,
+"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
+"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
+SET DEBUG_SYNC= "now SIGNAL t1_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
+connection server_1;
+INSERT INTO t1 VALUES (52);
+SET BINLOG_FORMAT= @old_format;
+SELECT * FROM t2 WHERE a>=50 ORDER BY a;
+a
+50
+SELECT * FROM t1 WHERE a>=50 ORDER BY a;
+a
+50
+51
+52
+connection server_2;
+SET DEBUG_SYNC= "now SIGNAL prep_cont";
+SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
+SET DEBUG_SYNC= "now SIGNAL t2_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
+SET DEBUG_SYNC= "now SIGNAL t1_cont2";
+connection server_1;
+connection server_2;
+SELECT * FROM t2 WHERE a>=50 ORDER BY a;
+a
+50
+SELECT * FROM t1 WHERE a>=50 ORDER BY a;
+a
+50
+51
+52
+SET DEBUG_SYNC="reset";
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** MDEV-7326 Server deadlock in connection with parallel replication ***
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode='conservative';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=3;
+SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid";
+include/start_slave.inc
+connection server_1;
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+INSERT INTO t1 VALUES (foo(60,
+"rpl_parallel_start_waiting_for_prior SIGNAL t3_ready",
+"rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR prep_ready";
+connection server_1;
+INSERT INTO t2 VALUES (foo(60,
+"rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1",
+"rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2"));
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready1";
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+SET binlog_format=statement;
+INSERT INTO t1 VALUES (foo(61,
+"rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1",
+"rpl_parallel_after_mark_start_commit SIGNAL t2_ready2"));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+INSERT INTO t6 VALUES (62);
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection server_1;
+SET debug_sync='RESET';
+SET BINLOG_FORMAT= @old_format;
+SELECT * FROM t2 WHERE a>=60 ORDER BY a;
+a
+60
+SELECT * FROM t1 WHERE a>=60 ORDER BY a;
+a
+60
+61
+SELECT * FROM t6 WHERE a>=60 ORDER BY a;
+a
+62
+connection server_2;
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready1";
+SET DEBUG_SYNC= "now SIGNAL t1_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t1_ready2";
+connection server_2;
+SET DEBUG_SYNC= "now SIGNAL prep_cont";
+SET DEBUG_SYNC= "now WAIT_FOR t3_ready";
+SET DEBUG_SYNC= "now SIGNAL t2_cont1";
+SET DEBUG_SYNC= "now WAIT_FOR t2_ready2";
+SET DEBUG_SYNC= "now SIGNAL t1_cont2";
+connection server_1;
+connection server_2;
+SELECT * FROM t2 WHERE a>=60 ORDER BY a;
+a
+60
+SELECT * FROM t1 WHERE a>=60 ORDER BY a;
+a
+60
+61
+SELECT * FROM t6 WHERE a>=60 ORDER BY a;
+a
+62
+SET DEBUG_SYNC="reset";
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP function foo;
+DROP TABLE t1,t2,t6;
+disconnect con_temp3;
+disconnect con_temp4;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_rollback_assert.result b/mysql-test/suite/rpl/r/rpl_parallel_rollback_assert.result
new file mode 100644
index 00000000000..af9c5f14687
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_rollback_assert.result
@@ -0,0 +1,45 @@
+*** MDEV-8725: Assertion on ROLLBACK statement in the binary log ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+BEGIN;
+INSERT INTO t2 VALUES (2000);
+INSERT INTO t1 VALUES (2000);
+INSERT INTO t2 VALUES (2001);
+ROLLBACK;
+SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
+a
+2000
+SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
+a
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+connection server_1;
+INSERT INTO t2 VALUES (2020);
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+SELECT * FROM t2 WHERE a>=2000 ORDER BY a;
+a
+2020
+SELECT * FROM t1 WHERE a>=2000 ORDER BY a;
+a
+2000
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1,t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_single_grpcmt.result b/mysql-test/suite/rpl/r/rpl_parallel_single_grpcmt.result
new file mode 100644
index 00000000000..18ffac4fa5d
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_single_grpcmt.result
@@ -0,0 +1,160 @@
+*** Test that group-committed transactions on the master can replicate in parallel on the slave. ***
+include/master-slave.inc
+[connection master]
+connection server_1;
+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 server_2;
+include/stop_slave.inc
+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;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7);
+connection server_2;
+connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+BEGIN;
+INSERT INTO t3 VALUES (2,102);
+connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+BEGIN;
+INSERT INTO t3 VALUES (4,104);
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+SET binlog_format=statement;
+INSERT INTO t3 VALUES (2, foo(12,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+SET binlog_format=statement;
+INSERT INTO t3 VALUES (4, foo(14,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+SET binlog_format=statement;
+INSERT INTO t3 VALUES (6, foo(16,
+'group_commit_waiting_for_prior SIGNAL slave_queued3',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+SET debug_sync='RESET';
+connection server_1;
+SELECT * FROM t3 ORDER BY a;
+a b
+1 1
+2 12
+3 3
+4 14
+5 5
+6 16
+7 7
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+''))
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+''))
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+master-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
+'group_commit_waiting_for_prior SIGNAL slave_queued3',
+''))
+master-bin.000001 # Xid # # COMMIT /* XID */
+connection server_2;
+SET debug_sync='now WAIT_FOR slave_queued3';
+connection con_temp1;
+ROLLBACK;
+connection server_2;
+SET debug_sync='now WAIT_FOR slave_queued1';
+connection con_temp2;
+ROLLBACK;
+connection server_2;
+SET debug_sync='now WAIT_FOR slave_queued2';
+SET debug_sync='now SIGNAL slave_cont1';
+SELECT * FROM t3 ORDER BY a;
+a b
+1 1
+2 12
+3 3
+4 14
+5 5
+6 16
+7 7
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000001 # Gtid # # GTID #-#-#
+slave-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
+slave-bin.000001 # Gtid # # GTID #-#-#
+slave-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7)
+slave-bin.000001 # Xid # # COMMIT /* XID */
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (2, foo(12,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1',
+''))
+slave-bin.000001 # Xid # # COMMIT /* XID */
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (4, foo(14,
+'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2',
+''))
+slave-bin.000001 # Xid # # COMMIT /* XID */
+slave-bin.000001 # Gtid # # BEGIN GTID #-#-# cid=#
+slave-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (6, foo(16,
+'group_commit_waiting_for_prior SIGNAL slave_queued3',
+''))
+slave-bin.000001 # Xid # # COMMIT /* XID */
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP function foo;
+DROP TABLE t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_slave_bgc_kill.result b/mysql-test/suite/rpl/r/rpl_parallel_slave_bgc_kill.result
new file mode 100644
index 00000000000..320bf0e49f8
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_slave_bgc_kill.result
@@ -0,0 +1,323 @@
+*** Test killing slave threads at various wait points ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+connection server_1;
+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 server_2;
+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;
+*** 1. Test killing transaction waiting in commit for previous transaction to commit ***
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (31, foo(31,
+'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+INSERT INTO t3 VALUES (32, foo(32,
+'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+''));
+INSERT INTO t3 VALUES (33, foo(33,
+'group_commit_waiting_for_prior SIGNAL t2_waiting',
+'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+COMMIT;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (34, foo(34,
+'',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+a b
+31 31
+32 32
+33 33
+34 34
+SET debug_sync='RESET';
+connection server_2;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Query execution was interrupted");
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
+CALL mtr.add_suppression("Slave: Connection was killed");
+SET sql_log_bin=1;
+SET debug_sync='now WAIT_FOR t2_query';
+SET debug_sync='now SIGNAL t2_cont';
+SET debug_sync='now WAIT_FOR t1_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t2_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+STOP SLAVE IO_THREAD;
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+a b
+31 31
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+INSERT INTO t3 VALUES (39,0);
+connection server_2;
+include/start_slave.inc
+SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
+a b
+31 31
+32 32
+33 33
+34 34
+39 0
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** 2. Same as (1), but without restarting IO thread after kill of SQL threads ***
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (41, foo(41,
+'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+INSERT INTO t3 VALUES (42, foo(42,
+'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+''));
+INSERT INTO t3 VALUES (43, foo(43,
+'group_commit_waiting_for_prior SIGNAL t2_waiting',
+'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+COMMIT;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (44, foo(44,
+'',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
+a b
+41 41
+42 42
+43 43
+44 44
+SET debug_sync='RESET';
+connection server_2;
+SET debug_sync='now WAIT_FOR t2_query';
+SET debug_sync='now SIGNAL t2_cont';
+SET debug_sync='now WAIT_FOR t1_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t2_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+INSERT INTO t3 VALUES (49,0);
+connection server_2;
+START SLAVE SQL_THREAD;
+SELECT * FROM t3 WHERE a >= 40 ORDER BY a;
+a b
+41 41
+42 42
+43 43
+44 44
+49 0
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+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;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+include/start_slave.inc
+*** 3. Same as (2), but not using gtid mode ***
+connection server_2;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=no;
+include/start_slave.inc
+connection server_1;
+connection con_temp3;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+INSERT INTO t3 VALUES (51, foo(51,
+'commit_before_prepare_ordered WAIT_FOR t2_waiting',
+'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont'));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con_temp4;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+BEGIN;
+INSERT INTO t3 VALUES (52, foo(52,
+'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
+''));
+INSERT INTO t3 VALUES (53, foo(53,
+'group_commit_waiting_for_prior SIGNAL t2_waiting',
+'group_commit_waiting_for_prior_killed SIGNAL t2_killed'));
+COMMIT;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+connection con_temp5;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
+INSERT INTO t3 VALUES (54, foo(54,
+'',
+''));
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued3';
+SET debug_sync='now SIGNAL master_cont1';
+connection con_temp3;
+connection con_temp4;
+connection con_temp5;
+connection server_1;
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+a b
+51 51
+52 52
+53 53
+54 54
+SET debug_sync='RESET';
+connection server_2;
+SET debug_sync='now WAIT_FOR t2_query';
+SET debug_sync='now SIGNAL t2_cont';
+SET debug_sync='now WAIT_FOR t1_ready';
+KILL THD_ID;
+SET debug_sync='now WAIT_FOR t2_killed';
+SET debug_sync='now SIGNAL t1_cont';
+include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+a b
+51 51
+SET debug_sync='RESET';
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+SET sql_log_bin=0;
+DROP FUNCTION foo;
+CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
+RETURNS INT DETERMINISTIC
+BEGIN
+RETURN x;
+END
+||
+SET sql_log_bin=1;
+connection server_1;
+INSERT INTO t3 VALUES (59,0);
+connection server_2;
+START SLAVE SQL_THREAD;
+SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
+a b
+51 51
+52 52
+53 53
+54 54
+59 0
+connection server_2;
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP function foo;
+DROP TABLE t1,t2,t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_stop_on_con_kill.result b/mysql-test/suite/rpl/r/rpl_parallel_stop_on_con_kill.result
new file mode 100644
index 00000000000..bf0ed9e4374
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_stop_on_con_kill.result
@@ -0,0 +1,102 @@
+*** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (201,0), (202,0);
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_mdev8031';
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @commit_id= 10200;
+INSERT INTO t3 VALUES (203, 1);
+INSERT INTO t3 VALUES (204, 1);
+INSERT INTO t3 VALUES (205, 1);
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=201;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=202;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=204;
+UPDATE t3 SET b=b+1 WHERE a=203;
+UPDATE t3 SET b=b+1 WHERE a=205;
+UPDATE t3 SET b=b+1 WHERE a=205;
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 3
+202 4
+203 4
+204 4
+205 3
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 3
+202 4
+203 4
+204 4
+205 3
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_dbug;
+include/start_slave.inc
+*** Check getting deadlock killed inside open_binlog() during retry. ***
+connection server_2;
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill';
+SET @old_max= @@GLOBAL.max_relay_log_size;
+SET GLOBAL max_relay_log_size= 4096;
+connection server_1;
+SET @old_dbug= @@SESSION.debug_dbug;
+SET SESSION debug_dbug="+d,binlog_force_commit_id";
+SET @commit_id= 10210;
+Omit long queries that cause relaylog rotations and transaction retries...
+SET SESSION debug_dbug=@old_dbug;
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 6
+202 8
+203 7
+204 7
+205 5
+include/save_master_gtid.inc
+connection server_2;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+SELECT * FROM t3 WHERE a>=200 ORDER BY a;
+a b
+201 6
+202 8
+203 7
+204 7
+205 5
+include/stop_slave.inc
+SET GLOBAL debug_dbug= @old_debg;
+SET GLOBAL max_relay_log_size= @old_max;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_stop_slave.result b/mysql-test/suite/rpl/r/rpl_parallel_stop_slave.result
new file mode 100644
index 00000000000..6c9fd168e73
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_stop_slave.result
@@ -0,0 +1,85 @@
+*** Test STOP SLAVE in parallel mode ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+SET GLOBAL slave_parallel_mode='conservative';
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connect con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+connect con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,;
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
+CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+connection server_2;
+include/stop_slave.inc
+connection server_1;
+SET binlog_direct_non_transactional_updates=0;
+SET sql_log_bin=0;
+CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction");
+SET sql_log_bin=1;
+BEGIN;
+INSERT INTO t2 VALUES (20);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t2 VALUES (21);
+INSERT INTO t3 VALUES (20, 20);
+COMMIT;
+INSERT INTO t3 VALUES(21, 21);
+INSERT INTO t3 VALUES(22, 22);
+connection con_temp1;
+BEGIN;
+INSERT INTO t2 VALUES (21);
+connection server_2;
+START SLAVE;
+connection con_temp2;
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger";
+STOP SLAVE;
+connection con_temp1;
+SET debug_sync='now WAIT_FOR wait_for_done_waiting';
+ROLLBACK;
+connection con_temp2;
+SET GLOBAL debug_dbug=@old_dbug;
+SET debug_sync='RESET';
+connection server_2;
+include/wait_for_slave_to_stop.inc
+SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
+a
+20
+SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
+a
+20
+21
+SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
+a b
+20 20
+include/start_slave.inc
+SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
+a
+20
+SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
+a
+20
+21
+SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
+a b
+20 20
+21 21
+22 22
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+disconnect con_temp1;
+disconnect con_temp2;
+connection server_1;
+DROP TABLE t1,t2,t3;
+SET DEBUG_SYNC= 'RESET';
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_wrong_binlog_order.result b/mysql-test/suite/rpl/r/rpl_parallel_wrong_binlog_order.result
new file mode 100644
index 00000000000..f6781f64d30
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_wrong_binlog_order.result
@@ -0,0 +1,75 @@
+*** MDEV-6775: Wrong binlog order in parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=10;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
+INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6);
+connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+connect con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
+include/save_master_gtid.inc
+connection server_2;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log";
+SET @old_format=@@GLOBAL.binlog_format;
+SET GLOBAL binlog_format=ROW;
+SET GLOBAL slave_parallel_threads=0;
+SET GLOBAL slave_parallel_threads=10;
+connection con1;
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+UPDATE t4 SET b=NULL WHERE a=6;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued1';
+connection con2;
+SET @old_format= @@binlog_format;
+SET binlog_format= statement;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+DELETE FROM t4 WHERE b <= 3;
+connection server_1;
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+connection con1;
+SET binlog_format= @old_format;
+connection con2;
+SET binlog_format= @old_format;
+SET debug_sync='RESET';
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 NULL
+connection server_2;
+include/start_slave.inc
+SET debug_sync= 'now WAIT_FOR waiting';
+SELECT * FROM t4 ORDER BY a;
+a b
+1 NULL
+3 NULL
+4 4
+5 NULL
+6 NULL
+SET debug_sync= 'now SIGNAL cont';
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL binlog_format= @old_format;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+SET DEBUG_SYNC= 'RESET';
+connection server_1;
+DROP TABLE t4;
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+disconnect con2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_wrong_exec_master_pos.result b/mysql-test/suite/rpl/r/rpl_parallel_wrong_exec_master_pos.result
new file mode 100644
index 00000000000..47cfa5e08e2
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_wrong_exec_master_pos.result
@@ -0,0 +1,34 @@
+*** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
+include/master-slave.inc
+[connection master]
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+connection server_1;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+CREATE TABLE t5 (a INT PRIMARY KEY, b INT);
+INSERT INTO t5 VALUES (1,1);
+INSERT INTO t5 VALUES (2,2), (3,8);
+INSERT INTO t5 VALUES (4,16);
+connection server_2;
+test_check
+OK
+test_check
+OK
+connection server_1;
+FLUSH LOGS;
+connection server_2;
+test_check
+OK
+test_check
+OK
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t5;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations b/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations
index 8adc75e834f..bac7cb337c9 100644
--- a/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations
+++ b/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations
@@ -1,5 +1,4 @@
[nonparallel]
[parallel]
---slave-parallel-mode=conservative
--slave-parallel-threads=10
diff --git a/mysql-test/suite/rpl/t/rpl_mdev6386.test b/mysql-test/suite/rpl/t/rpl_mdev6386.test
index e85b1ae0132..e6fb72dc788 100644
--- a/mysql-test/suite/rpl/t/rpl_mdev6386.test
+++ b/mysql-test/suite/rpl/t/rpl_mdev6386.test
@@ -10,6 +10,7 @@ CREATE TABLE t1 (a INT PRIMARY KEY, b INT) Engine=InnoDB;
--source include/stop_slave.inc
# Provoke a duplicate key error on replication.
SET sql_log_bin= 0;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
INSERT INTO t1 VALUES (1, 2);
SET sql_log_bin= 1;
CHANGE MASTER TO master_use_gtid= current_pos;
diff --git a/mysql-test/suite/rpl/t/rpl_parallel.test b/mysql-test/suite/rpl/t/rpl_parallel.test
deleted file mode 100644
index ee39bfa7a39..00000000000
--- a/mysql-test/suite/rpl/t/rpl_parallel.test
+++ /dev/null
@@ -1 +0,0 @@
---source include/rpl_parallel.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test b/mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test
new file mode 100644
index 00000000000..c1f1b9bac43
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_analyze_table_hang.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_conflicts-slave.opt b/mysql-test/suite/rpl/t/rpl_parallel_conflicts-slave.opt
deleted file mode 100644
index af7bd138793..00000000000
--- a/mysql-test/suite/rpl/t/rpl_parallel_conflicts-slave.opt
+++ /dev/null
@@ -1 +0,0 @@
---slave_parallel_threads=40 --slave_parallel_mode=conservative --slave_transaction_retries=5
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test b/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test
index fc294f68197..0ba6a2b2dc1 100644
--- a/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test
+++ b/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test
@@ -15,7 +15,12 @@ CREATE TABLE t8 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
--connection server_2
--sync_with_master
--source include/stop_slave.inc
-
+SET @old_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode='conservative';
+SET @old_threads= @@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=40;
+SET @old_transaction_retries= @@GLOBAL.slave_transaction_retries;
+SET GLOBAL slave_transaction_retries=5;
# Using dbug error injection, we artificially create event groups with a lot of
# conflicting transactions in each event group. The bugs were originally seen
@@ -249,6 +254,9 @@ SELECT * FROM t7 ORDER BY a;
--source include/stop_slave.inc
SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_mode=@old_mode;
+SET GLOBAL slave_parallel_threads=@old_threads;
+SET GLOBAL slave_transaction_retries=@old_transaction_retries;
# Clean up.
--source include/start_slave.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test
new file mode 100644
index 00000000000..9ee06f59858
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_deadlock_corrupt_binlog.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_domain.test b/mysql-test/suite/rpl/t/rpl_parallel_domain.test
new file mode 100644
index 00000000000..f5864380f02
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_domain.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_domain.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test b/mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test
new file mode 100644
index 00000000000..5ddd2af323c
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_domain_slave_single_grp.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test b/mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test
new file mode 100644
index 00000000000..e2a41d0db7e
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_free_deferred_event.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test
new file mode 100644
index 00000000000..d9dc4dfd293
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_gco_wait_kill.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test b/mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test
new file mode 100644
index 00000000000..0756caca084
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_gtid_slave_pos_update_fail.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test b/mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test
new file mode 100644
index 00000000000..92c84d497a7
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_ignore_error_on_rotate.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test b/mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test
new file mode 100644
index 00000000000..e0226d9453e
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_incorrect_relay_pos.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test b/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test
new file mode 100644
index 00000000000..3838973c201
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_innodb_lock_conflict.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test b/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test
index 5929fad71df..981c6216376 100644
--- a/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test
+++ b/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test
@@ -99,6 +99,7 @@ eval SELECT MASTER_GTID_WAIT('$wait_pos');
# duplicate key error.
--connection con_temp1
COMMIT;
+CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
SET sql_log_bin=1;
--connection server_2
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test b/mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test
new file mode 100644
index 00000000000..de9dc7f782a
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_missed_error_handling.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_mode.test b/mysql-test/suite/rpl/t/rpl_parallel_mode.test
new file mode 100644
index 00000000000..afd9e038912
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_mode.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_mode.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test b/mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test
new file mode 100644
index 00000000000..7be26edabb8
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_partial_binlog_trans.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test b/mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test
new file mode 100644
index 00000000000..4529a268103
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_record_gtid_wakeup.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test b/mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test
new file mode 100644
index 00000000000..50b216b6f58
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_retry_deadlock.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test b/mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test
new file mode 100644
index 00000000000..f66375b7fb4
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_rollback_assert.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test b/mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test
new file mode 100644
index 00000000000..20919823945
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_single_grpcmt.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test
new file mode 100644
index 00000000000..7b0f9485e5e
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_slave_bgc_kill.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test
new file mode 100644
index 00000000000..64b4cb77dd4
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_stop_on_con_kill.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test b/mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test
new file mode 100644
index 00000000000..131ddc2efd9
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_stop_slave.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test b/mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test
new file mode 100644
index 00000000000..3c920e1539a
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_wrong_binlog_order.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test b/mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test
new file mode 100644
index 00000000000..9cd700f57fa
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test
@@ -0,0 +1 @@
+--source include/rpl_parallel_wrong_exec_master_pos.inc
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index b7f7615636b..09d8b4b7d1c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -536,7 +536,7 @@ ulong stored_program_cache_size= 0;
ulong opt_slave_parallel_threads= 0;
ulong opt_slave_domain_parallel_threads= 0;
-ulong opt_slave_parallel_mode= SLAVE_PARALLEL_CONSERVATIVE;
+ulong opt_slave_parallel_mode;
ulong opt_binlog_commit_wait_count= 0;
ulong opt_binlog_commit_wait_usec= 0;
ulong opt_slave_parallel_max_queued= 131072;
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index b167b849923..5d10cc661ca 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -24,7 +24,7 @@
#define TABLE_RULE_ARR_SIZE 16
Rpl_filter::Rpl_filter() :
- parallel_mode(SLAVE_PARALLEL_CONSERVATIVE),
+ parallel_mode(SLAVE_PARALLEL_OPTIMISTIC),
table_rules_on(0),
do_table_inited(0), ignore_table_inited(0),
wild_do_table_inited(0), wild_ignore_table_inited(0)
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 3441a1ae4b1..0d035d002c4 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2224,7 +2224,7 @@ static Sys_var_slave_parallel_mode Sys_slave_parallel_mode(
"\"minimal\" only parallelizes the commit steps of transactions. "
"\"none\" disables parallel apply completely.",
GLOBAL_VAR(opt_slave_parallel_mode), NO_CMD_LINE,
- slave_parallel_mode_names, DEFAULT(SLAVE_PARALLEL_CONSERVATIVE));
+ slave_parallel_mode_names, DEFAULT(SLAVE_PARALLEL_OPTIMISTIC));
static Sys_var_bit Sys_skip_parallel_replication(
1
0
[Commits] a49376056f9: MDEV-21383: Possible range plan is not used under certain conditions
by psergey 22 Dec '19
by psergey 22 Dec '19
22 Dec '19
revision-id: a49376056f9eeeb76f1818c0d8b9f9e006d4dfe3 (mariadb-10.3.10-2-ga49376056f9)
parent(s): ea9a7ef6ec0e3e24927fb1fc39e00cb526eec89c
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2019-12-23 01:13:38 +0300
message:
MDEV-21383: Possible range plan is not used under certain conditions
(10.3's variant of the fix)
make_join_select() has a section of code which starts with
"We plan to scan all rows. Check again if we should use an index."
the code in that section will [unnecessarily] re-run the range
optimizer using this condition:
condition_attached_to_current_table AND current_table's_ON_expr
Note that the original invocation of range optimizer in
make_join_statistics was done using the whole select's WHERE condition.
taking the whole select's WHERE condition and using multiple-equalities
allowed the range optimizer to do more inferences.
This fix uses a very conservative approach: we still re-run the range
optimizer, but we save the quick select we already have, and take the
best of the two quick selects.
---
mysql-test/main/distinct.result | 2 +-
mysql-test/main/group_min_max.result | 2 +-
sql/sql_select.cc | 15 +++++++++++++++
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/mysql-test/main/distinct.result b/mysql-test/main/distinct.result
index 70bce519ad2..9091d78d9fb 100644
--- a/mysql-test/main/distinct.result
+++ b/mysql-test/main/distinct.result
@@ -212,7 +212,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using index
explain SELECT distinct a from t3 order by a desc limit 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t3 index NULL a 5 NULL 40 Using index
+1 SIMPLE t3 range NULL a 5 NULL 10 Using index for group-by; Using temporary; Using filesort
explain SELECT distinct a,b from t3 order by a+1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort
diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result
index cfdf9ef9865..80de24e350c 100644
--- a/mysql-test/main/group_min_max.result
+++ b/mysql-test/main/group_min_max.result
@@ -2429,7 +2429,7 @@ EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE EXISTS
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by
EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 491e684f7a0..be0f85e9aa2 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -10670,6 +10670,11 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if (sel->cond && !sel->cond->fixed)
sel->cond->quick_fix_field();
+ // Move away the quick select (the first thing test_quick_select()
+ // will do is delete it anyway)
+ SQL_SELECT save_sel= *sel;
+ tab->select->quick=NULL;
+
if (sel->test_quick_select(thd, tab->keys,
((used_tables & ~ current_map) |
OUTER_REF_TABLE_BIT),
@@ -10697,6 +10702,16 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
else
sel->cond=orig_cond;
+ // If save_sel_copy has a better quick select than sel, put it
+ // back.
+ if (save_sel.quick &&
+ (!sel->quick || sel->quick->read_time > save_sel.read_time))
+ {
+ delete sel->quick;
+ *sel= save_sel;
+ save_sel.quick= NULL;
+ }
+
/* Fix for EXPLAIN */
if (sel->quick)
join->best_positions[i].records_read= (double)sel->quick->records;
1
0
21 Dec '19
revision-id: d7d7ee859c4fc35139034ac19adc8c9c18bf197f (mariadb-10.2.30-26-gd7d7ee859c4)
parent(s): c3824766c5788bf3aa0d1131e149dff187d41f2c
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2019-12-21 19:41:23 +0300
message:
MDEV-19901: Wrong window function calculation
Use a different approach to splitting window functions into groups which
can re-use the same data sorting.
Instead of sorting the window functions and then marking the bounds in
the list, partition window functions into groups directly.
---
mysql-test/r/win.result | 67 +++++++++--
mysql-test/t/win.test | 24 ++++
sql/sql_window.cc | 303 ++++++++++--------------------------------------
sql/sql_window.h | 7 +-
4 files changed, 148 insertions(+), 253 deletions(-)
diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result
index 2fe511d0e8b..7f08797c54c 100644
--- a/mysql-test/r/win.result
+++ b/mysql-test/r/win.result
@@ -2038,17 +2038,17 @@ row_number() over (order by pk desc) as r_desc,
row_number() over (order by pk asc) as r_asc
from t1;
pk r_desc r_asc
-11 1 11
-10 2 10
-9 3 9
-8 4 8
-7 5 7
-6 6 6
-5 7 5
-4 8 4
-3 9 3
-2 10 2
1 11 1
+2 10 2
+3 9 3
+4 8 4
+5 7 5
+6 6 6
+7 5 7
+8 4 8
+9 3 9
+10 2 10
+11 1 11
drop table t1;
#
# MDEV-10874: two window functions with compatible sorting
@@ -3653,5 +3653,52 @@ COUNT(*) OVER () MOD(MIN(i),2)
3 1
drop table t1;
#
+# MDEV-19901: Wrong window function calculation
+#
+create table t1 (a int, b int);
+insert into t1 values (1, 1), (2, 1), (3, 2), (4, 2);
+select
+sum(a) over (),
+sum(a) over (partition by b) c,
+sum(a) over (order by a) d
+from t1
+order by a;
+sum(a) over () c d
+10 3 1
+10 3 3
+10 7 6
+10 7 10
+explain format=json
+select
+sum(a) over (),
+sum(a) over (partition by b) c,
+sum(a) over (order by a) d
+from t1;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "window_functions_computation": {
+ "sorts": {
+ "filesort": {
+ "sort_key": "t1.b"
+ },
+ "filesort": {
+ "sort_key": "t1.a"
+ }
+ },
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ }
+ }
+}
+drop table t1;
+#
# End of 10.2 tests
#
diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test
index 1e302722b99..cb07d16e197 100644
--- a/mysql-test/t/win.test
+++ b/mysql-test/t/win.test
@@ -2361,6 +2361,30 @@ INSERT INTO t1 VALUES (1),(0),(1),(2),(0),(1),(2),(1),(2);
SELECT DISTINCT COUNT(*) OVER (), MOD(MIN(i),2) FROM t1 GROUP BY i ;
drop table t1;
+--echo #
+--echo # MDEV-19901: Wrong window function calculation
+--echo #
+
+create table t1 (a int, b int);
+insert into t1 values (1, 1), (2, 1), (3, 2), (4, 2);
+
+select
+ sum(a) over (),
+ sum(a) over (partition by b) c,
+ sum(a) over (order by a) d
+from t1
+ order by a;
+
+explain format=json
+select
+ sum(a) over (),
+ sum(a) over (partition by b) c,
+ sum(a) over (order by a) d
+from t1;
+
+
+drop table t1;
+
--echo #
--echo # End of 10.2 tests
--echo #
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index b258b8f56c9..a9a979bb664 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -6,6 +6,10 @@
#include "sql_window.h"
#include "my_dbug.h"
+typedef List<Item_window_func> Window_func_list;
+
+static List<Window_func_list>
+split_window_funcs_into_sorts(List<Item_window_func> *win_func_list);
bool
Window_spec::check_window_names(List_iterator_fast<Window_spec> &it)
@@ -368,84 +372,6 @@ int compare_order_lists(SQL_I_List<ORDER> *part_list1,
return CMP_EQ;
}
-
-static
-int compare_window_frame_bounds(Window_frame_bound *win_frame_bound1,
- Window_frame_bound *win_frame_bound2,
- bool is_bottom_bound)
-{
- int res;
- if (win_frame_bound1->precedence_type != win_frame_bound2->precedence_type)
- {
- res= win_frame_bound1->precedence_type > win_frame_bound2->precedence_type ?
- CMP_GT : CMP_LT;
- if (is_bottom_bound)
- res= -res;
- return res;
- }
-
- if (win_frame_bound1->is_unbounded() && win_frame_bound2->is_unbounded())
- return CMP_EQ;
-
- if (!win_frame_bound1->is_unbounded() && !win_frame_bound2->is_unbounded())
- {
- if (win_frame_bound1->offset->eq(win_frame_bound2->offset, true))
- return CMP_EQ;
- else
- {
- res= strcmp(win_frame_bound1->offset->name,
- win_frame_bound2->offset->name);
- res= res > 0 ? CMP_GT : CMP_LT;
- if (is_bottom_bound)
- res= -res;
- return res;
- }
- }
-
- /*
- Here we have:
- win_frame_bound1->is_unbounded() != win_frame_bound1->is_unbounded()
- */
- return is_bottom_bound != win_frame_bound1->is_unbounded() ? CMP_LT : CMP_GT;
-}
-
-
-static
-int compare_window_frames(Window_frame *win_frame1,
- Window_frame *win_frame2)
-{
- int cmp;
-
- if (win_frame1 == win_frame2)
- return CMP_EQ;
-
- if (!win_frame1)
- return CMP_LT;
-
- if (!win_frame2)
- return CMP_GT;
-
- if (win_frame1->units != win_frame2->units)
- return win_frame1->units > win_frame2->units ? CMP_GT : CMP_LT;
-
- cmp= compare_window_frame_bounds(win_frame1->top_bound,
- win_frame2->top_bound,
- false);
- if (cmp)
- return cmp;
-
- cmp= compare_window_frame_bounds(win_frame1->bottom_bound,
- win_frame2->bottom_bound,
- true);
- if (cmp)
- return cmp;
-
- if (win_frame1->exclusion != win_frame2->exclusion)
- return win_frame1->exclusion > win_frame2->exclusion ? CMP_GT_C : CMP_LT_C;
-
- return CMP_EQ;
-}
-
static
int compare_window_spec_joined_lists(Window_spec *win_spec1,
Window_spec *win_spec2)
@@ -459,147 +385,68 @@ int compare_window_spec_joined_lists(Window_spec *win_spec1,
return cmp;
}
-
-static
-int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
- Item_window_func *win_func2,
- void *arg)
-{
- int cmp;
- Window_spec *win_spec1= win_func1->window_spec;
- Window_spec *win_spec2= win_func2->window_spec;
- if (win_spec1 == win_spec2)
- return CMP_EQ;
- cmp= compare_order_lists(win_spec1->partition_list,
- win_spec2->partition_list);
- if (cmp == CMP_EQ)
- {
- /*
- Partition lists contain the same elements.
- Let's use only one of the lists.
- */
- if (!win_spec1->name() && win_spec2->name())
- win_spec1->partition_list= win_spec2->partition_list;
- else
- win_spec2->partition_list= win_spec1->partition_list;
-
- cmp= compare_order_lists(win_spec1->order_list,
- win_spec2->order_list);
-
- if (cmp != CMP_EQ)
- return cmp;
-
- /*
- Order lists contain the same elements.
- Let's use only one of the lists.
- */
- if (!win_spec1->name() && win_spec2->name())
- win_spec1->order_list= win_spec2->order_list;
- else
- win_spec2->order_list= win_spec1->order_list;
-
- cmp= compare_window_frames(win_spec1->window_frame,
- win_spec2->window_frame);
-
- if (cmp != CMP_EQ)
- return cmp;
-
- /* Window frames are equal. Let's use only one of them. */
- if (!win_spec1->name() && win_spec2->name())
- win_spec1->window_frame= win_spec2->window_frame;
- else
- win_spec2->window_frame= win_spec1->window_frame;
-
- return CMP_EQ;
- }
-
- if (cmp == CMP_GT || cmp == CMP_LT)
- return cmp;
-
- /* one of the partitions lists is the proper beginning of the another */
- cmp= compare_window_spec_joined_lists(win_spec1, win_spec2);
-
- if (CMP_LT_C <= cmp && cmp <= CMP_GT_C)
- cmp= win_spec1->partition_list->elements <
- win_spec2->partition_list->elements ? CMP_GT_C : CMP_LT_C;
-
- return cmp;
-}
-
-
-#define SORTORDER_CHANGE_FLAG 1
-#define PARTITION_CHANGE_FLAG 2
-#define FRAME_CHANGE_FLAG 4
-
-typedef int (*Item_window_func_cmp)(Item_window_func *f1,
- Item_window_func *f2,
- void *arg);
/*
@brief
- Sort window functions so that those that can be computed together are
- adjacent.
+ Split window functions into lists that can share the sorting.
- @detail
- Sort window functions by their
- - required sorting order,
- - partition list,
- - window frame compatibility.
+ @param win_func_list List of all window functions in the select.
- The changes between the groups are marked by setting item_window_func->marker.
+ @detail
+ Split the list of window functions into multiple lists. Each of the
+ new lists only includes functions that can be computed using
+ the sorting from the first element of the list.
+
+ @note
+ Within one sort, it's also possible to re-use
+ - partition bound detector (for equivalent PARTITION BY clauses)
+ - window frame cursors
+ This is not implemented currently, but could use the same approach.
*/
-static
-void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list)
+static List<Window_func_list>
+split_window_funcs_into_sorts(List<Item_window_func> *win_func_list)
{
- if (win_func_list->elements == 0)
- return;
+ List<Window_func_list> sorts;
- bubble_sort<Item_window_func>(win_func_list,
- compare_window_funcs_by_window_specs,
- NULL);
-
- List_iterator_fast<Item_window_func> it(*win_func_list);
- Item_window_func *prev= it++;
- prev->marker= SORTORDER_CHANGE_FLAG |
- PARTITION_CHANGE_FLAG |
- FRAME_CHANGE_FLAG;
- Item_window_func *curr;
- while ((curr= it++))
- {
- Window_spec *win_spec_prev= prev->window_spec;
- Window_spec *win_spec_curr= curr->window_spec;
- curr->marker= 0;
- if (!(win_spec_prev->partition_list == win_spec_curr->partition_list &&
- win_spec_prev->order_list == win_spec_curr->order_list))
+ List_iterator<Item_window_func> win_func_it(*win_func_list);
+ Item_window_func *new_win_func;
+ while ((new_win_func= win_func_it++))
+ {
+ List_iterator<Window_func_list> sorts_it(sorts);
+ Window_func_list *wfunc_list;
+ bool added= false;
+ while ((wfunc_list= sorts_it++))
{
- int cmp;
- if (win_spec_prev->partition_list == win_spec_curr->partition_list)
- cmp= compare_order_lists(win_spec_prev->order_list,
- win_spec_curr->order_list);
+ Item_window_func *win_func= wfunc_list->head();
+ int r= compare_window_spec_joined_lists(win_func->window_spec,
+ new_win_func->window_spec);
+
+ // maintain the invariant; the first element in the list uses the most
+ // restrictive sorting
+
+ if (r == CMP_EQ || r == CMP_GT_C)
+ wfunc_list->push_back(new_win_func);
+ else if (r == CMP_LT_C)
+ wfunc_list->push_front(new_win_func);
else
- cmp= compare_window_spec_joined_lists(win_spec_prev, win_spec_curr);
- if (!(CMP_LT_C <= cmp && cmp <= CMP_GT_C))
- {
- curr->marker= SORTORDER_CHANGE_FLAG |
- PARTITION_CHANGE_FLAG |
- FRAME_CHANGE_FLAG;
- }
- else if (win_spec_prev->partition_list != win_spec_curr->partition_list)
- {
- curr->marker|= PARTITION_CHANGE_FLAG | FRAME_CHANGE_FLAG;
- }
+ continue; // This element of sorts is not a match
+
+ added= true;
+ break;
}
- else if (win_spec_prev->window_frame != win_spec_curr->window_frame)
- curr->marker|= FRAME_CHANGE_FLAG;
- prev= curr;
+ if (!added)
+ {
+ // We didn't find a suitable sort to add window function to.
+ // Create a new sort and put it there.
+ Window_func_list *newlist = new Window_func_list;
+ newlist->push_back(new_win_func);
+ sorts.push_back(newlist);
+ }
}
+ return sorts;
}
-
-/////////////////////////////////////////////////////////////////////////////
-
-
/////////////////////////////////////////////////////////////////////////////
// Window Frames support
/////////////////////////////////////////////////////////////////////////////
@@ -2819,42 +2666,18 @@ bool Window_funcs_sort::exec(JOIN *join, bool keep_filesort_result)
bool Window_funcs_sort::setup(THD *thd, SQL_SELECT *sel,
- List_iterator<Item_window_func> &it,
+ List<Item_window_func> *window_funcs,
JOIN_TAB *join_tab)
{
- Window_spec *spec;
- Item_window_func *win_func= it.peek();
- Item_window_func *win_func_with_longest_order= NULL;
- int longest_order_elements= -1;
-
- /* The iterator should point to a valid function at the start of execution. */
- DBUG_ASSERT(win_func);
- do
- {
- spec= win_func->window_spec;
- int win_func_order_elements= spec->partition_list->elements +
- spec->order_list->elements;
- if (win_func_order_elements > longest_order_elements)
- {
- win_func_with_longest_order= win_func;
- longest_order_elements= win_func_order_elements;
- }
+ List_iterator<Item_window_func> it(*window_funcs);
+ Item_window_func *win_func;
+ while ((win_func = it++))
+ {
if (runner.add_function_to_run(win_func))
return true;
- it++;
- win_func= it.peek();
- } while (win_func && !(win_func->marker & SORTORDER_CHANGE_FLAG));
-
- /*
- The sort criteria must be taken from the last win_func in the group of
- adjacent win_funcs that do not have SORTORDER_CHANGE_FLAG. This is
- because the sort order must be the most specific sorting criteria defined
- within the window function group. This ensures that we sort the table
- in a way that the result is valid for all window functions belonging to
- this Window_funcs_sort.
- */
- spec= win_func_with_longest_order->window_spec;
+ }
+ Window_spec *spec= window_funcs->head()->window_spec;
ORDER* sort_order= concat_order_lists(thd->mem_root,
spec->partition_list->first,
spec->order_list->first);
@@ -2892,7 +2715,8 @@ bool Window_funcs_computation::setup(THD *thd,
List<Item_window_func> *window_funcs,
JOIN_TAB *tab)
{
- order_window_funcs_by_window_specs(window_funcs);
+ List<Window_func_list> wfunc_sorts=
+ split_window_funcs_into_sorts(window_funcs);
SQL_SELECT *sel= NULL;
/*
@@ -2908,11 +2732,12 @@ bool Window_funcs_computation::setup(THD *thd,
}
Window_funcs_sort *srt;
- List_iterator<Item_window_func> iter(*window_funcs);
- while (iter.peek())
+ List_iterator<Window_func_list> it(wfunc_sorts);
+ Window_func_list *wfunc_list;
+ while ((wfunc_list= it++))
{
if (!(srt= new Window_funcs_sort()) ||
- srt->setup(thd, sel, iter, tab))
+ srt->setup(thd, sel, wfunc_list, tab))
{
return true;
}
diff --git a/sql/sql_window.h b/sql/sql_window.h
index e0c1563e5bb..628ab908f14 100644
--- a/sql/sql_window.h
+++ b/sql/sql_window.h
@@ -163,9 +163,8 @@ int setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
class Frame_cursor;
/*
- This handles computation of one window function.
-
- Currently, we make a spearate filesort() call for each window function.
+ This handles computation of several window functions which require the same
+ sorting of the dataset.
*/
class Window_func_runner : public Sql_alloc
@@ -193,7 +192,7 @@ class Window_func_runner : public Sql_alloc
class Window_funcs_sort : public Sql_alloc
{
public:
- bool setup(THD *thd, SQL_SELECT *sel, List_iterator<Item_window_func> &it,
+ bool setup(THD *thd, SQL_SELECT *sel, List<Item_window_func> *window_funcs,
st_join_table *join_tab);
bool exec(JOIN *join, bool keep_filesort_result);
void cleanup() { delete filesort; }
1
0
18 Dec '19
revision-id: 409cc5bda27a518c244e82e9e24c61fee9f1f8a3 (mariadb-10.1.41-106-g409cc5bda27)
parent(s): d930422e9e84aa1bc265963225dd29295203e9d3
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-12-18 23:41:32 +0530
message:
MDEV-20922: Adding an order by changes the query results
For Item_direct_ref and its subclasses, get value from val_* methods
instead of result* family
The val_* methods gets value of item on which it is referred.
---
mysql-test/r/group_by.result | 16 ++++++++++++++++
mysql-test/t/group_by.test | 14 ++++++++++++++
sql/item.h | 6 ++++++
3 files changed, 36 insertions(+)
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index eb730a8c954..bde24afa6e3 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -2792,3 +2792,19 @@ SELECT 1 IN ( SELECT COUNT( DISTINCT f2 ) FROM t1 WHERE f1 <= 4 );
1 IN ( SELECT COUNT( DISTINCT f2 ) FROM t1 WHERE f1 <= 4 )
0
drop table t1;
+#
+# MDEV-20922: Adding an order by changes the query results
+#
+CREATE TABLE t1(a int, b int);
+INSERT INTO t1 values (1, 100), (2, 200), (3, 100), (4, 200);
+create view v1 as select a, b+1 as x from t1;
+select x, count(distinct a) as y from v1 group by x order by y;
+x y
+101 2
+201 2
+select b+1 as x, count(distinct a) as y from t1 group by x order by y;
+x y
+101 2
+201 2
+drop view v1;
+drop table t1;
diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test
index 0401ad9780c..b3e12a93147 100644
--- a/mysql-test/t/group_by.test
+++ b/mysql-test/t/group_by.test
@@ -1915,3 +1915,17 @@ INSERT INTO t1 VALUES (0,'foo'),(1,'bar');
SELECT 1 IN ( SELECT COUNT( DISTINCT f2 ) FROM t1 WHERE f1 <= 4 );
drop table t1;
+--echo #
+--echo # MDEV-20922: Adding an order by changes the query results
+--echo #
+
+CREATE TABLE t1(a int, b int);
+INSERT INTO t1 values (1, 100), (2, 200), (3, 100), (4, 200);
+
+create view v1 as select a, b+1 as x from t1;
+
+select x, count(distinct a) as y from v1 group by x order by y;
+select b+1 as x, count(distinct a) as y from t1 group by x order by y;
+
+drop view v1;
+drop table t1;
diff --git a/sql/item.h b/sql/item.h
index fb11064f122..bb8dc788f81 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -4146,6 +4146,12 @@ class Item_direct_ref :public Item_ref
bool val_bool();
bool is_null();
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ double val_result() { return val_real(); }
+ longlong val_int_result() { return val_int(); }
+ String *str_result(String* tmp) { return val_str(tmp); }
+ my_decimal *val_decimal_result(my_decimal *val)
+ { return val_decimal(val); }
+ bool val_bool_result() { return val_bool(); }
virtual Ref_Type ref_type() { return DIRECT_REF; }
};
1
0
[Commits] 8681b0e191d: MDEV-21341: Fix UBSAN failures, part 8: fix error in compare_fields_by_table_order
by psergey 18 Dec '19
by psergey 18 Dec '19
18 Dec '19
revision-id: 8681b0e191ded6e2061cd2b65b18d8d6d9a85491 (mariadb-10.1.43-38-g8681b0e191d)
parent(s): 6b24843647540d40d6115dd6b0e2a5a746ea03ca
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2019-12-18 21:53:19 +0300
message:
MDEV-21341: Fix UBSAN failures, part 8: fix error in compare_fields_by_table_order
Dont assign Item_field variables to point to Item_string objects (even if we
don't make any dangerous calls for them).
---
sql/sql_select.cc | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 40941294013..2358615affc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -13669,12 +13669,16 @@ static int compare_fields_by_table_order(Item *field1,
{
int cmp= 0;
bool outer_ref= 0;
- Item_field *f1= (Item_field *) (field1->real_item());
- Item_field *f2= (Item_field *) (field2->real_item());
- if (field1->const_item() || f1->const_item())
+ Item *field1_real= field1->real_item();
+ Item *field2_real= field2->real_item();
+
+ if (field1->const_item() || field1_real->const_item())
return 1;
- if (field2->const_item() || f2->const_item())
+ if (field2->const_item() || field2_real->const_item())
return -1;
+
+ Item_field *f1= (Item_field *) field1_real;
+ Item_field *f2= (Item_field *) field2_real;
if (f2->used_tables() & OUTER_REF_TABLE_BIT)
{
outer_ref= 1;
1
0
Re: [Commits] f72427f463d: MDEV-20923:UBSAN: member access within address Б─╕ which does not point to an object of type 'xid_count_per_binlog'
by andrei.elkinï¼ pp.inet.fi 17 Dec '19
by andrei.elkinï¼ pp.inet.fi 17 Dec '19
17 Dec '19
Sujatha, Kristian, howdy.
Sorry, I managed to sent my view without actually cc-ing Kristian, as claimed.
X-From-Line: nobody Wed Nov 27 19:27:51 2019
From: Andrei Elkin <andrei.elkin(a)mariadb.com>
To: sujatha <sujatha.sivakumar(a)mariadb.com>
Cc: <commits(a)mariadb.org>, <maria-developers(a)lists.launchpad.net>
Subject: Re: f72427f463d: MDEV-20923:UBSAN: member access within address
Let me try that again now.
Kristian, the question was about `xid_count_per_binlog' struct
comment -- ..
struct xid_count_per_binlog : public ilink {
char *binlog_name;
uint binlog_name_len;
ulong binlog_id;
/* Total prepared XIDs and pending checkpoint requests in this binlog. */
long xid_count;
/* For linking in requests to the binlog background thread. */
xid_count_per_binlog *next_in_queue;
xid_count_per_binlog(); /* Give link error if constructor used. */
.. -----------------------------^
};
Now I am guessing a constructor was attempted to fail out.. Was that
related to de-POD-ing of the object ('cos of the constructor)? It's
pretty obscure.
We would appreciate your explanation.
The former review mail is quoted (except one more [@]-marked view note, Sujatha) further.
Cheers,
Andrei
-------------------------------------------------------------------------------
Sujatha, hello.
The patch looks quite good. I have two suggestions though.
The first is to match the destructor's free() with actual allocation (of what is to be
freed) in the new parameterized constructor.
And 2nd-ly, I suggest to leave the explicit zero argument constructor
intact. Kristian is cc-d to help us to decide.
My comments are below.
Cheers,
Andrei
sujatha <sujatha.sivakumar(a)mariadb.com> writes:
> revision-id: f72427f463d316a54ebf87c2e84c73947e3c5fe4 (mariadb-10.1.43-5-gf72427f463d)
> parent(s): 13db50fc03e7312e6c01b06c7e4af69f69ba5382
> author: Sujatha
> committer: Sujatha
> timestamp: 2019-11-12 16:11:16 +0530
> message:
>
> MDEV-20923:UBSAN: member access within address … which does not point to an object of type 'xid_count_per_binlog'
>
> Problem:
> -------
> Accessing a member within 'xid_count_per_binlog' structure results in
> following error when 'UBSAN' is enabled.
>
> member access within address 0xXXX which does not point to an object of type
> 'xid_count_per_binlog'
>
> Analysis:
> ---------
> The problem appears to be that no constructor for 'xid_count_per_binlog' is
> being called, and thus the vtable will not be initialized.
>
> Fix:
> ---
> Defined a parameterized constructor for 'xid_count_per_binlog' class.
>
> ---
> sql/log.cc | 28 ++++++++++++++--------------
> sql/log.h | 9 ++++++++-
> 2 files changed, 22 insertions(+), 15 deletions(-)
>
> diff --git a/sql/log.cc b/sql/log.cc
> index acf1f8f8a9c..2b8b67febef 100644
> --- a/sql/log.cc
> +++ b/sql/log.cc
> @@ -3216,7 +3216,7 @@ void MYSQL_BIN_LOG::cleanup()
> DBUG_ASSERT(!binlog_xid_count_list.head());
> WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::cleanup(): Removing xid_list_entry "
> "for %s (%lu)", b);
> - my_free(b);
> + delete b;
> }
>
> mysql_mutex_destroy(&LOCK_log);
> @@ -3580,17 +3580,17 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
> */
> uint off= dirname_length(log_file_name);
> uint len= strlen(log_file_name) - off;
> - char *entry_mem, *name_mem;
> - if (!(new_xid_list_entry = (xid_count_per_binlog *)
> - my_multi_malloc(MYF(MY_WME),
> - &entry_mem, sizeof(xid_count_per_binlog),
> - &name_mem, len,
> - NULL)))
> + char *name_mem;
> + name_mem= (char *) my_malloc(len, MYF(MY_ZEROFILL));
> + if (!name_mem)
> goto err;
> memcpy(name_mem, log_file_name+off, len);
That is both my_malloc and memcpy to go into the new constructor to
match [*] (find the label below).
> - new_xid_list_entry->binlog_name= name_mem;
> - new_xid_list_entry->binlog_name_len= len;
> - new_xid_list_entry->xid_count= 0;
> + new_xid_list_entry= new xid_count_per_binlog(name_mem, (int)len);
> + if (!new_xid_list_entry)
> + {
> + my_free(name_mem);
> + goto err;
> + }
>
> /*
> Find the name for the Initial binlog checkpoint.
> @@ -3711,7 +3711,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
> {
> WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::open(): Removing xid_list_entry for "
> "%s (%lu)", b);
> - my_free(binlog_xid_count_list.get());
> + delete binlog_xid_count_list.get();
> }
> mysql_cond_broadcast(&COND_xid_list);
> WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::open(): Adding new xid_list_entry for "
> @@ -3758,7 +3758,7 @@ Turning logging off for the whole duration of the MySQL server process. \
> To turn it on again: fix the cause, \
> shutdown the MySQL server and restart it.", name, errno);
> if (new_xid_list_entry)
> - my_free(new_xid_list_entry);
> + delete new_xid_list_entry;
[@] With `delete` we don't need the non-null check: `if()` to remove.
> if (file >= 0)
> mysql_file_close(file, MYF(0));
> close(LOG_CLOSE_INDEX);
> @@ -4252,7 +4252,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log,
> DBUG_ASSERT(b->xid_count == 0);
> WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::reset_logs(): Removing "
> "xid_list_entry for %s (%lu)", b);
> - my_free(binlog_xid_count_list.get());
> + delete binlog_xid_count_list.get();
> }
> mysql_cond_broadcast(&COND_xid_list);
> reset_master_pending--;
> @@ -9736,7 +9736,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
> break;
> WSREP_XID_LIST_ENTRY("TC_LOG_BINLOG::mark_xid_done(): Removing "
> "xid_list_entry for %s (%lu)", b);
> - my_free(binlog_xid_count_list.get());
> + delete binlog_xid_count_list.get();
> }
>
> mysql_mutex_unlock(&LOCK_xid_list);
> diff --git a/sql/log.h b/sql/log.h
> index b4c9b24a3a9..30a55e577a4 100644
> --- a/sql/log.h
> +++ b/sql/log.h
> @@ -587,7 +587,14 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
> long xid_count;
> /* For linking in requests to the binlog background thread. */
> xid_count_per_binlog *next_in_queue;
> - xid_count_per_binlog(); /* Give link error if constructor used. */
Maybe we should leave it as it seems to be for catching inadvertent
object constructions.
I'm cc-ing Kristian to clear out.
> + xid_count_per_binlog(char *log_file_name, uint log_file_name_len)
> + :binlog_name(log_file_name), binlog_name_len(log_file_name_len),
> + binlog_id(0), xid_count(0)
> + {}
> + ~xid_count_per_binlog()
> + {
> + my_free(binlog_name);
[*]
> + }
> };
> I_List<xid_count_per_binlog> binlog_xid_count_list;
> mysql_mutex_t LOCK_binlog_background_thread;
> _______________________________________________
> commits mailing list
> commits(a)mariadb.org
> https://lists.askmonty.org/cgi-bin/mailman/listinfo/commits
1
0
[Commits] 176f446338f: MDEV-21087: ER_SLAVE_INCIDENT arrives at slave without failure specifics
by sujatha 17 Dec '19
by sujatha 17 Dec '19
17 Dec '19
revision-id: 176f446338f5374233522b2e185e1d0acc422ffd (mariadb-10.2.30-21-g176f446338f)
parent(s): 8129ff14407826d54745346c552fadf3d292a0d8
author: Sujatha
committer: Sujatha
timestamp: 2019-12-17 17:54:27 +0530
message:
MDEV-21087: ER_SLAVE_INCIDENT arrives at slave without failure specifics
Problem:
=======
Issue 1:
Incident event is reported for transactions which are rolled back successfully.
Issue 2:
When the mariadb slave (error) stops at receiving the incident event there's
no description of what led to it. Neither in the event nor in the master's
error log.
Analysis:
=========
Incident events are logged when a multi statement transaction specific changes
cannot be safely rolled back. In reported scenario a big multi statement
transaction is in progress and it makes use of innodb transactional engine.
Row based replication is being used. At the time of writing the annotate event
for the multi statement transaction the binary log cache size exceeds the
configured max_binlog_cache_size. Hence write to binary log fails. The write
error handling code generates an incident event and writes to binary log. This
stops the slave. The error code is propagated to the callers and transaction
is rolled back. Ideally binlog write error handling code should restrict
incident event reporting only for cases where clean rollback is not possible.
At the time of reporting incident event the actual error message which lead to
incident should also be written to server error log for debugging purpose.
Fix:
===
Report incident event in cases where transactions cannot be safely rolledback.
Write the error message into the error log.
@sql/handler.cc
Added new variable "stmt_modified_non_trans_table" to identify modification to
non transactional tables as "thd->transaction.stmt.modified_non_trans_table"
and "thd->transaction.all.modified_non_trans_table" will be set at the later
stage of execution. Annotate/Table_map events are written at the starting
stage of transaction execution. i.e In a multi statement transaction when the
first statement execution is complete its changes are written to binary log.
At this stage the Annotate/Table_map events are written.
To set "stmt_modified_non_trans_table" iterate through the list of tables
modified by the transaction and see if they are transactional or not. If table
is non transactional and it has write mode lock then set this variable to
true. Upon event write error check for the above flag and report incident
event.
@sql/log.cc
Report incident event if "stmt_modified_non_trans_table" variable is set.
In "write_incident" code print thd->error_message() to server error log.
---
.../extra/binlog_tests/binlog_write_error.inc | 2 +
.../extra/rpl_tests/rpl_binlog_max_cache_size.test | 3 +
mysql-test/suite/binlog/r/binlog_bug23533.result | 1 +
.../suite/binlog/r/binlog_write_error.result | 1 +
mysql-test/suite/binlog/t/binlog_bug23533.test | 2 +-
.../binlog_encryption/binlog_write_error.result | 1 +
.../rpl_mixed_binlog_max_cache_size.result | 2 +
mysql-test/suite/rpl/r/rpl_mdev-11092.result | 70 +++++++++++-
.../rpl/r/rpl_mixed_binlog_max_cache_size.result | 2 +
.../rpl/r/rpl_stm_binlog_max_cache_size.result | 2 +
mysql-test/suite/rpl/t/rpl_mdev-11092.test | 119 ++++++++++++++++++++-
sql/handler.cc | 26 ++++-
sql/log.cc | 54 +++++++---
sql/sql_class.h | 3 +-
14 files changed, 267 insertions(+), 21 deletions(-)
diff --git a/mysql-test/extra/binlog_tests/binlog_write_error.inc b/mysql-test/extra/binlog_tests/binlog_write_error.inc
index fa3ba087a7e..be5e9e0cfea 100644
--- a/mysql-test/extra/binlog_tests/binlog_write_error.inc
+++ b/mysql-test/extra/binlog_tests/binlog_write_error.inc
@@ -38,6 +38,8 @@ DROP TRIGGER IF EXISTS tr2;
DROP VIEW IF EXISTS v1, v2;
enable_warnings;
+call mtr.add_suppression("Write to binary log failed: Error writing file*");
+
--echo #
--echo # Test injecting binlog write error when executing queries
--echo #
diff --git a/mysql-test/extra/rpl_tests/rpl_binlog_max_cache_size.test b/mysql-test/extra/rpl_tests/rpl_binlog_max_cache_size.test
index 0f46b00f683..351b464de57 100644
--- a/mysql-test/extra/rpl_tests/rpl_binlog_max_cache_size.test
+++ b/mysql-test/extra/rpl_tests/rpl_binlog_max_cache_size.test
@@ -22,6 +22,9 @@
#
########################################################################################
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* ");
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* ");
+
let $old_max_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_cache_size", Value, 1);
let $old_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "binlog_cache_size", Value, 1);
diff --git a/mysql-test/suite/binlog/r/binlog_bug23533.result b/mysql-test/suite/binlog/r/binlog_bug23533.result
index cc9799506c3..aa357b58f2c 100644
--- a/mysql-test/suite/binlog/r/binlog_bug23533.result
+++ b/mysql-test/suite/binlog/r/binlog_bug23533.result
@@ -1,3 +1,4 @@
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.*");
SET AUTOCOMMIT=0;
CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b TEXT, PRIMARY KEY(a)) ENGINE=InnoDB;
SELECT COUNT(*) FROM t1;
diff --git a/mysql-test/suite/binlog/r/binlog_write_error.result b/mysql-test/suite/binlog/r/binlog_write_error.result
index 2606a9f40b3..ec1a701bd0e 100644
--- a/mysql-test/suite/binlog/r/binlog_write_error.result
+++ b/mysql-test/suite/binlog/r/binlog_write_error.result
@@ -9,6 +9,7 @@ DROP PROCEDURE IF EXISTS p2;
DROP TRIGGER IF EXISTS tr1;
DROP TRIGGER IF EXISTS tr2;
DROP VIEW IF EXISTS v1, v2;
+call mtr.add_suppression("Write to binary log failed: Error writing file*");
#
# Test injecting binlog write error when executing queries
#
diff --git a/mysql-test/suite/binlog/t/binlog_bug23533.test b/mysql-test/suite/binlog/t/binlog_bug23533.test
index ca610e399e4..a77497115e5 100644
--- a/mysql-test/suite/binlog/t/binlog_bug23533.test
+++ b/mysql-test/suite/binlog/t/binlog_bug23533.test
@@ -6,7 +6,7 @@
--source include/have_innodb.inc
--source include/have_log_bin.inc
--source include/have_binlog_format_row.inc
-
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.*");
SET AUTOCOMMIT=0;
# Create 1st table
diff --git a/mysql-test/suite/binlog_encryption/binlog_write_error.result b/mysql-test/suite/binlog_encryption/binlog_write_error.result
index 2606a9f40b3..ec1a701bd0e 100644
--- a/mysql-test/suite/binlog_encryption/binlog_write_error.result
+++ b/mysql-test/suite/binlog_encryption/binlog_write_error.result
@@ -9,6 +9,7 @@ DROP PROCEDURE IF EXISTS p2;
DROP TRIGGER IF EXISTS tr1;
DROP TRIGGER IF EXISTS tr2;
DROP VIEW IF EXISTS v1, v2;
+call mtr.add_suppression("Write to binary log failed: Error writing file*");
#
# Test injecting binlog write error when executing queries
#
diff --git a/mysql-test/suite/binlog_encryption/rpl_mixed_binlog_max_cache_size.result b/mysql-test/suite/binlog_encryption/rpl_mixed_binlog_max_cache_size.result
index 388c8e67b68..d302e73f15c 100644
--- a/mysql-test/suite/binlog_encryption/rpl_mixed_binlog_max_cache_size.result
+++ b/mysql-test/suite/binlog_encryption/rpl_mixed_binlog_max_cache_size.result
@@ -1,6 +1,8 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* ");
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* ");
SET GLOBAL max_binlog_cache_size = 4096;
SET GLOBAL binlog_cache_size = 4096;
SET GLOBAL max_binlog_stmt_cache_size = 4096;
diff --git a/mysql-test/suite/rpl/r/rpl_mdev-11092.result b/mysql-test/suite/rpl/r/rpl_mdev-11092.result
index 90b809477b2..ef392762eef 100644
--- a/mysql-test/suite/rpl/r/rpl_mdev-11092.result
+++ b/mysql-test/suite/rpl/r/rpl_mdev-11092.result
@@ -2,6 +2,9 @@ include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
call mtr.add_suppression("Slave SQL: The incident LOST_EVENTS occured on the master. .*");
+call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* ");
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* ");
+"*********** Annotate Event write failure **************"
SET GLOBAL max_binlog_cache_size = 4096;
SET GLOBAL binlog_cache_size = 4096;
SET GLOBAL max_binlog_stmt_cache_size = 4096;
@@ -10,12 +13,75 @@ disconnect master;
connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MYISAM;
connection master;
-ERROR HY000: Writing one row to the row-based binary log failed
+"#######################################################################"
+"# Test Case1: Annotate event write failure for MyISAM #"
+"#######################################################################"
+ERROR HY000: Multi-row statements required more than 'max_binlog_stmt_cache_size' bytes of storage; increase this mysqld variable and try again
include/wait_for_slave_sql_error_and_skip.inc [errno=1590]
+"#######################################################################"
+"# Test Case2: Annotate event write failure for INNODB #"
+"#######################################################################"
connection master;
+CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=INNODB;
+ERROR HY000: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
+"*** One row will be present as second row will be rolledback ***"
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+1
+connection slave;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+1
+"#######################################################################"
+"# Test Case3: Annotate event write failure for mixed engine UPDATE #"
+"#######################################################################"
+connection master;
+ERROR HY000: Multi-row statements required more than 'max_binlog_stmt_cache_size' bytes of storage; increase this mysqld variable and try again
+include/wait_for_slave_sql_error_and_skip.inc [errno=1590]
+connection master;
+"****** Clean up *******"
SET GLOBAL max_binlog_cache_size= ORIGINAL_VALUE;
SET GLOBAL binlog_cache_size= ORIGINAL_VALUE;
SET GLOBAL max_binlog_stmt_cache_size= ORIGINAL_VALUE;
SET GLOBAL binlog_stmt_cache_size= ORIGINAL_VALUE;
-DROP TABLE t1;
+DROP TABLE t1,t2;
+"*********** TABLE MAP Event write failure **************"
+CREATE TABLE tm (f INT) ENGINE=MYISAM;
+CREATE TABLE ti (f INT) ENGINE=INNODB;
+INSERT INTO tm VALUES (10);
+INSERT INTO ti VALUES (20);
+connection slave;
+"#######################################################################"
+"# Test Case4: Table_map event write failure for mixed engine UPDATE #"
+"#######################################################################"
+connection master;
+SET debug_dbug="+d,table_map_write_error";
+"In case of mixed engines if non trans table is updated write INCIDENT event"
+UPDATE ti,tm SET tm.f=88, ti.f=120;
+ERROR HY000: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
+include/wait_for_slave_sql_error_and_skip.inc [errno=1590]
+"On Slave non trans table should be updated one row with f=88 should be found"
+SELECT * FROM tm WHERE f=88;
+f
+88
+"On Innodb table 'ti' no update should be done no row exists with f=120"
+SELECT COUNT(*) FROM ti WHERE f=120;
+COUNT(*)
+0
+"#######################################################################"
+"# Test Case5: Table_map event write failure for trans engine UPDATE #"
+"#######################################################################"
+"Transaction will be rolled back. No incident event is written."
+connection master;
+UPDATE ti, tm set ti.f=30;
+ERROR HY000: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
+"Verify on master that no rows exists with f=30"
+SELECT COUNT(*) FROM ti WHERE f=30;
+COUNT(*)
+0
+connection slave;
+connection master;
+"******** Clean Up **********"
+SET GLOBAL debug_dbug = '';
+DROP TABLE tm,ti;
include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_mixed_binlog_max_cache_size.result b/mysql-test/suite/rpl/r/rpl_mixed_binlog_max_cache_size.result
index 388c8e67b68..d302e73f15c 100644
--- a/mysql-test/suite/rpl/r/rpl_mixed_binlog_max_cache_size.result
+++ b/mysql-test/suite/rpl/r/rpl_mixed_binlog_max_cache_size.result
@@ -1,6 +1,8 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* ");
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* ");
SET GLOBAL max_binlog_cache_size = 4096;
SET GLOBAL binlog_cache_size = 4096;
SET GLOBAL max_binlog_stmt_cache_size = 4096;
diff --git a/mysql-test/suite/rpl/r/rpl_stm_binlog_max_cache_size.result b/mysql-test/suite/rpl/r/rpl_stm_binlog_max_cache_size.result
index 388c8e67b68..d302e73f15c 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_binlog_max_cache_size.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_binlog_max_cache_size.result
@@ -1,6 +1,8 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* ");
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* ");
SET GLOBAL max_binlog_cache_size = 4096;
SET GLOBAL binlog_cache_size = 4096;
SET GLOBAL max_binlog_stmt_cache_size = 4096;
diff --git a/mysql-test/suite/rpl/t/rpl_mdev-11092.test b/mysql-test/suite/rpl/t/rpl_mdev-11092.test
index 31a385b40e6..6e130db37d8 100644
--- a/mysql-test/suite/rpl/t/rpl_mdev-11092.test
+++ b/mysql-test/suite/rpl/t/rpl_mdev-11092.test
@@ -1,3 +1,4 @@
+--source include/have_debug.inc
--source include/have_innodb.inc
--source include/not_embedded.inc
--source include/not_windows.inc
@@ -7,12 +8,16 @@
########################################################################################
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
call mtr.add_suppression("Slave SQL: The incident LOST_EVENTS occured on the master. .*");
+call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* ");
+call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* ");
let $old_max_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_cache_size", Value, 1);
let $old_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "binlog_cache_size", Value, 1);
let $old_max_binlog_stmt_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_stmt_cache_size", Value, 1);
let $old_binlog_stmt_cache_size= query_get_value(SHOW VARIABLES LIKE "binlog_stmt_cache_size", Value, 1);
+--echo "*********** Annotate Event write failure **************"
+
SET GLOBAL max_binlog_cache_size = 4096;
SET GLOBAL binlog_cache_size = 4096;
SET GLOBAL max_binlog_stmt_cache_size = 4096;
@@ -26,8 +31,19 @@ let $data = `select concat('"', repeat('a',2000), '"')`;
connection master;
+# Insert a huge row into MyISAM table. The row will be inserted in engine and a
+# request to write to binary log will be initiated. Since row annotations are
+# enabled the size of the annotate event itself will exceed the
+# "max_binlog_stmt_cache_size". This will result in ER_STMT_CACHE_FULL error
+# and an incident event will be written to the binary log as row update in
+# engine cannot be undone.
+
+--echo "#######################################################################"
+--echo "# Test Case1: Annotate event write failure for MyISAM #"
+--echo "#######################################################################"
+
--disable_query_log
---error ER_BINLOG_ROW_LOGGING_FAILED
+--error ER_STMT_CACHE_FULL
eval INSERT INTO t1 (a, data) VALUES (2,
CONCAT($data, $data, $data, $data, $data, $data));
--enable_query_log
@@ -37,8 +53,59 @@ eval INSERT INTO t1 (a, data) VALUES (2,
--let $slave_sql_errno= 1590
--source include/wait_for_slave_sql_error_and_skip.inc
-connection master;
+# MDEV-21087
+# Insert two huge rows in to transaction cache. Have data such that first row
+# fits inside the binary log cache. While writing the annotate event for the
+# second row the binary log cache size will exceed "max_binlog_cache_size".
+# Hence this statement cannot be written to binary log. As DMLs in Innodb can
+# be safely rolled back only an error will be reported. Slave will continue to
+# work.
+
+--echo "#######################################################################"
+--echo "# Test Case2: Annotate event write failure for INNODB #"
+--echo "#######################################################################"
+
+--connection master
+CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=INNODB;
+--disable_query_log
+BEGIN;
+eval INSERT INTO t2 (a, data) VALUES (1, CONCAT($data, $data));
+--error ER_TRANS_CACHE_FULL
+eval INSERT INTO t2 (a, data) VALUES (2, CONCAT($data, $data));
+COMMIT;
+--enable_query_log
+
+--echo "*** One row will be present as second row will be rolledback ***"
+SELECT COUNT(*) FROM t2;
+--sync_slave_with_master
+SELECT COUNT(*) FROM t2;
+# Testing mixed engine UPDATE statement scenario. In the following multi
+# update query 'ha_update_row' will be invoked for t1 (myisam) table. This
+# intern invokes binlog_write_table_map() function call. While writing a huge
+# annotate event binary log cache size will exceed max_binlog_cache_size.
+# Writing to binary log fails. Since non transactional changes cannot be
+# rolled back incident event will be written to binary log.
+
+--echo "#######################################################################"
+--echo "# Test Case3: Annotate event write failure for mixed engine UPDATE #"
+--echo "#######################################################################"
+
+--connection master
+let $new_data = `select concat('"', repeat('b',2000), '"')`;
+--disable_query_log
+--error ER_STMT_CACHE_FULL
+eval UPDATE t1,t2 SET t1.data="Hello", t2.data=CONCAT($new_data,$new_data,$new_data,$new_data,$new_data);
+--enable_query_log
+
+# Incident event
+# 1590=ER_SLAVE_INCIDENT
+--let $slave_sql_errno= 1590
+--source include/wait_for_slave_sql_error_and_skip.inc
+
+--connection master
+
+--echo "****** Clean up *******"
--replace_result $old_max_binlog_cache_size ORIGINAL_VALUE
--eval SET GLOBAL max_binlog_cache_size= $old_max_binlog_cache_size
--replace_result $old_binlog_cache_size ORIGINAL_VALUE
@@ -48,6 +115,52 @@ connection master;
--replace_result $old_binlog_stmt_cache_size ORIGINAL_VALUE
--eval SET GLOBAL binlog_stmt_cache_size= $old_binlog_stmt_cache_size
-DROP TABLE t1;
+DROP TABLE t1,t2;
+
+--echo "*********** TABLE MAP Event write failure **************"
+
+--let $debug_save= `SELECT @@GLOBAL.debug_dbug`
+CREATE TABLE tm (f INT) ENGINE=MYISAM;
+CREATE TABLE ti (f INT) ENGINE=INNODB;
+INSERT INTO tm VALUES (10);
+INSERT INTO ti VALUES (20);
+--sync_slave_with_master
+
+--echo "#######################################################################"
+--echo "# Test Case4: Table_map event write failure for mixed engine UPDATE #"
+--echo "#######################################################################"
+--connection master
+SET debug_dbug="+d,table_map_write_error";
+--echo "In case of mixed engines if non trans table is updated write INCIDENT event"
+--error ER_TRANS_CACHE_FULL
+UPDATE ti,tm SET tm.f=88, ti.f=120;
+
+# Incident event
+# 1590=ER_SLAVE_INCIDENT
+--let $slave_sql_errno= 1590
+--source include/wait_for_slave_sql_error_and_skip.inc
+
+--echo "On Slave non trans table should be updated one row with f=88 should be found"
+SELECT * FROM tm WHERE f=88;
+
+--echo "On Innodb table 'ti' no update should be done no row exists with f=120"
+SELECT COUNT(*) FROM ti WHERE f=120;
+
+--echo "#######################################################################"
+--echo "# Test Case5: Table_map event write failure for trans engine UPDATE #"
+--echo "#######################################################################"
+--echo "Transaction will be rolled back. No incident event is written."
+--connection master
+--error ER_TRANS_CACHE_FULL
+UPDATE ti, tm set ti.f=30;
+--echo "Verify on master that no rows exists with f=30"
+SELECT COUNT(*) FROM ti WHERE f=30;
+
+--sync_slave_with_master
+
+--connection master
+--echo "******** Clean Up **********"
+--eval SET GLOBAL debug_dbug = '$debug_save'
+DROP TABLE tm,ti;
--source include/rpl_end.inc
diff --git a/sql/handler.cc b/sql/handler.cc
index 914a4dc07b1..6cd5ab15b36 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -5863,7 +5863,27 @@ static int write_locked_table_maps(THD *thd)
continue;
TABLE **const end_ptr= lock->table + lock->table_count;
- for (TABLE **table_ptr= lock->table ;
+ bool stmt_modified_non_trans_table= false;
+ /*
+ Iterate through list of tables and identify if multi statement
+ transaction modifies any non transactional table. Set the
+ 'stmt_modified_non_trans_table' flag to 'true'. In case if there a
+ failure at the time of writing annotate/table_map event into the binary
+ log this flag will enable server to write an incident event into the
+ binary log. This additional flag is required as
+ 'thd->transaction.stmt.modified_non_trans_table' will not available at
+ the time of writing table_map/annotate event.
+ */
+ for (TABLE **table_ptr= lock->table; table_ptr != end_ptr ; ++table_ptr)
+ {
+ TABLE *const table= *table_ptr;
+ if (!table->file->has_transactions() && table->current_lock == F_WRLCK)
+ {
+ stmt_modified_non_trans_table=true;
+ break;
+ }
+ }
+ for (TABLE **table_ptr= lock->table ;
table_ptr != end_ptr ;
++table_ptr)
{
@@ -5887,8 +5907,10 @@ static int write_locked_table_maps(THD *thd)
*/
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
table->file->has_transactions();
+
int const error= thd->binlog_write_table_map(table, has_trans,
- &with_annotate);
+ &with_annotate,
+ stmt_modified_non_trans_table);
/*
If an error occurs, it is the responsibility of the caller to
roll back the transaction.
diff --git a/sql/log.cc b/sql/log.cc
index 5fd384d55a0..a82808bc7b7 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5673,14 +5673,14 @@ binlog_start_consistent_snapshot(handlerton *hton, THD *thd)
}
/**
- This function writes a table map to the binary log.
+ This function writes a table map to the binary log.
Note that in order to keep the signature uniform with related methods,
we use a redundant parameter to indicate whether a transactional table
was changed or not.
If with_annotate != NULL and
*with_annotate = TRUE write also Annotate_rows before the table map.
-
+
@param table a pointer to the table.
@param is_transactional @c true indicates a transactional table,
otherwise @c false a non-transactional.
@@ -5688,7 +5688,8 @@ binlog_start_consistent_snapshot(handlerton *hton, THD *thd)
nonzero if an error pops up when writing the table map event.
*/
int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
- my_bool *with_annotate)
+ my_bool *with_annotate,
+ bool stmt_modified_non_trans_table)
{
int error;
DBUG_ENTER("THD::binlog_write_table_map");
@@ -5699,7 +5700,7 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
/* Ensure that all events in a GTID group are in the same cache */
if (variables.option_bits & OPTION_GTID_BEGIN)
is_transactional= 1;
-
+
/* Pre-conditions */
DBUG_ASSERT(is_current_stmt_binlog_format_row());
DBUG_ASSERT(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open());
@@ -5726,17 +5727,34 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
/* Annotate event should be written not more than once */
*with_annotate= 0;
if ((error= writer.write(&anno)))
- {
- if (my_errno == EFBIG)
- cache_data->set_incident();
- DBUG_RETURN(error);
- }
+ goto write_err;
}
+ DBUG_EXECUTE_IF("table_map_write_error",
+ {
+ if (is_transactional)
+ {
+ my_errno= EFBIG;
+ error= 1;
+ goto write_err;
+ }
+ });
if ((error= writer.write(&the_event)))
- DBUG_RETURN(error);
+ goto write_err;
- binlog_table_maps++;
- DBUG_RETURN(0);
+ binlog_table_maps++;
+ DBUG_RETURN(0);
+
+write_err:
+ mysql_bin_log.set_write_error(this, is_transactional);
+ /*
+ For non-transactional engine or multi statement transaction with mixed
+ engines, data is written to table but writing to binary log failed. In
+ these scenarios rollback is not possible. Hence report an incident.
+ */
+ if (mysql_bin_log.check_write_error(this) && cache_data &&
+ stmt_modified_non_trans_table)
+ cache_data->set_incident();
+ DBUG_RETURN(error);
}
/**
@@ -7198,6 +7216,18 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd)
mysql_mutex_unlock(&LOCK_log);
}
+ /*
+ Upon writing incident event, check for thd->error() and print the
+ relevant error message in the error log.
+ */
+ if (!error && thd->is_error())
+ {
+ sql_print_error("Write to binary log failed: "
+ "%s. An incident event is written to binary log "
+ "and slave will be stopped.\n",
+ thd->get_stmt_da()->message());
+ }
+
DBUG_RETURN(error);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b35f9a93238..133bc9de607 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2423,7 +2423,8 @@ class THD :public Statement,
void binlog_start_trans_and_stmt();
void binlog_set_stmt_begin();
int binlog_write_table_map(TABLE *table, bool is_transactional,
- my_bool *with_annotate= 0);
+ my_bool *with_annotate= 0,
+ bool stmt_modified_non_trans_table= false);
int binlog_write_row(TABLE* table, bool is_transactional,
const uchar *buf);
int binlog_delete_row(TABLE* table, bool is_transactional,
1
0
[Commits] fc34657511a: MDEV-21318: Wrong results with window functions and implicit grouping
by Varun 17 Dec '19
by Varun 17 Dec '19
17 Dec '19
revision-id: fc34657511a9aa08dd92f7363dc53f58934f9673 (mariadb-10.2.29-62-gfc34657511a)
parent(s): f0aa073f2bf3d8d85b3d028df89cdb4cdfc4002d
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-12-17 16:40:06 +0530
message:
MDEV-21318: Wrong results with window functions and implicit grouping
The issue here is for degenerate joins we should execute the window
function but it is not getting executed in all the cases.
To get the window function values window function needs to be executed
always. This currently does not happen in few cases
where the join would return 0 or 1 row like
1) IMPOSSIBLE WHERE
2) IMPOSSIBLE HAVING
3) MIN/MAX optimization
4) EMPTY CONST TABLE
5) ZERO LIMIT
The fix is to make sure that window functions get executed
and the temporary table is setup for the execution of window functions
---
mysql-test/r/win.result | 51 ++++++++++++++++++++++++++++++++++++++++++++
mysql-test/t/win.test | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
sql/sql_select.cc | 33 ++++++++++++++++++++++++++++-
sql/sql_select.h | 1 +
4 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result
index 805fd2ed3d7..de6e0e5afbb 100644
--- a/mysql-test/r/win.result
+++ b/mysql-test/r/win.result
@@ -3643,5 +3643,56 @@ x
foo
drop table t1;
#
+# MDEV-21318: Wrong results with window functions and implicit grouping
+#
+CREATE TABLE t1 (a INT);
+#
+# With empty table
+# The expected result here is 1, NULL
+#
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+row_number() over() sum(1)
+1 NULL
+insert into t1 values (2);
+#
+# Const table has 1 row, but still impossible where
+# The expected result here is 1, NULL
+#
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+row_number() over() sum(1)
+1 NULL
+#
+# Impossible HAVING
+# Empty result is expected
+#
+SELECT row_number() over(), sum(1) FROM t1 where a=1 having 1=0;
+row_number() over() sum(1)
+#
+# const table has 1 row, no impossible where
+# The expected result here is 1, 2
+#
+SELECT row_number() over(), sum(a) FROM t1 where a=2;
+row_number() over() sum(a)
+1 2
+drop table t1;
+#
+# Impossible Where
+#
+create table t1(a int);
+insert into t1 values (1);
+#
+# Expected result is NULL, 0, NULL
+#
+SELECT MAX(a) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+MAX(a) OVER () COUNT(a) abs(a)
+NULL 0 NULL
+#
+# Expected result is 1, 0, NULL
+#
+SELECT MAX(1) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+MAX(1) OVER () COUNT(a) abs(a)
+1 0 NULL
+drop table t1;
+#
# End of 10.2 tests
#
diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test
index 0f79834567b..9bc867cea7f 100644
--- a/mysql-test/t/win.test
+++ b/mysql-test/t/win.test
@@ -2351,6 +2351,62 @@ INSERT INTO t1 VALUES (1),(2),(3);
SELECT (SELECT MIN('foo') OVER() FROM t1 LIMIT 1) as x;
drop table t1;
+--echo #
+--echo # MDEV-21318: Wrong results with window functions and implicit grouping
+--echo #
+
+CREATE TABLE t1 (a INT);
+
+--echo #
+--echo # With empty table
+--echo # The expected result here is 1, NULL
+--echo #
+
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+insert into t1 values (2);
+
+--echo #
+--echo # Const table has 1 row, but still impossible where
+--echo # The expected result here is 1, NULL
+--echo #
+
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+
+--echo #
+--echo # Impossible HAVING
+--echo # Empty result is expected
+--echo #
+
+SELECT row_number() over(), sum(1) FROM t1 where a=1 having 1=0;
+
+--echo #
+--echo # const table has 1 row, no impossible where
+--echo # The expected result here is 1, 2
+--echo #
+
+SELECT row_number() over(), sum(a) FROM t1 where a=2;
+drop table t1;
+
+--echo #
+--echo # Impossible Where
+--echo #
+
+create table t1(a int);
+insert into t1 values (1);
+
+--echo #
+--echo # Expected result is NULL, 0, NULL
+--echo #
+SELECT MAX(a) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+
+--echo #
+--echo # Expected result is 1, 0, NULL
+--echo #
+
+SELECT MAX(1) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+
+drop table t1;
+
--echo #
--echo # End of 10.2 tests
--echo #
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c9cb533aa33..f6943b18cee 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1447,6 +1447,7 @@ JOIN::optimize_inner()
zero_result_cause= "Zero limit";
}
table_count= top_join_tab_count= 0;
+ implicit_grouping_with_window_funcs();
error= 0;
goto setup_subq_exit;
}
@@ -1502,6 +1503,7 @@ JOIN::optimize_inner()
zero_result_cause= "No matching min/max row";
table_count= top_join_tab_count= 0;
error=0;
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
if (res > 1)
@@ -1517,6 +1519,7 @@ JOIN::optimize_inner()
tables_list= 0; // All tables resolved
select_lex->min_max_opt_list.empty();
const_tables= top_join_tab_count= table_count;
+ implicit_grouping_with_window_funcs();
/*
Extract all table-independent conditions and replace the WHERE
clause with them. All other conditions were computed by opt_sum_query
@@ -1615,6 +1618,7 @@ JOIN::optimize_inner()
zero_result_cause= "no matching row in const table";
DBUG_PRINT("error",("Error: %s", zero_result_cause));
error= 0;
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
if (!(thd->variables.option_bits & OPTION_BIG_SELECTS) &&
@@ -1639,6 +1643,7 @@ JOIN::optimize_inner()
zero_result_cause=
"Impossible WHERE noticed after reading const tables";
select_lex->mark_const_derived(zero_result_cause);
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
@@ -1781,6 +1786,7 @@ JOIN::optimize_inner()
zero_result_cause=
"Impossible WHERE noticed after reading const tables";
select_lex->mark_const_derived(zero_result_cause);
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
@@ -18225,7 +18231,8 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab)
}
}
else if (join->sort_and_group && !tmp_tbl->precomputed_group_by &&
- !join->sort_and_group_aggr_tab && join->tables_list)
+ !join->sort_and_group_aggr_tab && join->tables_list &&
+ join->top_join_tab_count)
{
DBUG_PRINT("info",("Using end_write_group"));
aggr->set_write_func(end_write_group);
@@ -26924,6 +26931,30 @@ Item *remove_pushed_top_conjuncts(THD *thd, Item *cond)
return cond;
}
+/*
+ There are 5 cases in which we shortcut the join optimization process as we
+ conclude that the join would be a degenerate one
+ 1) IMPOSSIBLE WHERE
+ 2) IMPOSSIBLE HAVING
+ 3) MIN/MAX optimization (@see opt_sum_query)
+ 4) EMPTY CONST TABLE
+ 5) ZERO LIMIT
+ If a window function is present in any of the above cases then to get the
+ result of the window function, we need to execute it. So we need to
+ create a temporary table for its execution. Here we need to take in mind
+ that aggregate functions and non-aggregate function need not be executed.
+
+*/
+
+
+void JOIN::implicit_grouping_with_window_funcs()
+{
+ if (select_lex->have_window_funcs() && send_row_on_empty_set())
+ {
+ const_tables= top_join_tab_count= table_count= 0;
+ }
+}
+
/**
@} (end of group Query_Optimizer)
*/
diff --git a/sql/sql_select.h b/sql/sql_select.h
index fe44f448446..74e8ef4698b 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1057,6 +1057,7 @@ class JOIN :public Sql_alloc
void restore_query_plan(Join_plan_state *restore_from);
/* Choose a subquery plan for a table-less subquery. */
bool choose_tableless_subquery_plan();
+ void implicit_grouping_with_window_funcs();
public:
JOIN_TAB *join_tab, **best_ref;
1
0
[Commits] 0e04bccc19a: MDEV-21318: Wrong results with window functions and implicit grouping
by Varun 17 Dec '19
by Varun 17 Dec '19
17 Dec '19
revision-id: 0e04bccc19adf9b9cdc2ae6461e3e707d26cd62d (mariadb-10.2.29-62-g0e04bccc19a)
parent(s): f0aa073f2bf3d8d85b3d028df89cdb4cdfc4002d
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-12-17 15:53:09 +0530
message:
MDEV-21318: Wrong results with window functions and implicit grouping
The issue here is for degenerate joins we should execute the window
function but it is not getting executed in all the cases.
To get the window function values window function needs to be executed
always. This currently does not happen in few cases
where the join would return 0 or 1 row like
1) IMPOSSIBLE WHERE
2) IMPOSSIBLE HAVING
3) MIN/MAX optimization
4) EMPTY CONST TABLE
5) ZERO LIMIT
The fix is to make sure that window functions get executed
and the temporary table is setup for the execution of window functions
---
mysql-test/r/win.result | 51 ++++++++++++++++++++++++++++++++++++++++++++
mysql-test/t/win.test | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
sql/sql_select.cc | 32 +++++++++++++++++++++++++++-
sql/sql_select.h | 1 +
4 files changed, 139 insertions(+), 1 deletion(-)
diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result
index 805fd2ed3d7..de6e0e5afbb 100644
--- a/mysql-test/r/win.result
+++ b/mysql-test/r/win.result
@@ -3643,5 +3643,56 @@ x
foo
drop table t1;
#
+# MDEV-21318: Wrong results with window functions and implicit grouping
+#
+CREATE TABLE t1 (a INT);
+#
+# With empty table
+# The expected result here is 1, NULL
+#
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+row_number() over() sum(1)
+1 NULL
+insert into t1 values (2);
+#
+# Const table has 1 row, but still impossible where
+# The expected result here is 1, NULL
+#
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+row_number() over() sum(1)
+1 NULL
+#
+# Impossible HAVING
+# Empty result is expected
+#
+SELECT row_number() over(), sum(1) FROM t1 where a=1 having 1=0;
+row_number() over() sum(1)
+#
+# const table has 1 row, no impossible where
+# The expected result here is 1, 2
+#
+SELECT row_number() over(), sum(a) FROM t1 where a=2;
+row_number() over() sum(a)
+1 2
+drop table t1;
+#
+# Impossible Where
+#
+create table t1(a int);
+insert into t1 values (1);
+#
+# Expected result is NULL, 0, NULL
+#
+SELECT MAX(a) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+MAX(a) OVER () COUNT(a) abs(a)
+NULL 0 NULL
+#
+# Expected result is 1, 0, NULL
+#
+SELECT MAX(1) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+MAX(1) OVER () COUNT(a) abs(a)
+1 0 NULL
+drop table t1;
+#
# End of 10.2 tests
#
diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test
index 0f79834567b..9bc867cea7f 100644
--- a/mysql-test/t/win.test
+++ b/mysql-test/t/win.test
@@ -2351,6 +2351,62 @@ INSERT INTO t1 VALUES (1),(2),(3);
SELECT (SELECT MIN('foo') OVER() FROM t1 LIMIT 1) as x;
drop table t1;
+--echo #
+--echo # MDEV-21318: Wrong results with window functions and implicit grouping
+--echo #
+
+CREATE TABLE t1 (a INT);
+
+--echo #
+--echo # With empty table
+--echo # The expected result here is 1, NULL
+--echo #
+
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+insert into t1 values (2);
+
+--echo #
+--echo # Const table has 1 row, but still impossible where
+--echo # The expected result here is 1, NULL
+--echo #
+
+SELECT row_number() over(), sum(1) FROM t1 where a=1;
+
+--echo #
+--echo # Impossible HAVING
+--echo # Empty result is expected
+--echo #
+
+SELECT row_number() over(), sum(1) FROM t1 where a=1 having 1=0;
+
+--echo #
+--echo # const table has 1 row, no impossible where
+--echo # The expected result here is 1, 2
+--echo #
+
+SELECT row_number() over(), sum(a) FROM t1 where a=2;
+drop table t1;
+
+--echo #
+--echo # Impossible Where
+--echo #
+
+create table t1(a int);
+insert into t1 values (1);
+
+--echo #
+--echo # Expected result is NULL, 0, NULL
+--echo #
+SELECT MAX(a) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+
+--echo #
+--echo # Expected result is 1, 0, NULL
+--echo #
+
+SELECT MAX(1) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE;
+
+drop table t1;
+
--echo #
--echo # End of 10.2 tests
--echo #
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c9cb533aa33..56865c51906 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1447,6 +1447,7 @@ JOIN::optimize_inner()
zero_result_cause= "Zero limit";
}
table_count= top_join_tab_count= 0;
+ implicit_grouping_with_window_funcs();
error= 0;
goto setup_subq_exit;
}
@@ -1502,6 +1503,7 @@ JOIN::optimize_inner()
zero_result_cause= "No matching min/max row";
table_count= top_join_tab_count= 0;
error=0;
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
if (res > 1)
@@ -1615,6 +1617,7 @@ JOIN::optimize_inner()
zero_result_cause= "no matching row in const table";
DBUG_PRINT("error",("Error: %s", zero_result_cause));
error= 0;
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
if (!(thd->variables.option_bits & OPTION_BIG_SELECTS) &&
@@ -1639,6 +1642,7 @@ JOIN::optimize_inner()
zero_result_cause=
"Impossible WHERE noticed after reading const tables";
select_lex->mark_const_derived(zero_result_cause);
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
@@ -1781,6 +1785,7 @@ JOIN::optimize_inner()
zero_result_cause=
"Impossible WHERE noticed after reading const tables";
select_lex->mark_const_derived(zero_result_cause);
+ implicit_grouping_with_window_funcs();
goto setup_subq_exit;
}
@@ -18225,7 +18230,8 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab)
}
}
else if (join->sort_and_group && !tmp_tbl->precomputed_group_by &&
- !join->sort_and_group_aggr_tab && join->tables_list)
+ !join->sort_and_group_aggr_tab && join->tables_list &&
+ join->top_join_tab_count)
{
DBUG_PRINT("info",("Using end_write_group"));
aggr->set_write_func(end_write_group);
@@ -26924,6 +26930,30 @@ Item *remove_pushed_top_conjuncts(THD *thd, Item *cond)
return cond;
}
+/*
+ There are 4 cases in which we shortcut the join optimization process as we
+ conclude that the join would be a degenerate one
+ 1) IMPOSSIBLE WHERE
+ 2) IMPOSSIBLE HAVING
+ 3) MIN/MAX optimzation (@see opt_sum_query)
+ 4) EMPTY CONST TABLE
+ 5) ZERO LIMIT
+ If a window function is present in any of the above cases then to get the
+ result of the window function, we need to execute it. So we need to
+ create a temporary table for its execution. Here we need to take in mind
+ that aggregate functions and non-aggregate function need not be executed.
+
+*/
+
+
+void JOIN::implicit_grouping_with_window_funcs()
+{
+ if (select_lex->have_window_funcs() && send_row_on_empty_set())
+ {
+ const_tables= top_join_tab_count= table_count= 0;
+ }
+}
+
/**
@} (end of group Query_Optimizer)
*/
diff --git a/sql/sql_select.h b/sql/sql_select.h
index fe44f448446..74e8ef4698b 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1057,6 +1057,7 @@ class JOIN :public Sql_alloc
void restore_query_plan(Join_plan_state *restore_from);
/* Choose a subquery plan for a table-less subquery. */
bool choose_tableless_subquery_plan();
+ void implicit_grouping_with_window_funcs();
public:
JOIN_TAB *join_tab, **best_ref;
1
0