1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-13915: STOP SLAVE takes very long time on a busy system

The problem is that a parallel replica would not immediately stop
running/queued transactions when issued STOP SLAVE. That is, it
allowed the current group of transactions to run, and sometimes the
transactions which belong to the next group could be started and run
through commit after STOP SLAVE was issued too, if the last group
had started committing. This would lead to long periods to wait for
all waiting transactions to finish.

This patch updates a parallel replica to try and abort immediately
and roll-back any ongoing transactions. The exception to this is any
transactions which are non-transactional (e.g. those modifying
sequences or non-transactional tables), and any prior transactions,
will be run to completion.

The specifics are as follows:

 1. A new stage was added to SHOW PROCESSLIST output for the SQL
Thread when it is waiting for a replica thread to either rollback or
finish its transaction before stopping. This stage presents as
“Waiting for worker thread to stop”

 2. Worker threads which error or are killed no longer perform GCO
cleanup if there is a concurrently running prior transaction. This
is because a worker thread scheduled to run in a future GCO could be
killed and incorrectly perform cleanup of the active GCO.

 3. Refined cases when the FL_TRANSACTIONAL flag is added to GTID
binlog events to disallow adding it to transactions which modify
both transactional and non-transactional engines when the binlogging
configuration allow the modifications to exist in the same event,
i.e. when using binlog_direct_non_trans_update == 0 and
binlog_format == statement.

 4. A few existing MTR tests relied on the completion of certain
transactions after issuing STOP SLAVE, and were re-recorded
(potentially with added synchronizations) under the new rollback
behavior.

Reviewed By
===========
Andrei Elkin <andrei.elkin@mariadb.com>
This commit is contained in:
Brandon Nesterenko
2023-03-08 13:49:32 -07:00
parent 8de6740a2f
commit 0a99d457b3
20 changed files with 2187 additions and 24 deletions

View File

@@ -0,0 +1,608 @@
#
# The stop_slave_quick suite of tests aims to validate that stopping a replica
# with parallelization enabled will stop in a timely manner. That is, a
# parallel replica should try to immediately stop and roll-back any ongoing
# transactions. If any threads have a non-transactional workload, then it
# along with all prior transactions are executed before stopping.
#
# This file provides test cases that should be binlog format independent. There
# is, however, behavior that is specific to either statement or row format,
# which each have their own test files that include this file.
#
# Requirements:
# 1. Tables named `ti`, `ti2`, and `ti3` have already been created with
# storage engine InnoDB; and a table named `tm` has been created with
# storage engine MyIsam.
# 2. Test variables ti_ctr, ti2_ctr, ti3_ctr, and tm_ctr have been created
# to serve as dynamic values to insert into their respective tables
#
# References:
# MDEV-13915: STOP SLAVE takes very long time on a busy system
#
--echo #
--echo # Common Test Case 1:
--echo # Using one parallel replication worker thread on workload {T,T}, ensure
--echo # the replica immediately rolls back the transaction and stops the
--echo # SQL thread
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=1;
--let $row_count_initial=`select count(*) from ti`
--connection master
--source include/save_master_gtid.inc
BEGIN;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
COMMIT;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--connection slave
LOCK TABLES ti WRITE;
--source include/start_slave.inc
--echo # Wait for replica to begin executing the first transaction
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $row_count_end=`select count(*) from ti`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
--let $assert_text= No new rows should have been inserted
--let $assert_cond= $row_count_diff = 0
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should not change
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Common Test Case 2:
--echo # Using multiple parallel replication threads (two) on workload {T,T},
--echo # ensure both transactions are rolled back if stop slave is issued
--echo # in the middle of the first transaction.
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=2;
--let $row_count_initial=`select count(*) from ti`
--connection master
--source include/save_master_gtid.inc
BEGIN;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
COMMIT;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--connection slave
LOCK TABLES ti WRITE;
--source include/start_slave.inc
--echo # Wait for replica to begin executing the first transaction
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--echo # Wait for second transaction to begin
--connection slave
--let $wait_condition= SELECT count(*)=0 FROM information_schema.processlist WHERE state LIKE 'Waiting for work from SQL thread' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $row_count_end=`select count(*) from ti`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
--let $assert_text= No insertions should have committed
--let $assert_cond= $row_count_diff = 0
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should not change
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
--echo # Slave should be error-free
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
--let $assert_text= Slave should be error free
--let $assert_cond= $last_error = 0
--source include/assert.inc
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Common Test Case 3:
--echo # Using multiple parallel replication threads (two) on workload {T,T},
--echo # with the same commit id (cid), ensure both transactions are rolled
--echo # back if stop slave is issued
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_mode=AGGRESSIVE;
set @@global.slave_parallel_threads=2;
--let $row_count_initial=`select count(*) from ti`
--connection master
--source include/save_master_gtid.inc
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10000;
BEGIN;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
COMMIT;
--eval insert into ti2 values ($ti2_ctr)
--inc $ti2_ctr
SET @@SESSION.debug_dbug=@old_dbug;
--connection slave
LOCK TABLES ti WRITE;
--source include/start_slave.inc
--echo # Wait for replica to begin executing the first transactions
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--echo # Wait for second transaction to start group commit
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to commit' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $row_count_end=`select count(*) from ti`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
--let $assert_text= No insertions should have committed
--let $assert_cond= $row_count_diff = 0
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should not change
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Common Test Case 4:
--echo # Using multiple parallel replication threads (4) on workload
--echo # T (long running); should commit
--echo # N (waiting for prior commit); should commit
--echo # T (long running); should rollback
--echo # T (waiting for prior commit); should rollback
--echo # Issuing STOP SLAVE should allow the first two transactions to commit
--echo # while preventing and rolling back the third
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_mode=optimistic;
set @@global.slave_parallel_threads=4;
--connection master
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10001;
BEGIN;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
COMMIT;
--connection master
--eval insert into tm values ($tm_ctr)
--inc $tm_ctr
--source include/save_master_gtid.inc
--eval insert into ti2 values ($ti2_ctr)
--inc $ti2_ctr
--eval insert into ti3 values ($ti3_ctr)
--inc $ti3_ctr
SET @@SESSION.debug_dbug=@old_dbug;
--connection slave
LOCK TABLES ti WRITE, ti2 WRITE;
--source include/start_slave.inc
--echo # Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--echo # Wait for replica to progress until unblocked transactions are queued for group commit..
--connection slave
--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to commit' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should reach first N transaction
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
set @@global.slave_parallel_mode=CONSERVATIVE;
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Common Test Case 5:
--echo # Using multiple parallel replication threads (5) on workload
--echo # T (long running); should commit
--echo # N (waiting for prior commit); should commit
--echo # T (waiting for prior commit); should commit
--echo # N (waiting for prior commit); should commit
--echo # T (long running); should rollback
--echo # Issuing STOP SLAVE should allow all transactions up to and including
--echo # the last N (4th) to commit, while preventing and rolling back the
--echo # final transaction (5th)
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_mode=optimistic;
set @@global.slave_parallel_threads=5;
--connection master
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10002;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into tm values ($tm_ctr)
--inc $tm_ctr
--eval insert into ti2 values ($ti2_ctr)
--inc $ti2_ctr
--eval insert into tm2 values ($tm2_ctr)
--inc $tm2_ctr
--source include/save_master_gtid.inc
--eval insert into ti3 values ($ti3_ctr)
--inc $ti3_ctr
SET @@SESSION.debug_dbug=@old_dbug;
--connection slave
LOCK TABLES ti WRITE, ti3 WRITE;
--source include/start_slave.inc
--echo # Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--echo # Wait for replica to progress until unblocked transactions are queued for group commit..
--connection slave
--let $wait_condition= SELECT count(*)=3 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to commit' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should reach second N transaction
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
set @@global.slave_parallel_mode=CONSERVATIVE;
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Common Test Case 6:
--echo # If retrying a T transaction while STOP SLAVE is issued, the
--echo # transaction should be rolled back and the slave abruptly stopped
--connection master
--eval insert into ti values ($ti_ctr)
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--source include/stop_slave.inc
set @@global.slave_parallel_threads=1;
--let $save_innodb_lock_wait_timeout= `SELECT @@global.innodb_lock_wait_timeout`
# 2 second buffer to give ample time to wait for transaction and issue stop slave
set @@global.innodb_lock_wait_timeout= 2;
BEGIN;
--eval SELECT * FROM ti WHERE a=$ti_ctr FOR UPDATE
--connection master
--source include/save_master_gtid.inc
--eval update ti set a=a+1 where a=$ti_ctr
--inc $ti_ctr
--inc $ti_ctr
--connection slave
--source include/start_slave.inc
--let $retried_tx_initial= query_get_value(SHOW ALL SLAVES STATUS, Retried_transactions, 1)
if (`SELECT @@global.binlog_format = 'ROW'`)
{
--let $update_state=Update_rows_log_event::find_row(-1)
}
if (`SELECT @@global.binlog_format = 'STATEMENT'`)
{
--let $update_state=Updating
}
--echo # Wait for replicating transaction to wait for innodb table lock
--source include/start_slave.inc
--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state LIKE "$update_state" and command like 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
--let $retried_tx_test= query_get_value(SHOW ALL SLAVES STATUS, Retried_transactions, 1)
if ($retried_tx_initial != $retried_tx_test)
{
--echo T transaction should have been rolled back without retry
--die T transaction should have been rolled back without retry
}
# End the SELECT ... FOR UPDATE
ROLLBACK;
--connection slave1
--reap
--connection slave
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= The retried T transaction should have been rolled back
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
--eval set @@global.innodb_lock_wait_timeout= $save_innodb_lock_wait_timeout
--echo #
--echo # Common Test Case 7:
--echo # Using multiple parallel replication threads on a workload with a
--echo # non-transactional transaction in-between transactional transactions..
--echo # 7a: with AGGRESSIVE replication where the N statement has been
--echo # executed already, all transactions up to and including N should
--echo # be replicated, and all transactions afterwards should be rolled
--echo # back.
--echo # 7b: with MINIMAL replication, the N statement should not execute
--echo # concurrently, but should wait along with the other later
--echo # transactions, and all future transactions except the first should
--echo # be rolled back.
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=4;
--let $mode_ctr=2
while ($mode_ctr)
{
--connection slave
if ($mode_ctr == 2)
{
--echo #
--echo # 7a: slave_parallel_mode=AGGRESSIVE
set @@global.slave_parallel_mode=AGGRESSIVE;
}
if ($mode_ctr == 1)
{
--echo #
--echo # 7b: slave_parallel_mode=MINIMAL
set @@global.slave_parallel_mode=MINIMAL;
}
--connection slave
--let $row_count_initial=`select count(*) from (select * from ti UNION ALL select * from tm UNION ALL select * from ti2 UNION ALL select * from tm2 UNION ALL select * from ti3) t`
--connection master
if ($mode_ctr == 1)
{
--let $master_gtid_cmp= `select @@global.gtid_binlog_pos`
}
--connection master
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into tm values ($tm_ctr)
if ($mode_ctr == 2)
{
# AGGRESSIVE mode should allow N trx to complete
--let $master_gtid_cmp= `select @@global.gtid_binlog_pos`
}
--eval insert into ti2 values ($ti2_ctr)
--inc $ti2_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--source include/save_master_gtid.inc
--connection slave
LOCK TABLES ti WRITE;
--connection slave_lock_extra
LOCK TABLES ti2 WRITE;
--source include/start_slave.inc
--echo # Wait for replica to halt due to locks and dependency requirements
--connection slave
if ($mode_ctr == 2)
{
# AGGRESSIVE allows for more concurrency that we need to wait for
--let $wait_condition= SELECT count(*)=3 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to commit' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
}
if ($mode_ctr == 1)
{
# MINIMAL will only have the first transaction begun
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--let $wait_condition= SELECT count(*)=3 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to start commit%' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
}
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--connection slave_lock_extra
UNLOCK TABLES;
--connection slave1
--reap
--connection slave
--source include/wait_for_slave_sql_to_stop.inc
--let $row_count_end=`select count(*) from (select * from ti UNION ALL select * from tm UNION ALL select * from ti2 UNION ALL select * from tm2 UNION ALL select * from ti3) t`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
if ($mode_ctr == 2)
{
--let $assert_text= The entirety of the first two transactions should have committed with AGGRESSIVE parallelization
--let $assert_cond= $row_count_diff = 2
}
if ($mode_ctr == 1)
{
--let $assert_text= All transactions should have rolled back with MINIMAL parallelization
--let $assert_cond= $row_count_diff = 0
}
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= Slave state should be consistent
--let $assert_cond= $master_gtid_cmp = $slave_gtid
--source include/assert.inc
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--source include/stop_slave.inc
--dec $mode_ctr
}
--source include/start_slave.inc
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc

View File

@@ -731,7 +731,7 @@ 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';
# Wait for replica to signal worker threads to stop
SET debug_sync='now SIGNAL t1_cont';
include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
STOP SLAVE IO_THREAD;
@@ -741,7 +741,6 @@ a b
61 61
62 62
63 63
64 64
68 68
69 69
70 70
@@ -815,6 +814,7 @@ connection server_2;
SET debug_sync='now WAIT_FOR wait_queue_ready';
KILL THD_ID;
SET debug_sync='now WAIT_FOR wait_queue_killed';
# Wait for replica to signal worker threads to stop
SET debug_sync='now SIGNAL query_cont';
include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
STOP SLAVE IO_THREAD;
@@ -826,6 +826,8 @@ SET binlog_format=@old_format;
connection server_2;
SET debug_sync='RESET';
include/start_slave.inc
SET debug_sync='now WAIT_FOR query_waiting';
SET debug_sync='now SIGNAL query_cont';
SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
a b
80 0
@@ -1214,6 +1216,7 @@ connection server_2;
include/wait_for_slave_sql_to_stop.inc
SELECT * FROM t2 WHERE a >= 40 ORDER BY a;
a
40
41
42
include/start_slave.inc

View File

@@ -1,6 +1,7 @@
include/rpl_init.inc [topology=1->2]
*** MDEV-5509: Incorrect value for Seconds_Behind_Master if parallel replication ***
connection server_2;
SET STATEMENT sql_log_bin=0 FOR 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;
include/stop_slave.inc

View File

@@ -0,0 +1,507 @@
include/master-slave.inc
[connection master]
#
# Setup
connection slave;
include/stop_slave.inc
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression("Can't find record");
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression("Commit failed due to failure");
set @@global.slave_parallel_mode=CONSERVATIVE;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
connect slave_lock_extra,127.0.0.1,root,,test,$SLAVE_MYPORT;
CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS;
include/start_slave.inc
#
# Initialize test data
connection master;
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
create sequence s1;
create table ti (a int) engine=innodb;
create table ti2 (a int) engine=innodb;
create table ti3 (a int) engine=innodb;
create table tm (a int) engine=myisam;
create table tm2 (a int) engine=myisam;
connection slave;
# Run binlog format independent test cases
#
# Common Test Case 1:
# Using one parallel replication worker thread on workload {T,T}, ensure
# the replica immediately rolls back the transaction and stops the
# SQL thread
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
connection master;
include/save_master_gtid.inc
BEGIN;
insert into ti values (100);
insert into ti values (101);
COMMIT;
insert into ti values (102);
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transaction
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No new rows should have been inserted]
include/assert.inc [GTID slave state should not change]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 2:
# Using multiple parallel replication threads (two) on workload {T,T},
# ensure both transactions are rolled back if stop slave is issued
# in the middle of the first transaction.
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=2;
connection master;
include/save_master_gtid.inc
BEGIN;
insert into ti values (103);
insert into ti values (104);
COMMIT;
insert into ti values (105);
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transaction
connection slave;
# Wait for second transaction to begin
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No insertions should have committed]
include/assert.inc [GTID slave state should not change]
# Slave should be error-free
include/assert.inc [Slave should be error free]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 3:
# Using multiple parallel replication threads (two) on workload {T,T},
# with the same commit id (cid), ensure both transactions are rolled
# back if stop slave is issued
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=AGGRESSIVE;
set @@global.slave_parallel_threads=2;
connection master;
include/save_master_gtid.inc
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10000;
BEGIN;
insert into ti values (106);
insert into ti values (107);
COMMIT;
insert into ti2 values (400);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transactions
connection slave;
# Wait for second transaction to start group commit
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No insertions should have committed]
include/assert.inc [GTID slave state should not change]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 4:
# Using multiple parallel replication threads (4) on workload
# T (long running); should commit
# N (waiting for prior commit); should commit
# T (long running); should rollback
# T (waiting for prior commit); should rollback
# Issuing STOP SLAVE should allow the first two transactions to commit
# while preventing and rolling back the third
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=optimistic;
set @@global.slave_parallel_threads=4;
connection master;
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10001;
BEGIN;
insert into ti values (108);
insert into ti values (109);
COMMIT;
connection master;
insert into tm values (200);
include/save_master_gtid.inc
insert into ti2 values (401);
insert into ti3 values (500);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti WRITE, ti2 WRITE;
include/start_slave.inc
# Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
# Wait for replica to progress until unblocked transactions are queued for group commit..
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [GTID slave state should reach first N transaction]
set @@global.slave_parallel_mode=CONSERVATIVE;
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 5:
# Using multiple parallel replication threads (5) on workload
# T (long running); should commit
# N (waiting for prior commit); should commit
# T (waiting for prior commit); should commit
# N (waiting for prior commit); should commit
# T (long running); should rollback
# Issuing STOP SLAVE should allow all transactions up to and including
# the last N (4th) to commit, while preventing and rolling back the
# final transaction (5th)
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=optimistic;
set @@global.slave_parallel_threads=5;
connection master;
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10002;
insert into ti values (110);
insert into tm values (201);
insert into ti2 values (402);
insert into tm2 values (300);
include/save_master_gtid.inc
insert into ti3 values (501);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti WRITE, ti3 WRITE;
include/start_slave.inc
# Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
# Wait for replica to progress until unblocked transactions are queued for group commit..
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [GTID slave state should reach second N transaction]
set @@global.slave_parallel_mode=CONSERVATIVE;
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 6:
# If retrying a T transaction while STOP SLAVE is issued, the
# transaction should be rolled back and the slave abruptly stopped
connection master;
insert into ti values (111);
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
include/sync_with_master_gtid.inc
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
set @@global.innodb_lock_wait_timeout= 2;
BEGIN;
SELECT * FROM ti WHERE a=111 FOR UPDATE;
a
111
connection master;
include/save_master_gtid.inc
update ti set a=a+1 where a=111;
connection slave;
include/start_slave.inc
# Wait for replicating transaction to wait for innodb table lock
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
connection slave1;
STOP SLAVE;;
connection slave;
include/wait_for_slave_sql_to_stop.inc
ROLLBACK;
connection slave1;
connection slave;
include/assert.inc [The retried T transaction should have been rolled back]
set @@global.innodb_lock_wait_timeout= 50;
#
# Common Test Case 7:
# Using multiple parallel replication threads on a workload with a
# non-transactional transaction in-between transactional transactions..
# 7a: with AGGRESSIVE replication where the N statement has been
# executed already, all transactions up to and including N should
# be replicated, and all transactions afterwards should be rolled
# back.
# 7b: with MINIMAL replication, the N statement should not execute
# concurrently, but should wait along with the other later
# transactions, and all future transactions except the first should
# be rolled back.
connection slave;
include/stop_slave.inc
Warnings:
Note 1255 Slave already has been stopped
set @@global.slave_parallel_threads=4;
connection slave;
#
# 7a: slave_parallel_mode=AGGRESSIVE
set @@global.slave_parallel_mode=AGGRESSIVE;
connection slave;
connection master;
connection master;
insert into ti values (113);
insert into tm values (202);
insert into ti2 values (403);
insert into ti values (114);
include/save_master_gtid.inc
connection slave;
LOCK TABLES ti WRITE;
connection slave_lock_extra;
LOCK TABLES ti2 WRITE;
include/start_slave.inc
# Wait for replica to halt due to locks and dependency requirements
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
connection slave_lock_extra;
UNLOCK TABLES;
connection slave1;
connection slave;
include/wait_for_slave_sql_to_stop.inc
include/assert.inc [The entirety of the first two transactions should have committed with AGGRESSIVE parallelization]
include/assert.inc [Slave state should be consistent]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
include/stop_slave.inc
connection slave;
#
# 7b: slave_parallel_mode=MINIMAL
set @@global.slave_parallel_mode=MINIMAL;
connection slave;
connection master;
connection master;
insert into ti values (115);
insert into tm values (202);
insert into ti2 values (404);
insert into ti values (116);
include/save_master_gtid.inc
connection slave;
LOCK TABLES ti WRITE;
connection slave_lock_extra;
LOCK TABLES ti2 WRITE;
include/start_slave.inc
# Wait for replica to halt due to locks and dependency requirements
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
connection slave_lock_extra;
UNLOCK TABLES;
connection slave1;
connection slave;
include/wait_for_slave_sql_to_stop.inc
include/assert.inc [All transactions should have rolled back with MINIMAL parallelization]
include/assert.inc [Slave state should be consistent]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
include/stop_slave.inc
include/start_slave.inc
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
include/sync_with_master_gtid.inc
#
# ROW Test Case 1:
# Using an N multi-statement transaction, ensure if STOP SLAVE is
# issued in-between row updates, that the transaction is finished.
connection master;
truncate table ti;
truncate table tm;
# Set up multiple rows to allow a multi-statement update rows event
insert into tm values (202);
insert into tm values (203);
connection slave;
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
connection master;
# Next-to-commit non-transactional transaction should finish
update tm set a=a+1;
include/save_master_gtid.inc
# This should not be committed because it is after next-to-commit
insert into ti values (117);
connection slave;
set @@global.debug_dbug="+d,pause_after_next_row_exec";
START SLAVE;
set debug_sync= "now WAIT_FOR row_executed";
connection slave1;
STOP SLAVE;;
connection slave;
set @@global.debug_dbug="";
set debug_sync= "now SIGNAL continue_row_execution";
connection slave1;
include/wait_for_slave_sql_to_stop.inc
# Slave should be error-free
include/assert.inc [Slave should be error free]
set debug_sync= "RESET";
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# ROW Test Case 2:
# Using a T multi-statement transaction, ensure if STOP SLAVE is
# issued in-between row updates, that the transaction is rolled back.
connection master;
truncate table ti;
truncate table ti2;
truncate table tm;
insert into ti values (118);
insert into ti values (119);
connection slave;
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
connection master;
# Next-to-commit transactional multi-row event should be rolled back
include/save_master_gtid.inc
update ti set a=a+1;
insert into ti values (120);
connection slave;
set @@global.debug_dbug="+d,pause_after_next_row_exec";
START SLAVE;
set debug_sync= "now WAIT_FOR row_executed";
connection slave1;
STOP SLAVE;;
connection slave;
set @@global.debug_dbug="";
set debug_sync= "now SIGNAL continue_row_execution";
connection slave1;
include/wait_for_slave_sql_to_stop.inc
include/assert.inc [No new rows should have been inserted]
# Comparing master gtid 0-1-42 to slaves 0-1-42
include/assert.inc [No transactions should have committed]
# Slave should be error-free
include/assert.inc [Slave should be error free]
connection master;
include/save_master_gtid.inc
connection slave;
set debug_sync= "RESET";
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Row Test Case 3:
# A workload with a later transaction that updates a sequence table
# should complete all transactions up to the sequence table update.
# Workload:
# T (long running); should commit
# S (waiting for prior commit); should commit
# T (long running); should rollback
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=AGGRESSIVE;
set @@global.slave_parallel_threads=3;
connection master;
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10002;
insert into ti values (121);
select next value for s1;
next value for s1
1
include/save_master_gtid.inc
insert into ti2 values (405);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti write, ti2 WRITE;
include/start_slave.inc
# Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
# Wait for replica to progress until unblocked transactions are queued for group commit..
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [GTID slave state should not change]
set @@global.slave_parallel_mode=CONSERVATIVE;
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Cleanup
connection master;
DROP TABLE ti, ti2, ti3, tm, tm2, s1;
include/save_master_gtid.inc
connection slave;
include/sync_with_master_gtid.inc
include/stop_slave.inc
set @@global.debug_dbug="";
set @@global.slave_parallel_threads=0;
set @@global.slave_parallel_mode=conservative;
include/start_slave.inc
include/rpl_end.inc
# End of tests

View File

@@ -0,0 +1,461 @@
include/master-slave.inc
[connection master]
#
# Setup
connection slave;
include/stop_slave.inc
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
set @@global.slave_parallel_mode=CONSERVATIVE;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
change master to master_use_gtid=slave_pos;
include/start_slave.inc
connect slave_lock_extra,127.0.0.1,root,,test,$SLAVE_MYPORT;
#
# Initialize test data
connection master;
set statement sql_log_bin=0 for call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
create table ti (a int primary key) engine=innodb;
create table ti2 (a int) engine=innodb;
create table ti3 (a int) engine=innodb;
create table tm (a int) engine=myisam;
create table tm2 (a int) engine=myisam;
connection slave;
# Run binlog format independent test cases
#
# Common Test Case 1:
# Using one parallel replication worker thread on workload {T,T}, ensure
# the replica immediately rolls back the transaction and stops the
# SQL thread
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
connection master;
include/save_master_gtid.inc
BEGIN;
insert into ti values (100);
insert into ti values (101);
COMMIT;
insert into ti values (102);
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transaction
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No new rows should have been inserted]
include/assert.inc [GTID slave state should not change]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 2:
# Using multiple parallel replication threads (two) on workload {T,T},
# ensure both transactions are rolled back if stop slave is issued
# in the middle of the first transaction.
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=2;
connection master;
include/save_master_gtid.inc
BEGIN;
insert into ti values (103);
insert into ti values (104);
COMMIT;
insert into ti values (105);
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transaction
connection slave;
# Wait for second transaction to begin
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No insertions should have committed]
include/assert.inc [GTID slave state should not change]
# Slave should be error-free
include/assert.inc [Slave should be error free]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 3:
# Using multiple parallel replication threads (two) on workload {T,T},
# with the same commit id (cid), ensure both transactions are rolled
# back if stop slave is issued
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=AGGRESSIVE;
set @@global.slave_parallel_threads=2;
connection master;
include/save_master_gtid.inc
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10000;
BEGIN;
insert into ti values (106);
insert into ti values (107);
COMMIT;
insert into ti2 values (400);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transactions
connection slave;
# Wait for second transaction to start group commit
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No insertions should have committed]
include/assert.inc [GTID slave state should not change]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 4:
# Using multiple parallel replication threads (4) on workload
# T (long running); should commit
# N (waiting for prior commit); should commit
# T (long running); should rollback
# T (waiting for prior commit); should rollback
# Issuing STOP SLAVE should allow the first two transactions to commit
# while preventing and rolling back the third
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=optimistic;
set @@global.slave_parallel_threads=4;
connection master;
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10001;
BEGIN;
insert into ti values (108);
insert into ti values (109);
COMMIT;
connection master;
insert into tm values (200);
include/save_master_gtid.inc
insert into ti2 values (401);
insert into ti3 values (500);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti WRITE, ti2 WRITE;
include/start_slave.inc
# Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
# Wait for replica to progress until unblocked transactions are queued for group commit..
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [GTID slave state should reach first N transaction]
set @@global.slave_parallel_mode=CONSERVATIVE;
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 5:
# Using multiple parallel replication threads (5) on workload
# T (long running); should commit
# N (waiting for prior commit); should commit
# T (waiting for prior commit); should commit
# N (waiting for prior commit); should commit
# T (long running); should rollback
# Issuing STOP SLAVE should allow all transactions up to and including
# the last N (4th) to commit, while preventing and rolling back the
# final transaction (5th)
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_mode=optimistic;
set @@global.slave_parallel_threads=5;
connection master;
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10002;
insert into ti values (110);
insert into tm values (201);
insert into ti2 values (402);
insert into tm2 values (300);
include/save_master_gtid.inc
insert into ti3 values (501);
SET @@SESSION.debug_dbug=@old_dbug;
connection slave;
LOCK TABLES ti WRITE, ti3 WRITE;
include/start_slave.inc
# Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
# Wait for replica to progress until unblocked transactions are queued for group commit..
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [GTID slave state should reach second N transaction]
set @@global.slave_parallel_mode=CONSERVATIVE;
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Common Test Case 6:
# If retrying a T transaction while STOP SLAVE is issued, the
# transaction should be rolled back and the slave abruptly stopped
connection master;
insert into ti values (111);
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
include/sync_with_master_gtid.inc
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
set @@global.innodb_lock_wait_timeout= 2;
BEGIN;
SELECT * FROM ti WHERE a=111 FOR UPDATE;
a
111
connection master;
include/save_master_gtid.inc
update ti set a=a+1 where a=111;
connection slave;
include/start_slave.inc
# Wait for replicating transaction to wait for innodb table lock
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
connection slave1;
STOP SLAVE;;
connection slave;
include/wait_for_slave_sql_to_stop.inc
ROLLBACK;
connection slave1;
connection slave;
include/assert.inc [The retried T transaction should have been rolled back]
set @@global.innodb_lock_wait_timeout= 50;
#
# Common Test Case 7:
# Using multiple parallel replication threads on a workload with a
# non-transactional transaction in-between transactional transactions..
# 7a: with AGGRESSIVE replication where the N statement has been
# executed already, all transactions up to and including N should
# be replicated, and all transactions afterwards should be rolled
# back.
# 7b: with MINIMAL replication, the N statement should not execute
# concurrently, but should wait along with the other later
# transactions, and all future transactions except the first should
# be rolled back.
connection slave;
include/stop_slave.inc
Warnings:
Note 1255 Slave already has been stopped
set @@global.slave_parallel_threads=4;
connection slave;
#
# 7a: slave_parallel_mode=AGGRESSIVE
set @@global.slave_parallel_mode=AGGRESSIVE;
connection slave;
connection master;
connection master;
insert into ti values (113);
insert into tm values (202);
insert into ti2 values (403);
insert into ti values (114);
include/save_master_gtid.inc
connection slave;
LOCK TABLES ti WRITE;
connection slave_lock_extra;
LOCK TABLES ti2 WRITE;
include/start_slave.inc
# Wait for replica to halt due to locks and dependency requirements
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
connection slave_lock_extra;
UNLOCK TABLES;
connection slave1;
connection slave;
include/wait_for_slave_sql_to_stop.inc
include/assert.inc [The entirety of the first two transactions should have committed with AGGRESSIVE parallelization]
include/assert.inc [Slave state should be consistent]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
include/stop_slave.inc
connection slave;
#
# 7b: slave_parallel_mode=MINIMAL
set @@global.slave_parallel_mode=MINIMAL;
connection slave;
connection master;
connection master;
insert into ti values (115);
insert into tm values (202);
insert into ti2 values (404);
insert into ti values (116);
include/save_master_gtid.inc
connection slave;
LOCK TABLES ti WRITE;
connection slave_lock_extra;
LOCK TABLES ti2 WRITE;
include/start_slave.inc
# Wait for replica to halt due to locks and dependency requirements
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
connection slave_lock_extra;
UNLOCK TABLES;
connection slave1;
connection slave;
include/wait_for_slave_sql_to_stop.inc
include/assert.inc [All transactions should have rolled back with MINIMAL parallelization]
include/assert.inc [Slave state should be consistent]
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
include/stop_slave.inc
include/start_slave.inc
connection master;
include/save_master_gtid.inc
connection slave;
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
include/sync_with_master_gtid.inc
#
# Statement Test Case 1:
# Using one parallel replication worker thread on workload {N,T}, ensure
# the replica finishes the non-transactional transaction, and does not
# start the next
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
connection master;
SET @@session.binlog_direct_non_transactional_updates= 0;
BEGIN;
insert into ti values (117);
insert into tm values (202);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction
insert into tm2 values (301);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction
COMMIT;
include/save_master_gtid.inc
insert into ti values (118);
connection slave;
lock tables tm2 write;
START SLAVE;
# Wait for replica to get stuck on held lock
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
# Unlock row-level lock holding transaction
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [Transaction should have committed]
include/assert.inc [N should have been applied]
# Slave should be error-free
include/assert.inc [Slave should be error free]
connection master;
include/save_master_gtid.inc
SET @@session.binlog_direct_non_transactional_updates= 1;
connection slave;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Statement Test Case 2:
# If STOP SLAVE is issued on a parallel slave, such that the next to
# commit transaction is T; even if the next event from the group will
# commit the transaction (e.g. XID_EVENT), the transaction should be
# stopped and rolled back.
connection slave;
include/stop_slave.inc
set @@global.slave_parallel_threads=1;
connection master;
insert into ti values (119);
insert into ti values (120);
include/save_master_gtid.inc
connection slave;
LOCK TABLES ti WRITE;
include/start_slave.inc
# Wait for replica to begin executing the first transaction
connection slave;
connection slave1;
STOP SLAVE;;
connection slave;
# Wait for replica to signal worker threads to stop
UNLOCK TABLES;
include/wait_for_slave_sql_to_stop.inc
connection slave1;
connection slave;
include/assert.inc [No insertions should have committed]
include/assert.inc [GTID slave state should increment to the first transaction]
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# Cleanup
connection master;
DROP TABLE ti, tm, ti2, tm2, ti3;
include/save_master_gtid.inc
connection slave;
include/sync_with_master_gtid.inc
include/stop_slave.inc
set @@global.slave_parallel_threads=0;
set @@global.slave_domain_parallel_threads=0;
set @@global.slave_parallel_mode=conservative;
set @@global.debug_dbug="";
include/start_slave.inc
include/rpl_end.inc
# End of tests

View File

@@ -949,8 +949,9 @@ SET debug_sync='now WAIT_FOR t4_waiting';
--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';
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
# Now we can allow T1 to proceed.
SET debug_sync='now SIGNAL t1_cont';
@@ -959,7 +960,7 @@ SET debug_sync='now SIGNAL t1_cont';
--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
# to commit or not before the stop. However, T1 should rollback, 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;
@@ -1058,6 +1059,11 @@ SET debug_sync='now WAIT_FOR wait_queue_ready';
eval KILL $thd_id;
SET debug_sync='now WAIT_FOR wait_queue_killed';
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
SET debug_sync='now SIGNAL query_cont';
--let $slave_sql_errno= 1317,1927,1964
@@ -1075,6 +1081,14 @@ SET binlog_format=@old_format;
--connection server_2
SET debug_sync='RESET';
--source include/start_slave.inc
# Test amendment from MDEV-13915:
# A worker thread's event queue is no longer executed on replica stop.
# The signal query_cont needs to be re-sent because the transaction was
# aborted.
SET debug_sync='now WAIT_FOR query_waiting';
SET debug_sync='now SIGNAL query_cont';
--sync_with_master
SELECT * FROM t3 WHERE a >= 80 ORDER BY a;

View File

@@ -7,6 +7,7 @@
--echo *** MDEV-5509: Incorrect value for Seconds_Behind_Master if parallel replication ***
--connection server_2
SET STATEMENT sql_log_bin=0 FOR 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;
--source include/stop_slave.inc

View File

@@ -122,10 +122,10 @@ SELECT COUNT(*) = 1 as "W4 remains with the same status" FROM information_schema
--echo # Slave_SQL_Running YES = $status
# B. In the fixed version W3 is waiting for W2,...
--let $wait_condition= SELECT count(*) = 1 as "W4 is waiting" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%"
--let $wait_condition= SELECT count(*) = 1 as "W3 is waiting" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%"
--source include/wait_condition.inc
--echo # while W2 is held back ...
--let $wait_condition= SELECT count(*) = 1 as "W2 simulates slowness" FROM information_schema.processlist WHERE state LIKE "debug sync point: now"
--let $wait_condition= SELECT count(*) >= 1 as "W2 simulates slowness" FROM information_schema.processlist WHERE state LIKE "debug sync point: now"
--source include/wait_condition.inc
# C. # ...until NOW.
@@ -143,7 +143,7 @@ if ($old_version_regression)
--let $wait_condition= SELECT count(*) = 0 as "W3 does not wait on W2" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%"
--source include/wait_condition.inc
--let $wait_condition= SELECT count(*) = 1 as "W2 simulates slowness" FROM information_schema.processlist WHERE state LIKE "debug sync point: now"
--let $wait_condition= SELECT count(*) >= 1 as "W2 simulates slowness" FROM information_schema.processlist WHERE state LIKE "debug sync point: now"
--source include/wait_condition.inc
# Like above, but signaling is done after W4 is done to violate the commit order

View File

@@ -0,0 +1,268 @@
#
# Validate that STOP SLAVE works in a timely manner on a parallel replica with
# ROW binary logging format.
#
--source include/have_debug.inc
--source include/have_debug_sync.inc
--source include/master-slave.inc
--source include/have_innodb.inc
--source include/have_binlog_format_row.inc
--echo #
--echo # Setup
--connection slave
--source include/stop_slave.inc
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression("Can't find record");
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression("Commit failed due to failure");
--let $old_debug= `SELECT @@global.debug_dbug`
--let $old_threads= `SELECT @@global.slave_parallel_threads`
--let $old_slave_mode= `SELECT @@global.slave_parallel_mode`
set @@global.slave_parallel_mode=CONSERVATIVE;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
--connect(slave_lock_extra,127.0.0.1,root,,test,$SLAVE_MYPORT)
CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS;
--source include/start_slave.inc
--echo #
--echo # Initialize test data
--connection master
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
# Needed by this test and include/rpl_par_stop_slave_quick.inc
create sequence s1;
create table ti (a int) engine=innodb;
create table ti2 (a int) engine=innodb;
create table ti3 (a int) engine=innodb;
create table tm (a int) engine=myisam;
create table tm2 (a int) engine=myisam;
--let $ti_ctr= 100
--let $tm_ctr= 200
--let $tm2_ctr= 300
--let $ti2_ctr= 400
--let $ti3_ctr= 500
--sync_slave_with_master
--echo # Run binlog format independent test cases
--source include/rpl_par_stop_slave_quick_common.test
--echo #
--echo # ROW Test Case 1:
--echo # Using an N multi-statement transaction, ensure if STOP SLAVE is
--echo # issued in-between row updates, that the transaction is finished.
--connection master
truncate table ti;
truncate table tm;
--echo # Set up multiple rows to allow a multi-statement update rows event
--eval insert into tm values ($tm_ctr)
--inc $tm_ctr
--eval insert into tm values ($tm_ctr)
--inc $tm_ctr
--sync_slave_with_master
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=1;
--let $row_count_initial=`select count(*) from (select * from ti UNION ALL select * from tm) t`
--connection master
--echo # Next-to-commit non-transactional transaction should finish
--eval update tm set a=a+1
--source include/save_master_gtid.inc
--let $master_gtid_after_update= `select @@global.gtid_binlog_pos`
--echo # This should not be committed because it is after next-to-commit
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--connection slave
set @@global.debug_dbug="+d,pause_after_next_row_exec";
START SLAVE;
set debug_sync= "now WAIT_FOR row_executed";
--connection slave1
--send STOP SLAVE;
--connection slave
set @@global.debug_dbug="";
set debug_sync= "now SIGNAL continue_row_execution";
--connection slave1
--reap
--source include/wait_for_slave_sql_to_stop.inc
--echo # Slave should be error-free
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
--let $assert_text= Slave should be error free
--let $assert_cond= $last_error = 0
--source include/assert.inc
set debug_sync= "RESET";
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # ROW Test Case 2:
--echo # Using a T multi-statement transaction, ensure if STOP SLAVE is
--echo # issued in-between row updates, that the transaction is rolled back.
--connection master
truncate table ti;
truncate table ti2;
truncate table tm;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--sync_slave_with_master
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=1;
--let $row_count_initial=`select count(*) from (select * from ti UNION ALL select * from tm) t`
--connection master
--echo # Next-to-commit transactional multi-row event should be rolled back
--source include/save_master_gtid.inc
--let $master_gtid_initial= `select @@global.gtid_binlog_pos`
--eval update ti set a=a+1
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--connection slave
set @@global.debug_dbug="+d,pause_after_next_row_exec";
START SLAVE;
set debug_sync= "now WAIT_FOR row_executed";
--connection slave1
--send STOP SLAVE;
--connection slave
set @@global.debug_dbug="";
set debug_sync= "now SIGNAL continue_row_execution";
--connection slave1
--reap
--source include/wait_for_slave_sql_to_stop.inc
--let $row_count_end=`select count(*) from (select * from ti UNION ALL select * from tm) t`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
--let $assert_text= No new rows should have been inserted
--let $assert_cond= $row_count_diff = 0
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
--echo # Comparing master gtid $master_pos to slaves $slave_gtid
--let $assert_text= No transactions should have committed
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
--echo # Slave should be error-free
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
--let $assert_text= Slave should be error free
--let $assert_cond= $last_error = 0
--source include/assert.inc
--connection master
--source include/save_master_gtid.inc
--connection slave
set debug_sync= "RESET";
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Row Test Case 3:
--echo # A workload with a later transaction that updates a sequence table
--echo # should complete all transactions up to the sequence table update.
--echo # Workload:
--echo # T (long running); should commit
--echo # S (waiting for prior commit); should commit
--echo # T (long running); should rollback
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_mode=AGGRESSIVE;
set @@global.slave_parallel_threads=3;
--connection master
SET @old_dbug= @@SESSION.debug_dbug;
SET @@SESSION.debug_dbug="+d,binlog_force_commit_id";
SET @commit_id= 10002;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
select next value for s1;
--source include/save_master_gtid.inc
--eval insert into ti2 values ($ti2_ctr)
--inc $ti2_ctr
SET @@SESSION.debug_dbug=@old_dbug;
--connection slave
LOCK TABLES ti write, ti2 WRITE;
--source include/start_slave.inc
--echo # Wait for replica to progress until the transactions targeting locked tables are stuck on their locks..
--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--echo # Wait for replica to progress until unblocked transactions are queued for group commit..
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to commit' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should not change
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
set @@global.slave_parallel_mode=CONSERVATIVE;
--connection master
--source include/save_master_gtid.inc
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Cleanup
--connection master
DROP TABLE ti, ti2, ti3, tm, tm2, s1;
--source include/save_master_gtid.inc
--connection slave
--source include/sync_with_master_gtid.inc
--source include/stop_slave.inc
--eval set @@global.debug_dbug="$old_debug"
--eval set @@global.slave_parallel_threads=$old_threads
--eval set @@global.slave_parallel_mode=$old_slave_mode
--source include/start_slave.inc
--source include/rpl_end.inc
--echo # End of tests

View File

@@ -0,0 +1,200 @@
#
# Validate that STOP SLAVE works in a timely manner on a parallel replica with
# STATEMENT binary logging format.
#
--source include/have_debug.inc
--source include/master-slave.inc
--source include/have_innodb.inc
--source include/have_binlog_format_statement.inc
--echo #
--echo # Setup
--connection slave
--source include/stop_slave.inc
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
SET STATEMENT sql_log_bin=0 FOR call mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
--let $old_threads= `SELECT @@global.slave_parallel_threads`
--let $old_domain_threads= `SELECT @@global.slave_domain_parallel_threads`
--let $old_slave_mode= `SELECT @@global.slave_parallel_mode`
--let $old_debug_dbug= `SELECT @@global.debug_dbug`
set @@global.slave_parallel_mode=CONSERVATIVE;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
change master to master_use_gtid=slave_pos;
--source include/start_slave.inc
--connect(slave_lock_extra,127.0.0.1,root,,test,$SLAVE_MYPORT)
--echo #
--echo # Initialize test data
--connection master
set statement sql_log_bin=0 for call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
create table ti (a int primary key) engine=innodb;
create table ti2 (a int) engine=innodb;
create table ti3 (a int) engine=innodb;
create table tm (a int) engine=myisam;
create table tm2 (a int) engine=myisam;
--let $ti_ctr= 100
--let $tm_ctr= 200
--let $tm2_ctr= 300
--let $ti2_ctr= 400
--let $ti3_ctr= 500
--sync_slave_with_master
--echo # Run binlog format independent test cases
--source include/rpl_par_stop_slave_quick_common.test
--echo #
--echo # Statement Test Case 1:
--echo # Using one parallel replication worker thread on workload {N,T}, ensure
--echo # the replica finishes the non-transactional transaction, and does not
--echo # start the next
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=1;
--let $row_count_initial=`select count(*) from (select * from ti UNION ALL select * from tm UNION ALL select * from tm2) t`
--connection master
--let $old_binlog_direct= `SELECT @@global.binlog_direct_non_transactional_updates`
SET @@session.binlog_direct_non_transactional_updates= 0;
BEGIN;
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into tm values ($tm_ctr)
--inc $tm_ctr
--eval insert into tm2 values ($tm2_ctr)
--inc $tm_ctr
COMMIT;
--source include/save_master_gtid.inc
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--connection slave
lock tables tm2 write;
START SLAVE;
--echo # Wait for replica to get stuck on held lock
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
--echo # Unlock row-level lock holding transaction
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $row_count_end=`select count(*) from (select * from ti UNION ALL select * from tm UNION ALL select * from tm2) t`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
--let $assert_text= Transaction should have committed
--let $assert_cond= $row_count_diff = 3
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
# N is the non-transactional transaction
--let $assert_text= N should have been applied
--let $assert_cond= $master_pos = $slave_gtid
--source include/assert.inc
--echo # Slave should be error-free
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
--let $assert_text= Slave should be error free
--let $assert_cond= $last_error = 0
--source include/assert.inc
--connection master
--source include/save_master_gtid.inc
--eval SET @@session.binlog_direct_non_transactional_updates= $old_binlog_direct
--connection slave
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Statement Test Case 2:
--echo # If STOP SLAVE is issued on a parallel slave, such that the next to
--echo # commit transaction is T; even if the next event from the group will
--echo # commit the transaction (e.g. XID_EVENT), the transaction should be
--echo # stopped and rolled back.
--connection slave
--source include/stop_slave.inc
set @@global.slave_parallel_threads=1;
--let $row_count_initial=`select count(*) from (select * from ti UNION ALL select * from tm) t`
--connection master
--let $master_gtid_cmp= `select @@global.gtid_binlog_pos`
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--eval insert into ti values ($ti_ctr)
--inc $ti_ctr
--source include/save_master_gtid.inc
--connection slave
LOCK TABLES ti WRITE;
--source include/start_slave.inc
--echo # Wait for replica to begin executing the first transaction
--connection slave
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock' and command LIKE 'Slave_worker';
--source include/wait_condition.inc
--connection slave1
--send STOP SLAVE;
--connection slave
--echo # Wait for replica to signal worker threads to stop
--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for worker thread to stop';
--source include/wait_condition.inc
UNLOCK TABLES;
--source include/wait_for_slave_sql_to_stop.inc
--connection slave1
--reap
--connection slave
--let $row_count_end=`select count(*) from (select * from ti UNION ALL select * from tm) t`
--let $row_count_diff=`select ($row_count_end-$row_count_initial)`
--let $assert_text= No insertions should have committed
--let $assert_cond= $row_count_diff = 0
--source include/assert.inc
--let $slave_gtid= `select @@global.gtid_slave_pos`
--let $assert_text= GTID slave state should increment to the first transaction
--let $assert_cond= $master_gtid_cmp = $slave_gtid
--source include/assert.inc
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # Cleanup
--connection master
DROP TABLE ti, tm, ti2, tm2, ti3;
--source include/save_master_gtid.inc
--connection slave
--source include/sync_with_master_gtid.inc
--source include/stop_slave.inc
--eval set @@global.slave_parallel_threads=$old_threads
--eval set @@global.slave_domain_parallel_threads=$old_domain_threads
--eval set @@global.slave_parallel_mode=$old_slave_mode
--eval set @@global.debug_dbug="$old_debug_dbug"
--source include/start_slave.inc
--source include/rpl_end.inc
--echo # End of tests