mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 11:01:52 +01:00
96784eb106
Parallel replication depends on locking (table locks, row locks, etc.) to prevent two conflicting transactions from running and committing in parallel. But temporary tables are designed to be visible only to one thread, and have no such locking. In the concrete issue, an intermediate master could commit a CREATE TEMPORARY TABLE in the same group commit as in INSERT into that table. Thus, a lower-level master could attempt to run them in parallel and get an error. More generally, we need protection from parallel replication trying to run transactions in parallel that access a common temporary table. This patch simply causes use of a temporary table from parallel replication to wait for all previous transactions to commit, serialising the replication at that point. (A more fine-grained locking could be added later, possibly. However, using temporary tables in statement-based replication is in any case normally undesirable; for example a restart of the server will lose temporary tables and can break replication). Note that row-based replication is not affected, as it does not do any temporary tables on the slave-side. This patch also cleans up the locking around protecting the list of temporary tables in Relay_log_info. This used to take the rli->data_lock at the end of every statement, which is very bad for concurrency. With this patch, the lock is not taken unless temporary tables (with statement-based binlogging) are in use on the slave.
52 lines
2.1 KiB
Text
52 lines
2.1 KiB
Text
include/rpl_init.inc [topology=1->2->3]
|
|
*** MDEV-7668: Intermediate master groups CREATE with INSERT, causing parallel replication failure ***
|
|
SET @old_updates= @@GLOBAL.binlog_direct_non_transactional_updates;
|
|
SET GLOBAL binlog_direct_non_transactional_updates=OFF;
|
|
SET SESSION binlog_direct_non_transactional_updates=OFF;
|
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
|
CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
|
|
include/stop_slave.inc
|
|
SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
|
|
SET GLOBAL slave_parallel_threads=10;
|
|
SET @old_commit_count=@@GLOBAL.binlog_commit_wait_count;
|
|
SET GLOBAL binlog_commit_wait_count=2;
|
|
SET @old_commit_usec=@@GLOBAL.binlog_commit_wait_usec;
|
|
SET GLOBAL binlog_commit_wait_usec=2000000;
|
|
SET @old_updates= @@GLOBAL.binlog_direct_non_transactional_updates;
|
|
SET GLOBAL binlog_direct_non_transactional_updates=OFF;
|
|
SET SESSION binlog_direct_non_transactional_updates=OFF;
|
|
CHANGE MASTER TO master_use_gtid=current_pos;
|
|
SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
|
|
include/stop_slave.inc
|
|
SET GLOBAL slave_parallel_threads=10;
|
|
CHANGE MASTER TO master_use_gtid=current_pos;
|
|
BEGIN;
|
|
CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY) ENGINE=MEMORY;
|
|
COMMIT;
|
|
INSERT INTO t2 VALUES (1);
|
|
INSERT INTO t1 SELECT a, a*10 FROM t2;
|
|
DROP TABLE t2;
|
|
include/save_master_gtid.inc
|
|
include/start_slave.inc
|
|
include/sync_with_master_gtid.inc
|
|
SELECT * FROM t1 ORDER BY a;
|
|
a b
|
|
1 10
|
|
include/start_slave.inc
|
|
include/sync_with_master_gtid.inc
|
|
SELECT * FROM t1 ORDER BY a;
|
|
a b
|
|
1 10
|
|
include/stop_slave.inc
|
|
SET GLOBAL slave_parallel_threads=@old_parallel_threads;
|
|
SET GLOBAL binlog_commit_wait_count=@old_commit_count;
|
|
SET GLOBAL binlog_commit_wait_usec=@old_commit_usec;
|
|
SET GLOBAL binlog_direct_non_transactional_updates= @old_updates;
|
|
include/start_slave.inc
|
|
include/stop_slave.inc
|
|
SET GLOBAL slave_parallel_threads=@old_parallel_threads;
|
|
include/start_slave.inc
|
|
SET GLOBAL binlog_direct_non_transactional_updates= @old_updates;
|
|
CALL mtr.add_suppression("Statement accesses nontransactional table as well as transactional or temporary table");
|
|
DROP TABLE t1;
|
|
include/rpl_end.inc
|