Commit b5b82108 authored by unknown's avatar unknown

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.
parent ec374f1e
......@@ -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
--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 @@ class Binlog_checkpoint_log_event: public Log_event
<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>
......
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