MDEV-30323 Some DDLs like ANALYZE can complete on parallel slave out of order
ANALYZE was observed to race over a preceding in binlog order DML in updating the binlog and slave gtid states. Tagging ANALYZE and other admin class commands in binlog by the fixes of MDEV-17515 left a flaw allowing such race leading to the gtid mode out-of-order error. This is fixed now to observe by ADMIN commands the ordered access to the slave gtid status variables and binlog.
This commit is contained in:
parent
3aa04c0deb
commit
7fe932444d
75
mysql-test/suite/rpl/include/create_or_drop_sync_func.inc
Normal file
75
mysql-test/suite/rpl/include/create_or_drop_sync_func.inc
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Creates or drops a stored function as a part of debug-sync based
|
||||||
|
# synchronization mechanism between replication servers.
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# $create_or_drop= [create]
|
||||||
|
# $server_master = [master]
|
||||||
|
# $server_slave = [slave]
|
||||||
|
if (!$create_or_drop)
|
||||||
|
{
|
||||||
|
--let $create_or_drop=create
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`select strcmp('$create_or_drop', 'create') = 0`)
|
||||||
|
{
|
||||||
|
if (!$server_master)
|
||||||
|
{
|
||||||
|
--let $server_master=master
|
||||||
|
}
|
||||||
|
if (!$server_slave)
|
||||||
|
{
|
||||||
|
--let $server_slave=slave
|
||||||
|
}
|
||||||
|
|
||||||
|
--connection $server_master
|
||||||
|
# Use a stored function to inject a debug_sync into the appropriate THD.
|
||||||
|
# The function does nothing on the master, and on the slave it injects the
|
||||||
|
# desired debug_sync action(s).
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
--delimiter ||
|
||||||
|
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||||
|
RETURNS INT DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
RETURN x;
|
||||||
|
END
|
||||||
|
||
|
||||||
|
--delimiter ;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
--connection $server_slave
|
||||||
|
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
--delimiter ||
|
||||||
|
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||||
|
RETURNS INT DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
IF d1 != '' THEN
|
||||||
|
SET debug_sync = d1;
|
||||||
|
END IF;
|
||||||
|
IF d2 != '' THEN
|
||||||
|
SET debug_sync = d2;
|
||||||
|
END IF;
|
||||||
|
RETURN x;
|
||||||
|
END
|
||||||
|
||
|
||||||
|
--delimiter ;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`select strcmp('$create_or_drop', 'drop') = 0`)
|
||||||
|
{
|
||||||
|
if (!$server_slave)
|
||||||
|
{
|
||||||
|
--let $server_slave=slave=
|
||||||
|
}
|
||||||
|
if (!$server_master)
|
||||||
|
{
|
||||||
|
--let $server_master=master
|
||||||
|
}
|
||||||
|
--connection $server_slave
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
|
||||||
|
--connection $server_master
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
DROP FUNCTION foo;
|
||||||
|
}
|
75
mysql-test/suite/rpl/r/rpl_parallel_analyze.result
Normal file
75
mysql-test/suite/rpl/r/rpl_parallel_analyze.result
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
include/master-slave.inc
|
||||||
|
[connection master]
|
||||||
|
# Initialize
|
||||||
|
connection slave;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||||
|
# Setup data
|
||||||
|
connection master;
|
||||||
|
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE ta (a int);
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
connection master;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||||
|
RETURNS INT DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
RETURN x;
|
||||||
|
END
|
||||||
|
||
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
connection slave;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||||
|
RETURNS INT DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
IF d1 != '' THEN
|
||||||
|
SET debug_sync = d1;
|
||||||
|
END IF;
|
||||||
|
IF d2 != '' THEN
|
||||||
|
SET debug_sync = d2;
|
||||||
|
END IF;
|
||||||
|
RETURN x;
|
||||||
|
END
|
||||||
|
||
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @old_parallel_threads =@@GLOBAL.slave_parallel_threads;
|
||||||
|
SET @old_parallel_mode =@@GLOBAL.slave_parallel_mode;
|
||||||
|
SET @old_gtid_strict_mode =@@GLOBAL.gtid_strict_mode;
|
||||||
|
SET GLOBAL slave_parallel_threads=10;
|
||||||
|
SET GLOBAL slave_parallel_mode=conservative;
|
||||||
|
SET GLOBAL gtid_strict_mode=ON;
|
||||||
|
include/start_slave.inc
|
||||||
|
connection master;
|
||||||
|
SET @old_format= @@SESSION.binlog_format;
|
||||||
|
SET binlog_format=statement;
|
||||||
|
INSERT INTO t1 VALUES (foo(1, 'rpl_parallel_after_mark_start_commit WAIT_FOR sig_go', ''));
|
||||||
|
ANALYZE TABLE ta;
|
||||||
|
Table Op Msg_type Msg_text
|
||||||
|
test.ta analyze status Table is already up to date
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
SELECT info FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit";
|
||||||
|
info
|
||||||
|
ANALYZE TABLE ta
|
||||||
|
set @@debug_sync="now signal sig_go";
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
# Cleanup
|
||||||
|
connection master;
|
||||||
|
DROP TABLE t1,ta;
|
||||||
|
connection slave;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
connection master;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
DROP FUNCTION foo;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads;
|
||||||
|
SET @@GLOBAL.slave_parallel_mode =@old_parallel_mode;
|
||||||
|
SET @@GLOBAL.gtid_strict_mode =@old_gtid_strict_mode;
|
||||||
|
include/start_slave.inc
|
||||||
|
include/rpl_end.inc
|
84
mysql-test/suite/rpl/t/rpl_parallel_analyze.test
Normal file
84
mysql-test/suite/rpl/t/rpl_parallel_analyze.test
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# The test file is created to prove fixes to
|
||||||
|
# MDEV-30323 Some DDLs like ANALYZE can complete on parallel slave out of order
|
||||||
|
# Debug-sync tests aiming at parallel replication of ADMIN commands
|
||||||
|
# are welcome here.
|
||||||
|
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
--source include/master-slave.inc
|
||||||
|
|
||||||
|
--echo # Initialize
|
||||||
|
--connection slave
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||||
|
|
||||||
|
--echo # Setup data
|
||||||
|
--connection master
|
||||||
|
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE ta (a int);
|
||||||
|
--let $pre_load_gtid=`SELECT @@last_gtid`
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
|
||||||
|
--source suite/rpl/include/create_or_drop_sync_func.inc
|
||||||
|
|
||||||
|
# configure MDEV-30323 slave
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET @old_parallel_threads =@@GLOBAL.slave_parallel_threads;
|
||||||
|
SET @old_parallel_mode =@@GLOBAL.slave_parallel_mode;
|
||||||
|
SET @old_gtid_strict_mode =@@GLOBAL.gtid_strict_mode;
|
||||||
|
SET GLOBAL slave_parallel_threads=10;
|
||||||
|
SET GLOBAL slave_parallel_mode=conservative;
|
||||||
|
SET GLOBAL gtid_strict_mode=ON;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
# MDEV-30323 setup needs two group of events the first of which is a DML
|
||||||
|
# and ANALYZE is the 2nd.
|
||||||
|
# The latter is made to race in slave execution over the DML thanks
|
||||||
|
# to a DML latency simulation.
|
||||||
|
# In the fixed case the race-over should not be a problem: ultimately
|
||||||
|
# ANALYZE must wait for its turn to update slave@@global.gtid_binlog_pos.
|
||||||
|
# Otherwise the reported OOO error must be issued.
|
||||||
|
|
||||||
|
--connection master
|
||||||
|
SET @old_format= @@SESSION.binlog_format;
|
||||||
|
SET binlog_format=statement;
|
||||||
|
INSERT INTO t1 VALUES (foo(1, 'rpl_parallel_after_mark_start_commit WAIT_FOR sig_go', ''));
|
||||||
|
|
||||||
|
ANALYZE TABLE ta;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit"
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
SELECT info FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit";
|
||||||
|
if (`select strcmp(@@global.gtid_binlog_pos, '$pre_load_gtid') <> 0 or strcmp(@@global.gtid_slave_pos, '$pre_load_gtid') <> 0`)
|
||||||
|
{
|
||||||
|
--let $bs=`SELECT @@global.gtid_binlog_pos`
|
||||||
|
--let $es=`SELECT @@global.gtid_slave_pos`
|
||||||
|
--echo Mismatch between expected $pre_load_gtid state and the actual binlog state " @@global.gtid_binlog_pos = $bs or/and slave execution state @@global.gtid_slave_pos = $es.
|
||||||
|
--die
|
||||||
|
}
|
||||||
|
|
||||||
|
set @@debug_sync="now signal sig_go";
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
|
||||||
|
--echo # Cleanup
|
||||||
|
--connection master
|
||||||
|
DROP TABLE t1,ta;
|
||||||
|
--let $create_or_drop=drop
|
||||||
|
--source suite/rpl/include/create_or_drop_sync_func.inc
|
||||||
|
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads;
|
||||||
|
SET @@GLOBAL.slave_parallel_mode =@old_parallel_mode;
|
||||||
|
SET @@GLOBAL.gtid_strict_mode =@old_gtid_strict_mode;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--source include/rpl_end.inc
|
@ -1249,16 +1249,16 @@ send_result_message:
|
|||||||
goto err;
|
goto err;
|
||||||
DEBUG_SYNC(thd, "admin_command_kill_after_modify");
|
DEBUG_SYNC(thd, "admin_command_kill_after_modify");
|
||||||
}
|
}
|
||||||
|
thd->resume_subsequent_commits(suspended_wfc);
|
||||||
|
DBUG_EXECUTE_IF("inject_analyze_table_sleep", my_sleep(500000););
|
||||||
if (is_table_modified && is_cmd_replicated &&
|
if (is_table_modified && is_cmd_replicated &&
|
||||||
(!opt_readonly || thd->slave_thread) && !thd->lex->no_write_to_binlog)
|
(!opt_readonly || thd->slave_thread) && !thd->lex->no_write_to_binlog)
|
||||||
{
|
{
|
||||||
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_eof(thd);
|
my_eof(thd);
|
||||||
thd->resume_subsequent_commits(suspended_wfc);
|
|
||||||
DBUG_EXECUTE_IF("inject_analyze_table_sleep", my_sleep(500000););
|
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user