Browse Source
MDEV-5363: Make parallel replication waits killable
MDEV-5363: Make parallel replication waits killable
Add another test case. This one for killing a query that is waiting for a prior commit, when --log-slave-updates=0 (in this case the wait happens in different code from --log-slave-updates=1).pull/3/head
5 changed files with 332 additions and 2 deletions
-
122mysql-test/suite/rpl/r/rpl_parallel_no_log_slave_updates.result
-
1mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates-slave.opt
-
199mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates.test
-
10sql/handler.cc
-
2sql/sql_class.cc
@ -0,0 +1,122 @@ |
|||
include/rpl_init.inc [topology=1->2] |
|||
*** Test killing transaction waiting in commit for previous transaction to commit, when not using 2-phase commit *** |
|||
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 |
|||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; |
|||
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; |
|||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; |
|||
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 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, |
|||
'ha_commit_one_phase WAIT_FOR t2_waiting', |
|||
'commit_one_phase_2 SIGNAL t1_ready WAIT_FOR t1_cont')); |
|||
SET debug_sync='now WAIT_FOR master_queued1'; |
|||
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, |
|||
'wait_for_prior_commit_waiting SIGNAL t2_waiting', |
|||
'wait_for_prior_commit_killed SIGNAL t2_killed')); |
|||
COMMIT; |
|||
SET debug_sync='now WAIT_FOR master_queued2'; |
|||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; |
|||
SET binlog_format=statement; |
|||
INSERT INTO t3 VALUES (34, foo(34, |
|||
'', |
|||
'')); |
|||
SET debug_sync='now WAIT_FOR master_queued3'; |
|||
SET debug_sync='now SIGNAL master_cont1'; |
|||
SELECT * FROM t3 WHERE a >= 30 ORDER BY a; |
|||
a b |
|||
31 31 |
|||
32 32 |
|||
33 33 |
|||
34 34 |
|||
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,1963] |
|||
STOP SLAVE IO_THREAD; |
|||
SELECT * FROM t3 WHERE a >= 30 ORDER BY a; |
|||
a b |
|||
31 31 |
|||
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; |
|||
INSERT INTO t3 VALUES (39,0); |
|||
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; |
|||
include/stop_slave.inc |
|||
SET GLOBAL slave_parallel_threads=0; |
|||
SET GLOBAL slave_parallel_threads=10; |
|||
include/start_slave.inc |
|||
include/stop_slave.inc |
|||
SET GLOBAL slave_parallel_threads=@old_parallel_threads; |
|||
include/start_slave.inc |
|||
DROP function foo; |
|||
DROP TABLE t3; |
|||
include/rpl_end.inc |
@ -0,0 +1 @@ |
|||
--log-slave-updates=0 |
@ -0,0 +1,199 @@ |
|||
--source include/have_innodb.inc |
|||
--source include/have_debug.inc |
|||
--source include/have_debug_sync.inc |
|||
--source include/have_binlog_format_statement.inc |
|||
--let $rpl_topology=1->2 |
|||
--source include/rpl_init.inc |
|||
|
|||
--echo *** Test killing transaction waiting in commit for previous transaction to commit, when not using 2-phase commit *** |
|||
|
|||
--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; |
|||
# 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; |
|||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; |
|||
--save_master_pos |
|||
|
|||
--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; |
|||
--sync_with_master |
|||
|
|||
|
|||
# Set up three transactions on the master that will be group-committed |
|||
# together so they can be replicated in parallel on the slave. |
|||
--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 (31, foo(31, |
|||
'ha_commit_one_phase WAIT_FOR t2_waiting', |
|||
'commit_one_phase_2 SIGNAL t1_ready WAIT_FOR t1_cont')); |
|||
|
|||
--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; |
|||
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, |
|||
'wait_for_prior_commit_waiting SIGNAL t2_waiting', |
|||
'wait_for_prior_commit_killed SIGNAL t2_killed')); |
|||
send COMMIT; |
|||
|
|||
--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 (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; |
|||
|
|||
--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,1963 |
|||
--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 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 |
|||
|
|||
|
|||
--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 function foo; |
|||
DROP TABLE t3; |
|||
|
|||
--source include/rpl_end.inc |
Write
Preview
Loading…
Cancel
Save
Reference in new issue