MDEV-26: Global transaction ID
- Add first basic mysql-test-run test case which tests switch to new master using MASTER_GTID_POS=AUTO. - When we connect with GTID, do not use any old relay logs, as they may contain the wrong events or be corrupt after crash. - Fix old bug that fails replication if we receive a heartbeat event immediately after an event was omitted in the stream from the master. - Fix rpl_end to clear Gtid_Pos_Auto, to keep check_testcase happy.
This commit is contained in:
parent
7426a466dc
commit
c350177a21
@ -79,6 +79,22 @@ while ($_rpl_server)
|
||||
--source include/rpl_sync.inc
|
||||
--source include/rpl_stop_slaves.inc
|
||||
|
||||
if (!$rpl_debug)
|
||||
{
|
||||
--disable_query_log
|
||||
}
|
||||
--let $_rpl_server= $rpl_server_count
|
||||
while ($_rpl_server)
|
||||
{
|
||||
--let $rpl_connection_name= server_$_rpl_server
|
||||
--source include/rpl_connection.inc
|
||||
|
||||
# Clear Gtid_Pos_Auto in SHOW SLAVE STATUS to keep check_testcase happy.
|
||||
CHANGE MASTER TO master_log_file='';
|
||||
|
||||
--dec $_rpl_server
|
||||
}
|
||||
|
||||
# mtr configures server 2 to be a slave before it runs the test. We
|
||||
# have to restore that state now, so we change topology to 1->2.
|
||||
--let $rpl_topology= none
|
||||
|
@ -44,5 +44,74 @@ a b
|
||||
2 i2
|
||||
3 i3
|
||||
4 i4
|
||||
*** Now take out D, let it fall behind a bit, and then test re-attaching it to A ***
|
||||
include/stop_slave.inc
|
||||
INSERT INTO t1 VALUES (5, "m1a");
|
||||
INSERT INTO t2 VALUES (5, "i1a");
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT,
|
||||
MASTER_GTID_POS=AUTO;
|
||||
include/start_slave.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
1 m1
|
||||
2 m2
|
||||
3 m3
|
||||
4 m4
|
||||
5 m1a
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
1 i1
|
||||
2 i2
|
||||
3 i3
|
||||
4 i4
|
||||
5 i1a
|
||||
*** Now move B to D (C is still replicating from B) ***
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
|
||||
MASTER_GTID_POS=AUTO;
|
||||
include/start_slave.inc
|
||||
UPDATE t2 SET b="j1a" WHERE a=5;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
1 m1
|
||||
2 m2
|
||||
3 m3
|
||||
4 m4
|
||||
5 m1a
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
1 i1
|
||||
2 i2
|
||||
3 i3
|
||||
4 i4
|
||||
5 j1a
|
||||
*** Now move C to D, after letting it fall a little behind ***
|
||||
include/stop_slave.inc
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (6, "i6b");
|
||||
INSERT INTO t2 VALUES (7, "i7b");
|
||||
COMMIT;
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
|
||||
MASTER_GTID_POS=AUTO;
|
||||
include/start_slave.inc
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
1 i1
|
||||
2 i2
|
||||
3 i3
|
||||
4 i4
|
||||
5 j1a
|
||||
6 i6b
|
||||
7 i7b
|
||||
*** Now change everything back to what it was, to make rpl_end.inc happy
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_MYPORT;
|
||||
include/start_slave.inc
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SLAVE_MYPORT;
|
||||
include/start_slave.inc
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_3;
|
||||
include/start_slave.inc
|
||||
DROP TABLE t1,t2;
|
||||
include/rpl_end.inc
|
||||
|
@ -2,6 +2,11 @@
|
||||
--let $rpl_topology=1->2->3->4
|
||||
--source include/rpl_init.inc
|
||||
|
||||
# Set up a 4-deep replication topology, then test various fail-overs
|
||||
# using GTID.
|
||||
#
|
||||
# A -> B -> C -> D
|
||||
|
||||
connection server_1;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB;
|
||||
@ -31,6 +36,82 @@ sync_with_master;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
||||
|
||||
--echo *** Now take out D, let it fall behind a bit, and then test re-attaching it to A ***
|
||||
connection server_4;
|
||||
--source include/stop_slave.inc
|
||||
|
||||
connection server_1;
|
||||
INSERT INTO t1 VALUES (5, "m1a");
|
||||
INSERT INTO t2 VALUES (5, "i1a");
|
||||
save_master_pos;
|
||||
|
||||
connection server_4;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT,
|
||||
MASTER_GTID_POS=AUTO;
|
||||
--source include/start_slave.inc
|
||||
sync_with_master;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
||||
--echo *** Now move B to D (C is still replicating from B) ***
|
||||
connection server_2;
|
||||
--source include/stop_slave.inc
|
||||
--replace_result $SERVER_MYPORT_4 SERVER_MYPORT_4
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_4,
|
||||
MASTER_GTID_POS=AUTO;
|
||||
--source include/start_slave.inc
|
||||
|
||||
connection server_4;
|
||||
UPDATE t2 SET b="j1a" WHERE a=5;
|
||||
save_master_pos;
|
||||
|
||||
connection server_2;
|
||||
sync_with_master;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
||||
--echo *** Now move C to D, after letting it fall a little behind ***
|
||||
connection server_3;
|
||||
--source include/stop_slave.inc
|
||||
|
||||
connection server_1;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (6, "i6b");
|
||||
INSERT INTO t2 VALUES (7, "i7b");
|
||||
COMMIT;
|
||||
|
||||
connection server_3;
|
||||
--replace_result $SERVER_MYPORT_4 SERVER_MYPORT_4
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_4,
|
||||
MASTER_GTID_POS=AUTO;
|
||||
--source include/start_slave.inc
|
||||
# This time, let's sync up without reference to binlog on D.
|
||||
--let $wait_condition= SELECT COUNT(*) = 7 FROM t2
|
||||
--source include/wait_condition.inc
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
||||
--echo *** Now change everything back to what it was, to make rpl_end.inc happy
|
||||
# Also check that MASTER_GTID_POS=AUTO is still enabled.
|
||||
connection server_2;
|
||||
--source include/stop_slave.inc
|
||||
--replace_result $MASTER_MYPORT MASTER_MYPORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT;
|
||||
--source include/start_slave.inc
|
||||
|
||||
connection server_3;
|
||||
--source include/stop_slave.inc
|
||||
--replace_result $SLAVE_MYPORT SLAVE_MYPORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SLAVE_MYPORT;
|
||||
--source include/start_slave.inc
|
||||
|
||||
connection server_4;
|
||||
--source include/stop_slave.inc
|
||||
--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_3;
|
||||
--source include/start_slave.inc
|
||||
|
||||
connection server_1;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
|
35
sql/slave.cc
35
sql/slave.cc
@ -397,6 +397,33 @@ int init_recovery(Master_info* mi, const char** errmsg)
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
When connecting a slave to a master with GTID, we reset the relay log
|
||||
coordinates of the SQL thread and clear the master coordinates of SQL and IO
|
||||
threads.
|
||||
|
||||
This way we ensure that we start from the correct place even after a change
|
||||
to new master or a crash where relay log coordinates may be wrong (GTID
|
||||
state is crash safe but master.info is not). And we get the correct master
|
||||
coordinates set upon reading the initial fake rotate event sent from master.
|
||||
*/
|
||||
static void
|
||||
reset_coordinates_for_gtid(Master_info *mi, Relay_log_info *rli)
|
||||
{
|
||||
mi->master_log_pos= 0;
|
||||
mi->master_log_name[0]= 0;
|
||||
rli->group_master_log_pos= 0;
|
||||
rli->group_master_log_name[0]= 0;
|
||||
rli->group_relay_log_pos= BIN_LOG_HEADER_SIZE;
|
||||
strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
|
||||
sizeof(rli->group_relay_log_name)-1);
|
||||
rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
|
||||
strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
|
||||
sizeof(mi->rli.event_relay_log_name)-1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert slave skip errors bitmap into a printable string.
|
||||
@ -3385,6 +3412,8 @@ connected:
|
||||
if (ret == 1)
|
||||
/* Fatal error */
|
||||
goto err;
|
||||
if (mi->gtid_pos_auto)
|
||||
reset_coordinates_for_gtid(mi, rli);
|
||||
|
||||
if (ret == 2)
|
||||
{
|
||||
@ -4694,16 +4723,18 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
|
||||
|
||||
Heartbeat is sent only after an event corresponding to the corrdinates
|
||||
the heartbeat carries.
|
||||
Slave can not have a difference in coordinates except in the only
|
||||
Slave can not have a higher coordinate except in the only
|
||||
special case when mi->master_log_name, master_log_pos have never
|
||||
been updated by Rotate event i.e when slave does not have any history
|
||||
with the master (and thereafter mi->master_log_pos is NULL).
|
||||
|
||||
Slave can have lower coordinates, if some event from master was omitted.
|
||||
|
||||
TODO: handling `when' for SHOW SLAVE STATUS' snds behind
|
||||
*/
|
||||
if ((memcmp(mi->master_log_name, hb.get_log_ident(), hb.get_ident_len())
|
||||
&& mi->master_log_name != NULL)
|
||||
|| mi->master_log_pos != hb.log_pos)
|
||||
|| mi->master_log_pos > hb.log_pos)
|
||||
{
|
||||
/* missed events of heartbeat from the past */
|
||||
error= ER_SLAVE_HEARTBEAT_FAILURE;
|
||||
|
Loading…
x
Reference in New Issue
Block a user