mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
MDEV-6549, failing to update gtid_slave_pos for a transaction that was retried.
The bug was that in some cases, if a replicated transaction was rolled back due to deadlock, during the subsequent retry of that transaction, the gtid_slave_pos would _not_ be updated with the new GTID, leaving the GTID position of the slave incorrect. Fix this by ensuring during the retry that we clear the flag that marks that the GTID has already been recorded in gtid_slave_pos, so that the update of gtid_slave_pos will be done again during the retry. In the original bug, the symptom was an assertion due to OPTION_GTID_BEGIN not being cleared during the retry of the transaction. The reason was some code in handling of a COMMIT query event, which would not clear the flag when not recording a GTID in gtid_slave_pos. This commit also fixes that code to always clear the OPTION_GTID_BEGIN flag for clarity, though it is actually not possible for OPTION_GTID_BEGIN to become set unless a GTID is pending for update (after fixing the bug described above).
This commit is contained in:
@ -1246,10 +1246,78 @@ SET debug_sync='RESET';
|
||||
--connection server_2
|
||||
--source include/start_slave.inc
|
||||
--sync_with_master
|
||||
--source include/stop_slave.inc
|
||||
|
||||
SELECT * FROM t4 ORDER BY a;
|
||||
|
||||
|
||||
# MDEV-6549, failing to update gtid_slave_pos for a transaction that was retried.
|
||||
# The problem was that when a transaction updates the mysql.gtid_slave_pos
|
||||
# table, it clears the flag that marks that there is a GTID position that
|
||||
# needs to be updated. Then, if the transaction got killed after that due
|
||||
# to a deadlock, the subsequent retry would fail to notice that the GTID needs
|
||||
# to be recorded in gtid_slave_pos.
|
||||
#
|
||||
# (In the original bug report, the symptom was an assertion; this was however
|
||||
# just a side effect of the missing update of gtid_slave_pos, which also
|
||||
# happened to cause a missing clear of OPTION_GTID_BEGIN).
|
||||
--connection server_1
|
||||
DELETE FROM t4;
|
||||
INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
|
||||
|
||||
# Create two transactions that can run in parallel on the slave but cause
|
||||
# a deadlock if the second runs before the first.
|
||||
--connection con1
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
|
||||
send UPDATE t4 SET b=NULL WHERE a=6;
|
||||
--connection server_1
|
||||
SET debug_sync='now WAIT_FOR master_queued1';
|
||||
|
||||
--connection con2
|
||||
# Must use statement-based binlogging. Otherwise the transaction will not be
|
||||
# binlogged at all, as it modifies no rows.
|
||||
SET @old_format= @@SESSION.binlog_format;
|
||||
SET binlog_format='statement';
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
|
||||
send DELETE FROM t4 WHERE b <= 1;
|
||||
|
||||
--connection server_1
|
||||
SET debug_sync='now WAIT_FOR master_queued2';
|
||||
SET debug_sync='now SIGNAL master_cont1';
|
||||
|
||||
--connection con1
|
||||
REAP;
|
||||
--connection con2
|
||||
REAP;
|
||||
SET @old_format=@@GLOBAL.binlog_format;
|
||||
SET debug_sync='RESET';
|
||||
--save_master_pos
|
||||
--let $last_gtid= `SELECT @@last_gtid`
|
||||
|
||||
--connection server_2
|
||||
# Disable the usual skip of gap locks for transactions that are run in
|
||||
# parallel, using DBUG. This allows the deadlock to occur, and this in turn
|
||||
# triggers a retry of the second transaction, and the code that was buggy and
|
||||
# caused the gtid_slave_pos update to be skipped in the retry.
|
||||
SET @old_dbug= @@GLOBAL.debug_dbug;
|
||||
SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with";
|
||||
--source include/start_slave.inc
|
||||
--sync_with_master
|
||||
SET GLOBAL debug_dbug=@old_dbug;
|
||||
|
||||
SELECT * FROM t4 ORDER BY a;
|
||||
# Check that the GTID of the second transaction was correctly recorded in
|
||||
# gtid_slave_pos, in the variable as well as in the table.
|
||||
--replace_result $last_gtid GTID
|
||||
eval SET @last_gtid= '$last_gtid';
|
||||
SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok",
|
||||
CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos))
|
||||
AS result;
|
||||
SELECT "ROW FOUND" AS `Is the row found?`
|
||||
FROM mysql.gtid_slave_pos
|
||||
WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid;
|
||||
|
||||
|
||||
--echo *** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication ***
|
||||
--connection server_2
|
||||
--source include/stop_slave.inc
|
||||
|
Reference in New Issue
Block a user