Commit c350177a authored by unknown's avatar unknown

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.
parent 7426a466
......@@ -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;
......
......@@ -398,6 +398,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;
......
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