mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +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:
237
mysql-test/suite/binlog/r/binlog_truncate_active_log.result
Normal file
237
mysql-test/suite/binlog/r/binlog_truncate_active_log.result
Normal file
@@ -0,0 +1,237 @@
|
||||
call mtr.add_suppression("Can.t init tc log");
|
||||
call mtr.add_suppression("Aborting");
|
||||
RESET MASTER;
|
||||
CREATE TABLE t (f INT) ENGINE=INNODB;
|
||||
CREATE TABLE t2 (f INT) ENGINE=INNODB;
|
||||
CREATE TABLE tm (f INT) ENGINE=Aria;
|
||||
# Case A.
|
||||
connect master1,localhost,root,,;
|
||||
connect master2,localhost,root,,;
|
||||
connect master3,localhost,root,,;
|
||||
connection default;
|
||||
INSERT INTO t VALUES (10);
|
||||
INSERT INTO tm VALUES (10);
|
||||
connection master1;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL master1_ready WAIT_FOR signal_never_arrives";
|
||||
INSERT INTO t VALUES (20);
|
||||
connection master2;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master1_ready";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL master2_ready";
|
||||
DELETE FROM t2 WHERE f = 0 /* no such record */;
|
||||
connection master3;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master2_ready";
|
||||
SELECT @@global.gtid_binlog_pos as 'Before the crash';
|
||||
Before the crash
|
||||
0-1-7
|
||||
connection default;
|
||||
# Kill the server
|
||||
disconnect master1;
|
||||
disconnect master2;
|
||||
disconnect master3;
|
||||
# restart: --rpl-semi-sync-slave-enabled=1
|
||||
FOUND 1 /Successfully truncated.*to remove transactions starting from GTID 0-1-6/ in mysqld.1.err
|
||||
Pre-crash binlog file content:
|
||||
include/show_binlog_events.inc
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE t (f INT) ENGINE=INNODB
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (f INT) ENGINE=INNODB
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE tm (f INT) ENGINE=Aria
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (10)
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO tm VALUES (10)
|
||||
master-bin.000001 # Query # # COMMIT
|
||||
SELECT @@global.gtid_binlog_pos as 'After the crash';
|
||||
After the crash
|
||||
0-1-5
|
||||
"One row should be present in table 't'"
|
||||
SELECT * FROM t;
|
||||
f
|
||||
10
|
||||
DELETE FROM t;
|
||||
# Case B.
|
||||
connect master1,localhost,root,,;
|
||||
connect master2,localhost,root,,;
|
||||
connect master3,localhost,root,,;
|
||||
connection default;
|
||||
INSERT INTO t VALUES (10);
|
||||
INSERT INTO tm VALUES (10);
|
||||
connection master1;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL master1_ready WAIT_FOR signal_never_arrives";
|
||||
DELETE FROM t2 WHERE f = 0;
|
||||
connection master2;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master1_ready";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL master2_ready";
|
||||
INSERT INTO t VALUES (20);
|
||||
connection master3;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master2_ready";
|
||||
SELECT @@global.gtid_binlog_pos as 'Before the crash';
|
||||
Before the crash
|
||||
0-1-10
|
||||
connection default;
|
||||
# Kill the server
|
||||
disconnect master1;
|
||||
disconnect master2;
|
||||
disconnect master3;
|
||||
# restart: --rpl-semi-sync-slave-enabled=1
|
||||
FOUND 1 /Successfully truncated.*to remove transactions starting from GTID 0-1-10/ in mysqld.1.err
|
||||
Pre-crash binlog file content:
|
||||
include/show_binlog_events.inc
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000002 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000002 # Query # # use `test`; DELETE FROM t
|
||||
master-bin.000002 # Xid # # COMMIT /* XID */
|
||||
master-bin.000002 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000002 # Query # # use `test`; INSERT INTO t VALUES (10)
|
||||
master-bin.000002 # Xid # # COMMIT /* XID */
|
||||
master-bin.000002 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000002 # Query # # use `test`; INSERT INTO tm VALUES (10)
|
||||
master-bin.000002 # Query # # COMMIT
|
||||
master-bin.000002 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000002 # Query # # use `test`; DELETE FROM t2 WHERE f = 0
|
||||
master-bin.000002 # Query # # COMMIT
|
||||
SELECT @@global.gtid_binlog_pos as 'After the crash';
|
||||
After the crash
|
||||
0-1-9
|
||||
"One row should be present in table 't'"
|
||||
SELECT * FROM t;
|
||||
f
|
||||
10
|
||||
DELETE FROM t;
|
||||
# Case C.
|
||||
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|
|
||||
connect master1,localhost,root,,;
|
||||
connect master2,localhost,root,,;
|
||||
connect master3,localhost,root,,;
|
||||
connection default;
|
||||
INSERT INTO t VALUES (10);
|
||||
INSERT INTO tm VALUES (10);
|
||||
connection master1;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL master1_ready WAIT_FOR signal_never_arrives";
|
||||
INSERT INTO t VALUES (20);
|
||||
connection master2;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master1_ready";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL master2_ready";
|
||||
CALL sp_blank_xa;
|
||||
connection master3;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master2_ready";
|
||||
SELECT @@global.gtid_binlog_pos as 'Before the crash';
|
||||
Before the crash
|
||||
0-1-15
|
||||
connection default;
|
||||
# Kill the server
|
||||
disconnect master1;
|
||||
disconnect master2;
|
||||
disconnect master3;
|
||||
# restart: --rpl-semi-sync-slave-enabled=1
|
||||
FOUND 1 /Successfully truncated.*to remove transactions starting from GTID 0-1-14/ in mysqld.1.err
|
||||
Pre-crash binlog file content:
|
||||
include/show_binlog_events.inc
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000003 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000003 # Query # # use `test`; DELETE FROM t
|
||||
master-bin.000003 # Xid # # COMMIT /* XID */
|
||||
master-bin.000003 # Gtid # # GTID #-#-#
|
||||
master-bin.000003 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_blank_xa`()
|
||||
BEGIN
|
||||
XA START 'blank';
|
||||
DELETE FROM t2 WHERE f = 0 /* no such record */;
|
||||
XA END 'blank';
|
||||
XA PREPARE 'blank';
|
||||
END
|
||||
master-bin.000003 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000003 # Query # # use `test`; INSERT INTO t VALUES (10)
|
||||
master-bin.000003 # Xid # # COMMIT /* XID */
|
||||
master-bin.000003 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000003 # Query # # use `test`; INSERT INTO tm VALUES (10)
|
||||
master-bin.000003 # Query # # COMMIT
|
||||
SELECT @@global.gtid_binlog_pos as 'After the crash';
|
||||
After the crash
|
||||
0-1-13
|
||||
"One row should be present in table 't'"
|
||||
SELECT * FROM t;
|
||||
f
|
||||
10
|
||||
DELETE FROM t;
|
||||
DROP PROCEDURE sp_blank_xa;
|
||||
# Case D.
|
||||
CREATE PROCEDURE sp_xa()
|
||||
BEGIN
|
||||
XA START 'xid';
|
||||
DELETE FROM t WHERE f = 10;
|
||||
XA END 'xid';
|
||||
XA PREPARE 'xid';
|
||||
END|
|
||||
connect master1,localhost,root,,;
|
||||
connect master2,localhost,root,,;
|
||||
connect master3,localhost,root,,;
|
||||
connection default;
|
||||
INSERT INTO t VALUES (10);
|
||||
INSERT INTO tm VALUES (10);
|
||||
connection master1;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL master1_ready WAIT_FOR signal_never_arrives";
|
||||
CALL sp_xa;
|
||||
connection master2;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master1_ready";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL master2_ready";
|
||||
INSERT INTO t2 VALUES (20);
|
||||
connection master3;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR master2_ready";
|
||||
SELECT @@global.gtid_binlog_pos as 'Before the crash';
|
||||
Before the crash
|
||||
0-1-20
|
||||
connection default;
|
||||
# Kill the server
|
||||
disconnect master1;
|
||||
disconnect master2;
|
||||
disconnect master3;
|
||||
# restart: --rpl-semi-sync-slave-enabled=1
|
||||
FOUND 1 /Successfully truncated.*to remove transactions starting from GTID 0-1-20/ in mysqld.1.err
|
||||
Pre-crash binlog file content:
|
||||
include/show_binlog_events.inc
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000004 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000004 # Query # # use `test`; DELETE FROM t
|
||||
master-bin.000004 # Xid # # COMMIT /* XID */
|
||||
master-bin.000004 # Gtid # # GTID #-#-#
|
||||
master-bin.000004 # Query # # use `test`; DROP PROCEDURE sp_blank_xa
|
||||
master-bin.000004 # Gtid # # GTID #-#-#
|
||||
master-bin.000004 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_xa`()
|
||||
BEGIN
|
||||
XA START 'xid';
|
||||
DELETE FROM t WHERE f = 10;
|
||||
XA END 'xid';
|
||||
XA PREPARE 'xid';
|
||||
END
|
||||
master-bin.000004 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000004 # Query # # use `test`; INSERT INTO t VALUES (10)
|
||||
master-bin.000004 # Xid # # COMMIT /* XID */
|
||||
master-bin.000004 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000004 # Query # # use `test`; INSERT INTO tm VALUES (10)
|
||||
master-bin.000004 # Query # # COMMIT
|
||||
master-bin.000004 # Gtid # # XA START X'786964',X'',1 GTID #-#-#
|
||||
master-bin.000004 # Query # # use `test`; DELETE FROM t WHERE f = 10
|
||||
master-bin.000004 # Query # # XA END X'786964',X'',1
|
||||
master-bin.000004 # XA_prepare # # XA PREPARE X'786964',X'',1
|
||||
SELECT @@global.gtid_binlog_pos as 'After the crash';
|
||||
After the crash
|
||||
0-1-19
|
||||
"One row should be present in table 't'"
|
||||
SELECT * FROM t;
|
||||
f
|
||||
10
|
||||
DELETE FROM t;
|
||||
DROP PROCEDURE sp_xa;
|
||||
# Cleanup
|
||||
DROP TABLE t,t2,tm;
|
||||
# End of the tests
|
Reference in New Issue
Block a user