diff options
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result | 28 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test | 50 | ||||
-rw-r--r-- | sql/log_event.cc | 30 | ||||
-rw-r--r-- | sql/log_event.h | 9 |
4 files changed, 106 insertions, 11 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result index 2a7ed37cf9b..12623bdeb3a 100644 --- a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result +++ b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result @@ -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 diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test index 99a371eac44..7a2f5f3e699 100644 --- a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -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 diff --git a/sql/log_event.cc b/sql/log_event.cc index 361efe4428e..acdf370cf76 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -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) diff --git a/sql/log_event.h b/sql/log_event.h index 312a9656d01..415332c46bc 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -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> |