MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0
The problem was when a GTID event was part of a group commit, and so contained a commit id. The code that replaces GTID with a BEGIN event for old slaves did not correctly handle this case. Fix the code so that the GTID with commit id can also be properly replaced with a BEGIN query event. The extra two bytes are in the BEGIN event replaced with a dummy, empty time zone string.
This commit is contained in:
parent
ec374f1e53
commit
b5b8210849
@ -62,6 +62,32 @@ slave-relay-bin.000007 # Query # # # Dummy ev
|
||||
slave-relay-bin.000007 # Table_map # # table_id: # (test.t1)
|
||||
slave-relay-bin.000007 # Write_rows # # table_id: # flags: STMT_END_F
|
||||
slave-relay-bin.000007 # Query # # COMMIT
|
||||
*** MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 ***
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
|
||||
INSERT INTO t2 VALUES (1);
|
||||
SET debug_sync='now WAIT_FOR master_queued1';
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
|
||||
INSERT INTO t2 VALUES (2);
|
||||
SET debug_sync='now WAIT_FOR master_queued2';
|
||||
SET debug_sync='now SIGNAL master_cont1';
|
||||
SET debug_sync='RESET';
|
||||
SET debug_sync='RESET';
|
||||
SET debug_sync='RESET';
|
||||
show binlog events in 'master-bin.000003' from <binlog_start> limit 0, 8;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
|
||||
master-bin.000003 # Table_map # # table_id: # (test.t2)
|
||||
master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F
|
||||
master-bin.000003 # Xid # # COMMIT /* XID */
|
||||
master-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=#
|
||||
master-bin.000003 # Table_map # # table_id: # (test.t2)
|
||||
master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F
|
||||
master-bin.000003 # Xid # # COMMIT /* XID */
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a
|
||||
1
|
||||
2
|
||||
# Test that slave which cannot tolerate holes in binlog stream but
|
||||
# knows the event does not get dummy event
|
||||
include/stop_slave.inc
|
||||
@ -95,5 +121,5 @@ select @@global.replicate_annotate_row_events;
|
||||
set @@global.debug_dbug= @old_slave_dbug;
|
||||
Clean up.
|
||||
set @@global.binlog_checksum = @old_master_binlog_checksum;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t1, t2;
|
||||
include/rpl_end.inc
|
||||
|
@ -1,6 +1,8 @@
|
||||
--source include/master-slave.inc
|
||||
--source include/have_debug.inc
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/have_binlog_format_row.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
connection master;
|
||||
|
||||
@ -71,6 +73,52 @@ let $binlog_start= 0;
|
||||
let $binlog_limit=7,5;
|
||||
--source include/show_relaylog_events.inc
|
||||
|
||||
|
||||
--echo *** MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 ***
|
||||
|
||||
# The problem was that for a group commit, we get commit id into the
|
||||
# GTID event, and there was a bug in the code that replaces GTID with
|
||||
# dummy that failed when commit id was present.
|
||||
#
|
||||
# So setup a group commit in InnoDB.
|
||||
|
||||
--connection master
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
|
||||
let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
|
||||
|
||||
--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
|
||||
send INSERT INTO t2 VALUES (1);
|
||||
|
||||
--connection master
|
||||
SET debug_sync='now WAIT_FOR master_queued1';
|
||||
|
||||
--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
|
||||
send INSERT INTO t2 VALUES (2);
|
||||
|
||||
--connection master
|
||||
SET debug_sync='now WAIT_FOR master_queued2';
|
||||
SET debug_sync='now SIGNAL master_cont1';
|
||||
|
||||
--connection con1
|
||||
REAP;
|
||||
SET debug_sync='RESET';
|
||||
--connection con2
|
||||
REAP;
|
||||
SET debug_sync='RESET';
|
||||
--connection master
|
||||
SET debug_sync='RESET';
|
||||
let $binlog_limit= 0, 8;
|
||||
--source include/show_binlog_events.inc
|
||||
--save_master_pos
|
||||
|
||||
--connection slave
|
||||
--sync_with_master
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
||||
|
||||
--echo # Test that slave which cannot tolerate holes in binlog stream but
|
||||
--echo # knows the event does not get dummy event
|
||||
|
||||
@ -106,6 +154,6 @@ set @@global.debug_dbug= @old_slave_dbug;
|
||||
--echo Clean up.
|
||||
connection master;
|
||||
set @@global.binlog_checksum = @old_master_binlog_checksum;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t1, t2;
|
||||
sync_slave_with_master;
|
||||
--source include/rpl_end.inc
|
||||
|
@ -3639,9 +3639,14 @@ Query_log_event::begin_event(String *packet, ulong ev_offset,
|
||||
DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
|
||||
checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
|
||||
|
||||
/* Currently we only need to replace GTID event. */
|
||||
DBUG_ASSERT(data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN);
|
||||
if (data_len != LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
|
||||
/*
|
||||
Currently we only need to replace GTID event.
|
||||
The length of GTID differs depending on whether it contains commit id.
|
||||
*/
|
||||
DBUG_ASSERT(data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN ||
|
||||
data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN + 2);
|
||||
if (data_len != LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN &&
|
||||
data_len != LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN + 2)
|
||||
return 1;
|
||||
|
||||
flags= uint2korr(p + FLAGS_OFFSET);
|
||||
@ -3654,9 +3659,22 @@ Query_log_event::begin_event(String *packet, ulong ev_offset,
|
||||
int4store(q + Q_EXEC_TIME_OFFSET, 0);
|
||||
q[Q_DB_LEN_OFFSET]= 0;
|
||||
int2store(q + Q_ERR_CODE_OFFSET, 0);
|
||||
int2store(q + Q_STATUS_VARS_LEN_OFFSET, 0);
|
||||
q[Q_DATA_OFFSET]= 0; /* Zero terminator for empty db */
|
||||
q+= Q_DATA_OFFSET + 1;
|
||||
if (data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
|
||||
{
|
||||
int2store(q + Q_STATUS_VARS_LEN_OFFSET, 0);
|
||||
q[Q_DATA_OFFSET]= 0; /* Zero terminator for empty db */
|
||||
q+= Q_DATA_OFFSET + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN + 2);
|
||||
/* Put in an empty time_zone_str to take up the extra 2 bytes. */
|
||||
int2store(q + Q_STATUS_VARS_LEN_OFFSET, 2);
|
||||
q[Q_DATA_OFFSET]= Q_TIME_ZONE_CODE;
|
||||
q[Q_DATA_OFFSET+1]= 0; /* Zero length for empty time_zone_str */
|
||||
q[Q_DATA_OFFSET+2]= 0; /* Zero terminator for empty db */
|
||||
q+= Q_DATA_OFFSET + 3;
|
||||
}
|
||||
memcpy(q, "BEGIN", 5);
|
||||
|
||||
if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
|
||||
|
@ -3105,12 +3105,15 @@ public:
|
||||
<td>flags</td>
|
||||
<td>1 byte bitfield</td>
|
||||
<td>Bit 0 set indicates stand-alone event (no terminating COMMIT)</td>
|
||||
<td>Bit 1 set indicates group commit, and that commit id exists</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Reserved</td>
|
||||
<td>6 bytes</td>
|
||||
<td>Reserved bytes, set to 0. Maybe be used for future expansion.</td>
|
||||
<td>Reserved (no group commit) / commit id (group commit) (see flags bit 1)</td>
|
||||
<td>6 bytes / 8 bytes</td>
|
||||
<td>Reserved bytes, set to 0. Maybe be used for future expansion (no
|
||||
group commit). OR commit id, same for all GTIDs in the same group
|
||||
commit (see flags bit 1).</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user