diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_glle_ordered.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_glle_ordered.result new file mode 100644 index 00000000000..2826cba99ae --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_glle_ordered.result @@ -0,0 +1,19 @@ +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_domain_id= 1; +SET @@session.server_id= 2; +CREATE TABLE t2 (a int); +SET @@session.server_id= 1; +INSERT INTO t2 VALUES (1); +SET @@session.gtid_domain_id= 2; +SET @@session.server_id= 3; +CREATE TABLE t3 (a int); +FLUSH LOGS; +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/binlog_file > SEARCH_FILE +FOUND 1 /Gtid list \[0-1-1,\n# 1-2-1,\n# 1-1-2,\n# 2-3-1\]/ in tmp_binlog.out +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result index 668c070b5ea..c2f7bac387c 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result @@ -272,7 +272,7 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Gtid_list 1 # [0-1-1] show binlog events in 'master-bin.000003' limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Gtid_list 1 # [1-2-1,0-1-2] +master-bin.000003 # Gtid_list 1 # [0-1-2,1-2-1] # MYSQL_BINLOG MYSQLD_DATADIR/BINLOG_FILE1 MYSQLD_DATADIR/BINLOG_FILE3 --gtid-strict-mode 2> log_error_ > OUT_FILE # We should have two warnings about missing data from domains 0 and 1 if # -vvv is specified @@ -578,7 +578,7 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Gtid_list 1 # [0-1-1] show binlog events in 'master-bin.000003' limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Gtid_list 1 # [1-2-1,0-1-2] +master-bin.000003 # Gtid_list 1 # [0-1-2,1-2-1] # MYSQL_BINLOG MYSQLD_DATADIR/BINLOG_FILE1 MYSQLD_DATADIR/BINLOG_FILE3 --skip-gtid-strict-mode -vvv 2> log_error_ > OUT_FILE # We should have two warnings about missing data from domains 0 and 1 if # -vvv is specified @@ -883,7 +883,7 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Gtid_list 1 # [0-1-1] show binlog events in 'master-bin.000003' limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Gtid_list 1 # [1-2-1,0-1-2] +master-bin.000003 # Gtid_list 1 # [0-1-2,1-2-1] # MYSQL_BINLOG MYSQLD_DATADIR/BINLOG_FILE1 MYSQLD_DATADIR/BINLOG_FILE3 --skip-gtid-strict-mode 2> log_error_ > OUT_FILE # We should have two warnings about missing data from domains 0 and 1 if # -vvv is specified diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result index 63af0d20cc6..fce5f95ce82 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result @@ -41,7 +41,7 @@ FLUSH LOGS; # matched against --start-position in the following tests: show binlog events in 'master-bin.000002' limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Gtid_list 1 # [1-3-4,1-2-5,0-1-3] +master-bin.000002 # Gtid_list 1 # [0-1-3,1-3-4,1-2-5] DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; @@ -249,7 +249,7 @@ FLUSH LOGS; # matched against --start-position in the following tests: show binlog events in 'master-bin.000002' limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Gtid_list 1 # [1-3-4,1-2-5,0-1-3] +master-bin.000002 # Gtid_list 1 # [0-1-3,1-3-4,1-2-5] DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_glle_ordered.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_glle_ordered.test new file mode 100644 index 00000000000..9c79925b4bd --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_glle_ordered.test @@ -0,0 +1,43 @@ +# +# Purpose: +# This test validates that GTIDs are ordered when mysqlbinlog outputs +# Gtid_list events. +# +# Methodology: +# Write multiple events to the binlog with different domain ids and server +# ids, and ensure that the Gtid_list event GTIDs are ordered first by domain id +# (ascending), and then sequence number (ascending). +# +# References: +# MDEV-4989: Support for GTID in mysqlbinlog +# +--source include/have_log_bin.inc + +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_domain_id= 1; +SET @@session.server_id= 2; +CREATE TABLE t2 (a int); +SET @@session.server_id= 1; +INSERT INTO t2 VALUES (1); +SET @@session.gtid_domain_id= 2; +SET @@session.server_id= 3; +CREATE TABLE t3 (a int); +FLUSH LOGS; +FLUSH LOGS; + +--let $binlog_file= query_get_value(SHOW BINARY LOGS, Log_name, 2) +--let $MYSQLD_DATADIR=`select @@datadir` +--let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/tmp_binlog.out + +--echo # MYSQL_BINLOG MYSQLD_DATADIR/binlog_file > SEARCH_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $SEARCH_FILE + +--let SEARCH_PATTERN= Gtid list \[0-1-1,\n# 1-2-1,\n# 1-1-2,\n# 2-3-1\] +--source include/search_pattern_in_file.inc + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; diff --git a/sql/log_event.cc b/sql/log_event.cc index d3d44e8dc30..b3943760720 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2653,6 +2653,20 @@ Gtid_log_event::Gtid_log_event(const uchar *buf, uint event_len, buf_0[event_len - 1] == 0); } +int compare_glle_gtids(const void * _gtid1, const void *_gtid2) +{ + rpl_gtid *gtid1= (rpl_gtid *) _gtid1; + rpl_gtid *gtid2= (rpl_gtid *) _gtid2; + + int ret; + if (*gtid1 < *gtid2) + ret= -1; + else if (*gtid1 > *gtid2) + ret= 1; + else + ret= 0; + return ret; +} /* GTID list. */ diff --git a/sql/log_event.h b/sql/log_event.h index db80ca841a2..405b9a15003 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -5902,4 +5902,10 @@ int row_log_event_uncompress(const Format_description_log_event bool is_parallel_retry_error(rpl_group_info *rgi, int err); +/* + Compares two GTIDs to facilitate sorting a GTID list log event by domain id + (ascending) and sequence number (ascending) +*/ +int compare_glle_gtids(const void * _gtid1, const void *_gtid2); + #endif /* _log_event_h */ diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index 9e75d3f4c4c..e460fc17848 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -2342,6 +2342,8 @@ Gtid_list_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info) char buf[21]; uint32 i; + qsort(list, count, sizeof(rpl_gtid), compare_glle_gtids); + if (print_header(&cache, print_event_info, FALSE) || my_b_printf(&cache, "\tGtid list [")) goto err; diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index cf16d538744..ca988354205 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -4085,6 +4085,12 @@ Gtid_list_log_event::pack_info(Protocol *protocol) uint32 i; bool first; + /* + For output consistency and ease of reading, we sort the GTID list in + ascending order + */ + qsort(list, count, sizeof(rpl_gtid), compare_glle_gtids); + buf.length(0); buf.append(STRING_WITH_LEN("[")); first= true; diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 7b0e1e4a363..ae40fd46f4d 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -3398,9 +3398,8 @@ my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid) /* Assume result should be excluded to start */ my_bool should_exclude= TRUE; - DBUG_ASSERT((m_has_start || m_has_stop) && - (gtid->domain_id == m_start.domain_id || - gtid->domain_id == m_stop.domain_id)); + DBUG_ASSERT((m_has_start && gtid->domain_id == m_start.domain_id) || + (m_has_stop && gtid->domain_id == m_stop.domain_id)); if (!m_is_active && !m_has_passed) { diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index 8b8c3bb9c92..759e4e4eea3 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -48,6 +48,18 @@ inline bool operator==(const rpl_gtid& lhs, const rpl_gtid& rhs) lhs.seq_no == rhs.seq_no; }; +inline bool operator<(const rpl_gtid& lhs, const rpl_gtid& rhs) +{ + return (lhs.domain_id == rhs.domain_id) ? lhs.seq_no < rhs.seq_no + : lhs.domain_id < rhs.domain_id; +}; + +inline bool operator>(const rpl_gtid& lhs, const rpl_gtid& rhs) +{ + return (lhs.domain_id == rhs.domain_id) ? lhs.seq_no > rhs.seq_no + : lhs.domain_id > rhs.domain_id; +}; + enum enum_gtid_skip_type { GTID_SKIP_NOT, GTID_SKIP_STANDALONE, GTID_SKIP_TRANSACTION };