Commit 2f761fd1 authored by Kristian Nielsen's avatar Kristian Nielsen

MDEV-26632: GTID master switch when slave position is filtered on new master

If an intermediate slave S1 has replication filters enabled, its
@@gtid_slave_pos may contain a GTID that is filtered and doesn't propagate
to lower-level slaves with S1 as master.

If then later S1 is demoted to a slave, it may attempt to connect to the
filtered position. This is normally disallowed in --gtid-strict-mode. But if
--gtid-ignore-duplicates is enabled, we should allow it, as in this case we
can trust the GTID sequence numbers between different server ids. So we can
know that the next GTID is the right one for the filtered slave GTID
position.

This allows advanced users to use replication filtering in topologies like
this and still run with --gtid-strict-mode enabled.
Signed-off-by: default avatarKristian Nielsen <knielsen@knielsen-hq.org>
parent 2430b7a4
include/rpl_init.inc [topology=1->2->3]
*** Test GTID master switch in a topology with filtered events.
*** With --gtid-ignore-duplicate and --gtid-strict-mode, should allow
*** GTID connect at a GTID position that is filtered on the new master.
connection server_1;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,1);
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t3 VALUES (1,1);
INSERT INTO t1 VALUES (2,1);
INSERT INTO t3 VALUES (2,1);
include/save_master_gtid.inc
connection server_2;
CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1,2);
include/sync_with_master_gtid.inc
include/save_master_gtid.inc
connection server_3;
include/sync_with_master_gtid.inc
*** Promote 3 as new master, demote 2 as slave of 3.
*** GTID position of 2 in domain 0 is filtered on 3.
connection server_2;
include/stop_slave.inc
connection server_3;
include/stop_slave.inc
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_1,
MASTER_USE_GTID=SLAVE_POS;
connection server_2;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_3,
MASTER_USE_GTID=SLAVE_POS;
include/start_slave.inc
connection server_3;
include/start_slave.inc
connection server_1;
INSERT INTO t1 VALUES (3,1);
INSERT INTO t3 VALUES (3,1);
include/save_master_gtid.inc
connection server_3;
INSERT INTO t2 VALUES (2,2);
include/sync_with_master_gtid.inc
include/save_master_gtid.inc
connection server_2;
include/sync_with_master_gtid.inc
SELECT * FROM t1 ORDER BY a;
a b
1 1
2 1
3 1
SELECT * FROM t3 ORDER BY a;
ERROR 42S02: Table 'test.t3' doesn't exist
SELECT * FROM t2 ORDER BY a;
a b
1 2
2 2
*** Restore original topology.
connection server_3;
include/stop_slave.inc
connection server_2;
include/stop_slave.inc
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_1,
MASTER_USE_GTID=SLAVE_POS;
include/start_slave.inc
connection server_3;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_2,
MASTER_USE_GTID=SLAVE_POS;
include/start_slave.inc
connection server_1;
DROP TABLE t1;
DROP TABLE t3;
include/save_master_gtid.inc
connection server_2;
DROP TABLE t2;
include/sync_with_master_gtid.inc
include/save_master_gtid.inc
connection server_3;
include/sync_with_master_gtid.inc
include/rpl_end.inc
!include ../my.cnf
[mysqld.1]
log-slave-updates
loose-innodb
gtid-domain-id=1
gtid-strict-mode=1
gtid-ignore-duplicates=1
[mysqld.2]
log-slave-updates
loose-innodb
gtid-domain-id=0
replicate-ignore-table=test.t3
gtid-strict-mode=1
gtid-ignore-duplicates=1
[mysqld.3]
log-slave-updates
loose-innodb
gtid-domain-id=0
replicate-ignore-table=test.t3
gtid-strict-mode=1
gtid-ignore-duplicates=1
[ENV]
SERVER_MYPORT_3= @mysqld.3.port
SERVER_MYSOCK_3= @mysqld.3.socket
--source include/have_innodb.inc
--source include/have_binlog_format_mixed.inc
--let $rpl_topology=1->2->3
--source include/rpl_init.inc
--echo *** Test GTID master switch in a topology with filtered events.
--echo *** With --gtid-ignore-duplicate and --gtid-strict-mode, should allow
--echo *** GTID connect at a GTID position that is filtered on the new master.
--connection server_1
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,1);
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t3 VALUES (1,1);
INSERT INTO t1 VALUES (2,1);
INSERT INTO t3 VALUES (2,1);
--source include/save_master_gtid.inc
--connection server_2
CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1,2);
--let $slave_timeout= 10
--source include/sync_with_master_gtid.inc
--source include/save_master_gtid.inc
--connection server_3
--source include/sync_with_master_gtid.inc
--echo *** Promote 3 as new master, demote 2 as slave of 3.
--echo *** GTID position of 2 in domain 0 is filtered on 3.
--connection server_2
--source include/stop_slave.inc
--connection server_3
--source include/stop_slave.inc
--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1,
MASTER_USE_GTID=SLAVE_POS;
--connection server_2
--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_3,
MASTER_USE_GTID=SLAVE_POS;
--source include/start_slave.inc
--connection server_3
--source include/start_slave.inc
--connection server_1
INSERT INTO t1 VALUES (3,1);
INSERT INTO t3 VALUES (3,1);
--source include/save_master_gtid.inc
--connection server_3
INSERT INTO t2 VALUES (2,2);
--source include/sync_with_master_gtid.inc
--source include/save_master_gtid.inc
--connection server_2
--source include/sync_with_master_gtid.inc
SELECT * FROM t1 ORDER BY a;
# Verify that table t3 is being filtered.
--error 1146
SELECT * FROM t3 ORDER BY a;
SELECT * FROM t2 ORDER BY a;
--echo *** Restore original topology.
--connection server_3
--source include/stop_slave.inc
--connection server_2
--source include/stop_slave.inc
--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1,
MASTER_USE_GTID=SLAVE_POS;
--source include/start_slave.inc
--connection server_3
--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2,
MASTER_USE_GTID=SLAVE_POS;
--source include/start_slave.inc
# Cleanup
--connection server_1
DROP TABLE t1;
DROP TABLE t3;
--source include/save_master_gtid.inc
--connection server_2
DROP TABLE t2;
--source include/sync_with_master_gtid.inc
--source include/save_master_gtid.inc
--connection server_3
--source include/sync_with_master_gtid.inc
--source include/rpl_end.inc
...@@ -1823,13 +1823,19 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type, ...@@ -1823,13 +1823,19 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type,
{ {
if (info->slave_gtid_strict_mode && if (info->slave_gtid_strict_mode &&
event_gtid.seq_no > gtid->seq_no && event_gtid.seq_no > gtid->seq_no &&
!(gtid_entry->flags & slave_connection_state::START_OWN_SLAVE_POS)) !(gtid_entry->flags & slave_connection_state::START_OWN_SLAVE_POS) &&
!info->slave_gtid_ignore_duplicates)
{ {
/* /*
In strict mode, it is an error if the slave requests to start In strict mode, it is an error if the slave requests to start
in a "hole" in the master's binlog: a GTID that does not in a "hole" in the master's binlog: a GTID that does not
exist, even though both the prior and subsequent seq_no exists exist, even though both the prior and subsequent seq_no exists
for same domain_id and server_id. for same domain_id and server_id.
But in --gtid-ignore-duplicates this is relaxed, as this
implies that we trust the sequence numbers between different
server_id. Thus, we want to allow the slave to connect at the
"hole", which could eg. be a filtered event.
*/ */
info->error= ER_GTID_START_FROM_BINLOG_HOLE; info->error= ER_GTID_START_FROM_BINLOG_HOLE;
*error_gtid= *gtid; *error_gtid= *gtid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment