mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-21117: refine the server binlog-based recovery for semisync
Problem: ======= When the semisync master is crashed and restarted as slave it could recover transactions that former slaves may never have seen. A known method existed to clear out all prepared transactions with --tc-heuristic-recover=rollback does not care to adjust binlog accordingly. Fix: === The binlog-based recovery is made to concern of the slave semisync role of post-crash restarted server. No changes in behavior is done to the "normal" binloggging server and the semisync master. When the restarted server is configured with --rpl-semi-sync-slave-enabled=1 the refined recovery attempts to roll back prepared transactions and truncate binlog accordingly. In case of a partially committed (that is committed at least in one of the engine participants) such transaction gets committed. It's guaranteed no (partially as well) committed transactions exist beyond the truncate position. In case there exists a non-transactional replication event (being in a way a committed transaction) past the computed truncate position the recovery ends with an error. As after master crash and failover to slave, the demoted-to-slave ex-master must be ready to face and accept its own (generated by) events, without generally necessary --replicate-same-server-id. So the acceptance conditions are relaxed for the semisync slave to accept own events without that option. While gtid_strict_mode ON ensures no duplicate transaction can be (re-)executed the master_use_gtid=none slave has to be configured with --replicate-same-server-id. *NOTE* for reviewers. This patch does not handle the user XA which is done in next git commit.
This commit is contained in:
102
mysql-test/suite/binlog/t/binlog_truncate_active_log.test
Normal file
102
mysql-test/suite/binlog/t/binlog_truncate_active_log.test
Normal file
@@ -0,0 +1,102 @@
|
||||
# ==== Purpose ====
|
||||
#
|
||||
# Test verifies the truncation of single binary log file.
|
||||
#
|
||||
# ==== References ====
|
||||
#
|
||||
# MDEV-21117: recovery for --rpl-semi-sync-slave-enabled server
|
||||
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_aria.inc
|
||||
# File: binlog_truncate_active_log.inc included in test makes use of
|
||||
# 'debug_sync' facility.
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/have_binlog_format_statement.inc
|
||||
|
||||
call mtr.add_suppression("Can.t init tc log");
|
||||
call mtr.add_suppression("Aborting");
|
||||
|
||||
# The following cases are tested:
|
||||
# A. 2pc transaction is followed by a blank "zero-engines" one
|
||||
# B. 2pc transaction follows the blank one
|
||||
# C. Similarly to A, with the XA blank transaction
|
||||
|
||||
RESET MASTER;
|
||||
CREATE TABLE t (f INT) ENGINE=INNODB;
|
||||
CREATE TABLE t2 (f INT) ENGINE=INNODB;
|
||||
CREATE TABLE tm (f INT) ENGINE=Aria;
|
||||
|
||||
# Old (pre-crash) binlog file index initial value.
|
||||
# It keeps incremented at the end of each case.
|
||||
--let $binlog_file_index=1
|
||||
|
||||
--echo # Case A.
|
||||
# Using 'debug_sync' hold 'query1' execution after 'query1' is flushed and
|
||||
# synced to binary log but not yet committed. In an another connection hold
|
||||
# 'query2' execution after 'query2' is flushed and synced to binlog.
|
||||
# Crash and restart server with --rpl-semi-sync-slave-enabled=1
|
||||
#
|
||||
# During recovery of binary log 'query1' status is checked with InnoDB engine,
|
||||
# it will be in prepared but not yet commited. All transactions starting from
|
||||
# 'query1' onwards will be removed from the binary log.
|
||||
# Show-binlog-events is to prove that.
|
||||
|
||||
--let $truncate_gtid_pos = 0-1-6
|
||||
--let $query1 = INSERT INTO t VALUES (20)
|
||||
--let $query2 = DELETE FROM t2 WHERE f = 0 /* no such record */
|
||||
--source binlog_truncate_active_log.inc
|
||||
|
||||
--echo # Case B.
|
||||
# The inverted sequence ends up to truncate starting from $query2
|
||||
--let $truncate_gtid_pos = 0-1-10
|
||||
--let $query1 = DELETE FROM t2 WHERE f = 0
|
||||
--let $query2 = INSERT INTO t VALUES (20)
|
||||
--source binlog_truncate_active_log.inc
|
||||
|
||||
|
||||
--echo # Case C.
|
||||
delimiter |;
|
||||
CREATE PROCEDURE sp_blank_xa()
|
||||
BEGIN
|
||||
XA START 'blank';
|
||||
DELETE FROM t2 WHERE f = 0 /* no such record */;
|
||||
XA END 'blank';
|
||||
XA PREPARE 'blank';
|
||||
END|
|
||||
delimiter ;|
|
||||
|
||||
# The same as in A with $query2 being the zero-engine XA transaction.
|
||||
# Both $query1 and $query2 are going to be truncated.
|
||||
--let $truncate_gtid_pos = 0-1-14
|
||||
--let $query1 = INSERT INTO t VALUES (20)
|
||||
--let $query2 = CALL sp_blank_xa
|
||||
--source binlog_truncate_active_log.inc
|
||||
|
||||
DROP PROCEDURE sp_blank_xa;
|
||||
|
||||
|
||||
--echo # Case D.
|
||||
delimiter |;
|
||||
CREATE PROCEDURE sp_xa()
|
||||
BEGIN
|
||||
XA START 'xid';
|
||||
DELETE FROM t WHERE f = 10;
|
||||
XA END 'xid';
|
||||
XA PREPARE 'xid';
|
||||
END|
|
||||
delimiter ;|
|
||||
|
||||
# The same as in B with $query1 being the prepared XA transaction.
|
||||
# Truncation must occurs at $query2.
|
||||
--let $truncate_gtid_pos = 0-1-20
|
||||
--let $query1 = CALL sp_xa
|
||||
--let $query2 = INSERT INTO t2 VALUES (20)
|
||||
--source binlog_truncate_active_log.inc
|
||||
|
||||
DROP PROCEDURE sp_xa;
|
||||
|
||||
|
||||
--echo # Cleanup
|
||||
DROP TABLE t,t2,tm;
|
||||
|
||||
--echo # End of the tests
|
Reference in New Issue
Block a user