mirror of
https://github.com/MariaDB/server.git
synced 2025-11-10 15:56:13 +01:00
The MDL_BACKUP_COMMIT lock used in handler.cc:ha_commit_trans() that is used to block commits as part of FLUSH TABLES WITH READ LOCK and BACKUP STAGE BLOCK_COMMIT can have a notable performance impact We need the commit block to be able to ensure consistent backups. The purpose of this commit is to instead of taking an expensive MDL lock, to protect each commit for a unlikely backup or FTWRL, we would instead add markers to threads that are doing a commit and when BLOCK_COMMIT or a FTWRL lock is used we would do slightly more work to ensure that all threads are taking MDL locks before taking the requested lock. When backup and FTRWL are not running we are now incrementing a global variable and setting a marker in the THD to signal that the thread is in the 'protected commit code block'. When FTWRL or BACKUP STAGE START is executed we enable MDL locking for commits and wait until all threads are outside of the protected block before continuing. When FTWRL and BACKUP STAGE end, we mark that MDL protecting is not anymore needed. The effect is that we change a MDL lock to two atomic increments and two memory assignments and one extra if. This speeds up commits but causes FTWRL and BACKUP STAGE START to be slower to start as they have to wait for active commits to complete. Most of the new logic can be found in the functions: enable_backup_commit_locks(), protect_against_backup() and unprotect_against_backup(). Other things: - The changes in the tests where because BACKUP STAGE START will now block if there are threads inside the 'protected commit block'. Before we waited in the test for BACKUP STAGE BLOCK COMMIT. I have now changed the tests to either wait for BACKUP STAGE START or by doing BACKUP STAGE START early and wait for BACKUP STAGE COMMIT. - Added MDL_request mdl_backup to THD to avoid initializing a new MDL_request for each commit and to simplify some code. This added 448 bytes to the THD.
229 lines
5.6 KiB
Text
229 lines
5.6 KiB
Text
include/master-slave.inc
|
|
[connection master]
|
|
#
|
|
# MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel
|
|
# replication
|
|
#
|
|
connection master;
|
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
|
|
INSERT INTO t1 VALUES(100);
|
|
connection slave;
|
|
call mtr.add_suppression("Deadlock found when trying to get lock");
|
|
call mtr.add_suppression("Commit failed due to failure of an earlier commit");
|
|
include/stop_slave.inc
|
|
SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads;
|
|
SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode;
|
|
SET @@global.slave_parallel_threads= 2;
|
|
SET @@global.slave_parallel_mode = 'optimistic';
|
|
connection master;
|
|
INSERT INTO t1 VALUES (1);
|
|
INSERT INTO t1 VALUES (2);
|
|
connect aux_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (1);
|
|
connection slave;
|
|
include/start_slave.inc
|
|
connection aux_slave;
|
|
connect backup_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
|
|
BACKUP STAGE START;
|
|
connection aux_slave;
|
|
ROLLBACK;
|
|
connection backup_slave;
|
|
BACKUP STAGE END;
|
|
connection slave;
|
|
include/diff_tables.inc [master:t1,slave:t1]
|
|
#
|
|
# Test with blocking BLOCK_COMMIT
|
|
#
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
connection backup_slave;
|
|
BACKUP STAGE START;
|
|
connection master;
|
|
INSERT INTO t1 VALUES (3);
|
|
INSERT INTO t1 VALUES (4);
|
|
connection aux_slave;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (3);
|
|
connection slave;
|
|
include/start_slave.inc
|
|
connection aux_slave;
|
|
connection backup_slave;
|
|
BACKUP STAGE BLOCK_COMMIT;;
|
|
connection aux_slave;
|
|
ROLLBACK;
|
|
connection backup_slave;
|
|
BACKUP STAGE END;
|
|
connection slave;
|
|
include/diff_tables.inc [master:t1,slave:t1]
|
|
#
|
|
# MDEV-30423: dealock XA COMMIT vs BACKUP
|
|
#
|
|
#
|
|
# Normal XA COMMIT
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
connection master;
|
|
connection aux_slave;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (102);
|
|
connection master;
|
|
XA START '1';
|
|
INSERT INTO t1 VALUES (101);
|
|
XA END '1';
|
|
XA PREPARE '1';
|
|
connection master1;
|
|
INSERT INTO t1 VALUES (102);
|
|
connection master;
|
|
XA COMMIT '1';
|
|
include/save_master_gtid.inc
|
|
connection backup_slave;
|
|
BACKUP STAGE START;
|
|
connection slave;
|
|
include/start_slave.inc
|
|
connection aux_slave;
|
|
# Xid '1' must be in the output:
|
|
XA RECOVER;
|
|
formatID gtrid_length bqual_length data
|
|
1 1 0 1
|
|
connection backup_slave;
|
|
BACKUP STAGE BLOCK_COMMIT;
|
|
connection aux_slave;
|
|
ROLLBACK;
|
|
connection backup_slave;
|
|
BACKUP STAGE END;
|
|
connection slave;
|
|
include/sync_with_master_gtid.inc
|
|
include/stop_slave.inc
|
|
#
|
|
# Normal XA ROLLBACK
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
connection master;
|
|
connection aux_slave;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (104);
|
|
connection master;
|
|
XA START '1';
|
|
INSERT INTO t1 VALUES (103);
|
|
XA END '1';
|
|
XA PREPARE '1';
|
|
connection master1;
|
|
INSERT INTO t1 VALUES (104);
|
|
connection master;
|
|
XA ROLLBACK '1';
|
|
include/save_master_gtid.inc
|
|
connection backup_slave;
|
|
BACKUP STAGE START;
|
|
connection slave;
|
|
include/start_slave.inc
|
|
connection aux_slave;
|
|
# Xid '1' must be in the output:
|
|
XA RECOVER;
|
|
formatID gtrid_length bqual_length data
|
|
1 1 0 1
|
|
connection backup_slave;
|
|
BACKUP STAGE BLOCK_COMMIT;
|
|
connection aux_slave;
|
|
ROLLBACK;
|
|
connection backup_slave;
|
|
BACKUP STAGE END;
|
|
connection slave;
|
|
include/sync_with_master_gtid.inc
|
|
include/stop_slave.inc
|
|
#
|
|
# Errored out XA COMMIT
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
connection master;
|
|
connection aux_slave;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (106);
|
|
connection master;
|
|
XA START '1';
|
|
INSERT INTO t1 VALUES (105);
|
|
XA END '1';
|
|
XA PREPARE '1';
|
|
connection master1;
|
|
INSERT INTO t1 VALUES (106);
|
|
connection master;
|
|
XA COMMIT '1';
|
|
include/save_master_gtid.inc
|
|
connection backup_slave;
|
|
BACKUP STAGE START;
|
|
connection slave;
|
|
SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout;
|
|
SET @sav_slave_transaction_retries = @@global.slave_transaction_retries;
|
|
SET @@global.innodb_lock_wait_timeout =5;
|
|
SET @@global.slave_transaction_retries=0;
|
|
include/start_slave.inc
|
|
connection aux_slave;
|
|
# Xid '1' must be in the output:
|
|
XA RECOVER;
|
|
formatID gtrid_length bqual_length data
|
|
1 1 0 1
|
|
connection backup_slave;
|
|
BACKUP STAGE BLOCK_COMMIT;
|
|
connection aux_slave;
|
|
ROLLBACK;
|
|
connection backup_slave;
|
|
BACKUP STAGE END;
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout;
|
|
SET @@global.slave_transaction_retries= @sav_slave_transaction_retries;
|
|
connection slave;
|
|
include/start_slave.inc
|
|
include/sync_with_master_gtid.inc
|
|
#
|
|
# Errored out XA ROLLBACK
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
connection master;
|
|
connection aux_slave;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (108);
|
|
connection master;
|
|
XA START '1';
|
|
INSERT INTO t1 VALUES (107);
|
|
XA END '1';
|
|
XA PREPARE '1';
|
|
connection master1;
|
|
INSERT INTO t1 VALUES (108);
|
|
connection master;
|
|
XA ROLLBACK '1';
|
|
include/save_master_gtid.inc
|
|
connection backup_slave;
|
|
BACKUP STAGE START;
|
|
connection slave;
|
|
SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout;
|
|
SET @sav_slave_transaction_retries = @@global.slave_transaction_retries;
|
|
SET @@global.innodb_lock_wait_timeout =5;
|
|
SET @@global.slave_transaction_retries=0;
|
|
include/start_slave.inc
|
|
connection aux_slave;
|
|
# Xid '1' must be in the output:
|
|
XA RECOVER;
|
|
formatID gtrid_length bqual_length data
|
|
1 1 0 1
|
|
connection backup_slave;
|
|
BACKUP STAGE BLOCK_COMMIT;
|
|
connection aux_slave;
|
|
ROLLBACK;
|
|
connection backup_slave;
|
|
BACKUP STAGE END;
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout;
|
|
SET @@global.slave_transaction_retries= @sav_slave_transaction_retries;
|
|
connection slave;
|
|
include/start_slave.inc
|
|
include/sync_with_master_gtid.inc
|
|
connection slave;
|
|
include/stop_slave.inc
|
|
SET @@global.slave_parallel_threads= @old_parallel_threads;
|
|
SET @@global.slave_parallel_mode = @old_parallel_mode;
|
|
include/start_slave.inc
|
|
connection server_1;
|
|
DROP TABLE t1;
|
|
include/rpl_end.inc
|