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_sync.inc
|
||||||
--source include/rpl_stop_slaves.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
|
# 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.
|
# have to restore that state now, so we change topology to 1->2.
|
||||||
--let $rpl_topology= none
|
--let $rpl_topology= none
|
||||||
|
@ -44,5 +44,74 @@ a b
|
|||||||
2 i2
|
2 i2
|
||||||
3 i3
|
3 i3
|
||||||
4 i4
|
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;
|
DROP TABLE t1,t2;
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
--let $rpl_topology=1->2->3->4
|
--let $rpl_topology=1->2->3->4
|
||||||
--source include/rpl_init.inc
|
--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;
|
connection server_1;
|
||||||
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM;
|
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM;
|
||||||
CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB;
|
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 t1 ORDER BY a;
|
||||||
SELECT * FROM t2 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;
|
connection server_1;
|
||||||
DROP TABLE t1,t2;
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
35
sql/slave.cc
35
sql/slave.cc
@ -398,6 +398,33 @@ int init_recovery(Master_info* mi, const char** errmsg)
|
|||||||
DBUG_RETURN(0);
|
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.
|
Convert slave skip errors bitmap into a printable string.
|
||||||
*/
|
*/
|
||||||
@ -3385,6 +3412,8 @@ connected:
|
|||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
/* Fatal error */
|
/* Fatal error */
|
||||||
goto err;
|
goto err;
|
||||||
|
if (mi->gtid_pos_auto)
|
||||||
|
reset_coordinates_for_gtid(mi, rli);
|
||||||
|
|
||||||
if (ret == 2)
|
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
|
Heartbeat is sent only after an event corresponding to the corrdinates
|
||||||
the heartbeat carries.
|
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
|
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
|
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).
|
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
|
TODO: handling `when' for SHOW SLAVE STATUS' snds behind
|
||||||
*/
|
*/
|
||||||
if ((memcmp(mi->master_log_name, hb.get_log_ident(), hb.get_ident_len())
|
if ((memcmp(mi->master_log_name, hb.get_log_ident(), hb.get_ident_len())
|
||||||
&& mi->master_log_name != NULL)
|
&& 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 */
|
/* missed events of heartbeat from the past */
|
||||||
error= ER_SLAVE_HEARTBEAT_FAILURE;
|
error= ER_SLAVE_HEARTBEAT_FAILURE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user