diff options
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_gtid_sort.result | 99 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_gtid_sort.test | 77 | ||||
-rw-r--r-- | sql/rpl_gtid.cc | 112 | ||||
-rw-r--r-- | sql/rpl_gtid.h | 11 |
4 files changed, 284 insertions, 15 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_gtid_sort.result b/mysql-test/suite/rpl/r/rpl_gtid_sort.result new file mode 100644 index 00000000000..add24522b90 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_gtid_sort.result @@ -0,0 +1,99 @@ +include/rpl_init.inc [topology=1->2] +*** Test connecting with empty GTID state to start from very beginning of binlog *** +include/stop_slave.inc +RESET MASTER; +RESET SLAVE; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +Variable_name Value +gtid_binlog_pos +SHOW VARIABLES LIKE 'gtid_current_pos'; +Variable_name Value +gtid_current_pos +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SHOW VARIABLES LIKE 'gtid_binlog_state'; +Variable_name Value +gtid_binlog_state +RESET MASTER; +FLUSH LOGS; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +SET @@SESSION.gtid_domain_id=1; +INSERT INTO t1 VALUES(1); +SET @@SESSION.gtid_domain_id=99999; +INSERT INTO t1 VALUES(3); +SET @@SESSION.gtid_domain_id=10; +INSERT INTO t1 VALUES(4); +SET @@SESSION.gtid_domain_id=100; +INSERT INTO t1 VALUES(5); +SET @@SESSION.gtid_domain_id=2147483648; +INSERT INTO t1 VALUES(6); +SET @@SESSION.gtid_domain_id=4294967295; +INSERT INTO t1 VALUES(7); +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +Variable_name Value +gtid_binlog_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_current_pos'; +Variable_name Value +gtid_current_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SHOW VARIABLES LIKE 'gtid_binlog_state'; +Variable_name Value +gtid_binlog_state 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +Variable_name Value +gtid_binlog_pos +SHOW VARIABLES LIKE 'gtid_current_pos'; +Variable_name Value +gtid_current_pos +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SHOW VARIABLES LIKE 'gtid_binlog_state'; +Variable_name Value +gtid_binlog_state +CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT, +MASTER_USE_GTID=CURRENT_POS; +include/start_slave.inc +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +Variable_name Value +gtid_binlog_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_current_pos'; +Variable_name Value +gtid_current_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_binlog_state'; +Variable_name Value +gtid_binlog_state 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SELECT * FROM t1; +a +1 +3 +4 +5 +6 +7 +SET @@SESSION.gtid_domain_id=1000; +INSERT INTO t1 VALUES(8); +SET @@SESSION.gtid_domain_id=89; +INSERT INTO t1 VALUES(9); +SET @@SESSION.gtid_domain_id=10100000; +INSERT INTO t1 VALUES(10); +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +Variable_name Value +gtid_binlog_pos 0-1-1,1-1-1,10-1-1,89-2-1,100-1-1,1000-2-1,99999-1-1,10100000-2-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_current_pos'; +Variable_name Value +gtid_current_pos 0-1-1,1-1-1,10-1-1,89-2-1,100-1-1,1000-2-1,99999-1-1,10100000-2-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1 +SHOW VARIABLES LIKE 'gtid_binlog_state'; +Variable_name Value +gtid_binlog_state 0-1-1,1-1-1,10-1-1,89-2-1,100-1-1,1000-2-1,99999-1-1,10100000-2-1,2147483648-1-1,4294967295-1-1 +DROP TABLE t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_sort.test b/mysql-test/suite/rpl/t/rpl_gtid_sort.test new file mode 100644 index 00000000000..dc3b18aa897 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_sort.test @@ -0,0 +1,77 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test connecting with empty GTID state to start from very beginning of binlog *** +--connection server_2 +--source include/stop_slave.inc +RESET MASTER; +RESET SLAVE; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +--connection server_1 +RESET MASTER; +FLUSH LOGS; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +SET @@SESSION.gtid_domain_id=1; +INSERT INTO t1 VALUES(1); + +SET @@SESSION.gtid_domain_id=99999; +INSERT INTO t1 VALUES(3); + +SET @@SESSION.gtid_domain_id=10; +INSERT INTO t1 VALUES(4); + +SET @@SESSION.gtid_domain_id=100; +INSERT INTO t1 VALUES(5); + +SET @@SESSION.gtid_domain_id=2147483648; # 0x80000000 +INSERT INTO t1 VALUES(6); + +SET @@SESSION.gtid_domain_id=4294967295; # 0xFFFFFFFF +INSERT INTO t1 VALUES(7); + +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +--save_master_pos + +--connection server_2 +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=CURRENT_POS; +--source include/start_slave.inc +--sync_with_master +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +SELECT * FROM t1; + +SET @@SESSION.gtid_domain_id=1000; +INSERT INTO t1 VALUES(8); + +SET @@SESSION.gtid_domain_id=89; +INSERT INTO t1 VALUES(9); + +SET @@SESSION.gtid_domain_id=10100000; +INSERT INTO t1 VALUES(10); + +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +# Clean up. +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index e5620ec41a2..8b339e0c34e 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -247,6 +247,7 @@ rpl_slave_state::rpl_slave_state() { my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE); + my_init_dynamic_array(>id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); } @@ -292,6 +293,7 @@ rpl_slave_state::deinit() return; truncate_hash(); my_hash_free(&hash); + delete_dynamic(>id_sort_array); mysql_mutex_destroy(&LOCK_slave_state); } @@ -705,7 +707,20 @@ rpl_slave_state::next_sub_id(uint32 domain_id) return sub_id; } +/* A callback used in sorting of gtid list based on domain_id. */ +static int rpl_gtid_cmp_cb(const void *id1, const void *id2) +{ + uint32 d1= ((rpl_gtid *)id1)->domain_id; + uint32 d2= ((rpl_gtid *)id2)->domain_id; + + if (d1 < d2) + return -1; + else if (d1 > d2) + return 1; + return 0; +} +/* Format the specified gtid and store it in the given string buffer. */ bool rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first) { @@ -722,16 +737,64 @@ rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first) dest->append_ulonglong(gtid->seq_no); } +/* + Sort the given gtid list based on domain_id and store them in the specified + string. +*/ +static bool +rpl_slave_state_tostring_helper(DYNAMIC_ARRAY *gtid_dynarr, String *str) +{ + bool first= true, res= true; + + sort_dynamic(gtid_dynarr, rpl_gtid_cmp_cb); + + for (uint i= 0; i < gtid_dynarr->elements; i ++) + { + rpl_gtid *gtid= dynamic_element(gtid_dynarr, i, rpl_gtid *); + if (rpl_slave_state_tostring_helper(str, gtid, &first)) + goto err; + } + res= false; + +err: + return res; +} + + +/* Sort the given gtid list based on domain_id and call cb for each gtid. */ +static bool +rpl_slave_state_tostring_helper(DYNAMIC_ARRAY *gtid_dynarr, + int (*cb)(rpl_gtid *, void *), + void *data) +{ + rpl_gtid *gtid; + bool res= true; + + sort_dynamic(gtid_dynarr, rpl_gtid_cmp_cb); + + for (uint i= 0; i < gtid_dynarr->elements; i ++) + { + gtid= dynamic_element(gtid_dynarr, i, rpl_gtid *); + if ((*cb)(gtid, data)) + goto err; + } + res= false; + +err: + return res; +} int rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, - rpl_gtid *extra_gtids, uint32 num_extra) + rpl_gtid *extra_gtids, uint32 num_extra, + bool sort) { uint32 i; HASH gtid_hash; uchar *rec; rpl_gtid *gtid; int res= 1; + bool locked= false; my_hash_init(>id_hash, &my_charset_bin, 32, offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, NULL, HASH_UNIQUE); @@ -741,6 +804,8 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, goto err; mysql_mutex_lock(&LOCK_slave_state); + locked= true; + reset_dynamic(>id_sort_array); for (i= 0; i < hash.records; ++i) { @@ -775,31 +840,38 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, memcpy(&best_gtid, gtid, sizeof(best_gtid)); if (my_hash_delete(>id_hash, rec)) { - mysql_mutex_unlock(&LOCK_slave_state); goto err; } } - if ((res= (*cb)(&best_gtid, data))) + if ((res= sort ? insert_dynamic(>id_sort_array, + (const void *) &best_gtid) : + (*cb)(&best_gtid, data))) { - mysql_mutex_unlock(&LOCK_slave_state); goto err; } } - mysql_mutex_unlock(&LOCK_slave_state); - /* Also add any remaining extra domain_ids. */ for (i= 0; i < gtid_hash.records; ++i) { gtid= (rpl_gtid *)my_hash_element(>id_hash, i); - if ((res= (*cb)(gtid, data))) + if ((res= sort ? insert_dynamic(>id_sort_array, (const void *) gtid) : + (*cb)(gtid, data))) + { goto err; + } + } + + if (sort && rpl_slave_state_tostring_helper(>id_sort_array, cb, data)) + { + goto err; } res= 0; err: + if (locked) mysql_mutex_unlock(&LOCK_slave_state); my_hash_free(>id_hash); return res; @@ -840,7 +912,8 @@ rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra) data.first= true; data.dest= dest; - return iterate(rpl_slave_state_tostring_cb, &data, extra_gtids, num_extra); + return iterate(rpl_slave_state_tostring_cb, &data, extra_gtids, + num_extra, true); } @@ -1030,6 +1103,7 @@ rpl_binlog_state::rpl_binlog_state() { my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); + my_init_dynamic_array(>id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state, MY_MUTEX_INIT_SLOW); initialized= 1; @@ -1063,6 +1137,7 @@ void rpl_binlog_state::free() initialized= 0; reset_nolock(); my_hash_free(&hash); + delete_dynamic(>id_sort_array); mysql_mutex_destroy(&LOCK_binlog_state); } } @@ -1547,21 +1622,25 @@ end: return res; } - bool rpl_binlog_state::append_pos(String *str) { uint32 i; - bool first= true; mysql_mutex_lock(&LOCK_binlog_state); + reset_dynamic(>id_sort_array); + for (i= 0; i < hash.records; ++i) { element *e= (element *)my_hash_element(&hash, i); if (e->last_gtid && - rpl_slave_state_tostring_helper(str, e->last_gtid, &first)) + insert_dynamic(>id_sort_array, (const void *) e->last_gtid)) + { + mysql_mutex_unlock(&LOCK_binlog_state); return true; + } } + rpl_slave_state_tostring_helper(>id_sort_array, str); mysql_mutex_unlock(&LOCK_binlog_state); return false; @@ -1572,10 +1651,11 @@ bool rpl_binlog_state::append_state(String *str) { uint32 i, j; - bool first= true; bool res= false; mysql_mutex_lock(&LOCK_binlog_state); + reset_dynamic(>id_sort_array); + for (i= 0; i < hash.records; ++i) { element *e= (element *)my_hash_element(&hash, i); @@ -1596,7 +1676,7 @@ rpl_binlog_state::append_state(String *str) else gtid= e->last_gtid; - if (rpl_slave_state_tostring_helper(str, gtid, &first)) + if (insert_dynamic(>id_sort_array, (const void *) gtid)) { res= true; goto end; @@ -1604,6 +1684,8 @@ rpl_binlog_state::append_state(String *str) } } + rpl_slave_state_tostring_helper(>id_sort_array, str); + end: mysql_mutex_unlock(&LOCK_binlog_state); return res; @@ -1615,12 +1697,14 @@ slave_connection_state::slave_connection_state() my_hash_init(&hash, &my_charset_bin, 32, offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); + my_init_dynamic_array(>id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); } slave_connection_state::~slave_connection_state() { my_hash_free(&hash); + delete_dynamic(>id_sort_array); } @@ -1730,7 +1814,7 @@ slave_connection_state::load(rpl_slave_state *state, { reset(); return state->iterate(slave_connection_state_load_cb, this, - extra_gtids, num_extra); + extra_gtids, num_extra, false); } diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index b203f34df5a..bd58d091a02 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -159,6 +159,8 @@ struct rpl_slave_state HASH hash; /* Mutex protecting access to the state. */ mysql_mutex_t LOCK_slave_state; + /* Auxiliary buffer to sort gtid list. */ + DYNAMIC_ARRAY gtid_sort_array; uint64 last_sub_id; bool inited; @@ -178,7 +180,8 @@ struct rpl_slave_state bool in_transaction, bool in_statement); uint64 next_sub_id(uint32 domain_id); int iterate(int (*cb)(rpl_gtid *, void *), void *data, - rpl_gtid *extra_gtids, uint32 num_extra); + rpl_gtid *extra_gtids, uint32 num_extra, + bool sort); int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra); bool domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid); int load(THD *thd, char *state_from_master, size_t len, bool reset, @@ -228,6 +231,9 @@ struct rpl_binlog_state mysql_mutex_t LOCK_binlog_state; my_bool initialized; + /* Auxiliary buffer to sort gtid list. */ + DYNAMIC_ARRAY gtid_sort_array; + rpl_binlog_state(); ~rpl_binlog_state(); @@ -271,6 +277,9 @@ struct slave_connection_state /* Mapping from domain_id to the entry with GTID requested for that domain. */ HASH hash; + /* Auxiliary buffer to sort gtid list. */ + DYNAMIC_ARRAY gtid_sort_array; + slave_connection_state(); ~slave_connection_state(); |