Commit 75a27eea authored by Nirbhay Choubey's avatar Nirbhay Choubey

MDEV-4987: Sort by domain_id when list of GTIDs are output

Added logic to sort gtid list based on domain_id before
populating them in string. Added a test case.
parent 34d86ac9
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
--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
...@@ -247,6 +247,7 @@ rpl_slave_state::rpl_slave_state() ...@@ -247,6 +247,7 @@ rpl_slave_state::rpl_slave_state()
{ {
my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE); sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE);
my_init_dynamic_array(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
} }
...@@ -292,6 +293,7 @@ rpl_slave_state::deinit() ...@@ -292,6 +293,7 @@ rpl_slave_state::deinit()
return; return;
truncate_hash(); truncate_hash();
my_hash_free(&hash); my_hash_free(&hash);
delete_dynamic(&gtid_sort_array);
mysql_mutex_destroy(&LOCK_slave_state); mysql_mutex_destroy(&LOCK_slave_state);
} }
...@@ -705,7 +707,20 @@ rpl_slave_state::next_sub_id(uint32 domain_id) ...@@ -705,7 +707,20 @@ rpl_slave_state::next_sub_id(uint32 domain_id)
return sub_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 bool
rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first) 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) ...@@ -722,16 +737,64 @@ rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first)
dest->append_ulonglong(gtid->seq_no); 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 int
rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, 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; uint32 i;
HASH gtid_hash; HASH gtid_hash;
uchar *rec; uchar *rec;
rpl_gtid *gtid; rpl_gtid *gtid;
int res= 1; int res= 1;
bool locked= false;
my_hash_init(&gtid_hash, &my_charset_bin, 32, offsetof(rpl_gtid, domain_id), my_hash_init(&gtid_hash, &my_charset_bin, 32, offsetof(rpl_gtid, domain_id),
sizeof(uint32), NULL, NULL, HASH_UNIQUE); sizeof(uint32), NULL, NULL, HASH_UNIQUE);
...@@ -741,6 +804,8 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, ...@@ -741,6 +804,8 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
goto err; goto err;
mysql_mutex_lock(&LOCK_slave_state); mysql_mutex_lock(&LOCK_slave_state);
locked= true;
reset_dynamic(&gtid_sort_array);
for (i= 0; i < hash.records; ++i) for (i= 0; i < hash.records; ++i)
{ {
...@@ -775,31 +840,38 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, ...@@ -775,31 +840,38 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
memcpy(&best_gtid, gtid, sizeof(best_gtid)); memcpy(&best_gtid, gtid, sizeof(best_gtid));
if (my_hash_delete(&gtid_hash, rec)) if (my_hash_delete(&gtid_hash, rec))
{ {
mysql_mutex_unlock(&LOCK_slave_state);
goto err; goto err;
} }
} }
if ((res= (*cb)(&best_gtid, data))) if ((res= sort ? insert_dynamic(&gtid_sort_array,
(const void *) &best_gtid) :
(*cb)(&best_gtid, data)))
{ {
mysql_mutex_unlock(&LOCK_slave_state);
goto err; goto err;
} }
} }
mysql_mutex_unlock(&LOCK_slave_state);
/* Also add any remaining extra domain_ids. */ /* Also add any remaining extra domain_ids. */
for (i= 0; i < gtid_hash.records; ++i) for (i= 0; i < gtid_hash.records; ++i)
{ {
gtid= (rpl_gtid *)my_hash_element(&gtid_hash, i); gtid= (rpl_gtid *)my_hash_element(&gtid_hash, i);
if ((res= (*cb)(gtid, data))) if ((res= sort ? insert_dynamic(&gtid_sort_array, (const void *) gtid) :
(*cb)(gtid, data)))
{
goto err; goto err;
}
}
if (sort && rpl_slave_state_tostring_helper(&gtid_sort_array, cb, data))
{
goto err;
} }
res= 0; res= 0;
err: err:
if (locked) mysql_mutex_unlock(&LOCK_slave_state);
my_hash_free(&gtid_hash); my_hash_free(&gtid_hash);
return res; return res;
...@@ -840,7 +912,8 @@ rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra) ...@@ -840,7 +912,8 @@ rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra)
data.first= true; data.first= true;
data.dest= dest; 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() ...@@ -1030,6 +1103,7 @@ rpl_binlog_state::rpl_binlog_state()
{ {
my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
sizeof(uint32), NULL, my_free, HASH_UNIQUE); sizeof(uint32), NULL, my_free, HASH_UNIQUE);
my_init_dynamic_array(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state, mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state,
MY_MUTEX_INIT_SLOW); MY_MUTEX_INIT_SLOW);
initialized= 1; initialized= 1;
...@@ -1063,6 +1137,7 @@ void rpl_binlog_state::free() ...@@ -1063,6 +1137,7 @@ void rpl_binlog_state::free()
initialized= 0; initialized= 0;
reset_nolock(); reset_nolock();
my_hash_free(&hash); my_hash_free(&hash);
delete_dynamic(&gtid_sort_array);
mysql_mutex_destroy(&LOCK_binlog_state); mysql_mutex_destroy(&LOCK_binlog_state);
} }
} }
...@@ -1547,21 +1622,25 @@ end: ...@@ -1547,21 +1622,25 @@ end:
return res; return res;
} }
bool bool
rpl_binlog_state::append_pos(String *str) rpl_binlog_state::append_pos(String *str)
{ {
uint32 i; uint32 i;
bool first= true;
mysql_mutex_lock(&LOCK_binlog_state); mysql_mutex_lock(&LOCK_binlog_state);
reset_dynamic(&gtid_sort_array);
for (i= 0; i < hash.records; ++i) for (i= 0; i < hash.records; ++i)
{ {
element *e= (element *)my_hash_element(&hash, i); element *e= (element *)my_hash_element(&hash, i);
if (e->last_gtid && if (e->last_gtid &&
rpl_slave_state_tostring_helper(str, e->last_gtid, &first)) insert_dynamic(&gtid_sort_array, (const void *) e->last_gtid))
{
mysql_mutex_unlock(&LOCK_binlog_state);
return true; return true;
}
} }
rpl_slave_state_tostring_helper(&gtid_sort_array, str);
mysql_mutex_unlock(&LOCK_binlog_state); mysql_mutex_unlock(&LOCK_binlog_state);
return false; return false;
...@@ -1572,10 +1651,11 @@ bool ...@@ -1572,10 +1651,11 @@ bool
rpl_binlog_state::append_state(String *str) rpl_binlog_state::append_state(String *str)
{ {
uint32 i, j; uint32 i, j;
bool first= true;
bool res= false; bool res= false;
mysql_mutex_lock(&LOCK_binlog_state); mysql_mutex_lock(&LOCK_binlog_state);
reset_dynamic(&gtid_sort_array);
for (i= 0; i < hash.records; ++i) for (i= 0; i < hash.records; ++i)
{ {
element *e= (element *)my_hash_element(&hash, i); element *e= (element *)my_hash_element(&hash, i);
...@@ -1596,7 +1676,7 @@ rpl_binlog_state::append_state(String *str) ...@@ -1596,7 +1676,7 @@ rpl_binlog_state::append_state(String *str)
else else
gtid= e->last_gtid; gtid= e->last_gtid;
if (rpl_slave_state_tostring_helper(str, gtid, &first)) if (insert_dynamic(&gtid_sort_array, (const void *) gtid))
{ {
res= true; res= true;
goto end; goto end;
...@@ -1604,6 +1684,8 @@ rpl_binlog_state::append_state(String *str) ...@@ -1604,6 +1684,8 @@ rpl_binlog_state::append_state(String *str)
} }
} }
rpl_slave_state_tostring_helper(&gtid_sort_array, str);
end: end:
mysql_mutex_unlock(&LOCK_binlog_state); mysql_mutex_unlock(&LOCK_binlog_state);
return res; return res;
...@@ -1615,12 +1697,14 @@ slave_connection_state::slave_connection_state() ...@@ -1615,12 +1697,14 @@ slave_connection_state::slave_connection_state()
my_hash_init(&hash, &my_charset_bin, 32, my_hash_init(&hash, &my_charset_bin, 32,
offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id), offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id),
sizeof(uint32), NULL, my_free, HASH_UNIQUE); sizeof(uint32), NULL, my_free, HASH_UNIQUE);
my_init_dynamic_array(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
} }
slave_connection_state::~slave_connection_state() slave_connection_state::~slave_connection_state()
{ {
my_hash_free(&hash); my_hash_free(&hash);
delete_dynamic(&gtid_sort_array);
} }
...@@ -1730,7 +1814,7 @@ slave_connection_state::load(rpl_slave_state *state, ...@@ -1730,7 +1814,7 @@ slave_connection_state::load(rpl_slave_state *state,
{ {
reset(); reset();
return state->iterate(slave_connection_state_load_cb, this, return state->iterate(slave_connection_state_load_cb, this,
extra_gtids, num_extra); extra_gtids, num_extra, false);
} }
......
...@@ -159,6 +159,8 @@ struct rpl_slave_state ...@@ -159,6 +159,8 @@ struct rpl_slave_state
HASH hash; HASH hash;
/* Mutex protecting access to the state. */ /* Mutex protecting access to the state. */
mysql_mutex_t LOCK_slave_state; mysql_mutex_t LOCK_slave_state;
/* Auxiliary buffer to sort gtid list. */
DYNAMIC_ARRAY gtid_sort_array;
uint64 last_sub_id; uint64 last_sub_id;
bool inited; bool inited;
...@@ -178,7 +180,8 @@ struct rpl_slave_state ...@@ -178,7 +180,8 @@ struct rpl_slave_state
bool in_transaction, bool in_statement); bool in_transaction, bool in_statement);
uint64 next_sub_id(uint32 domain_id); uint64 next_sub_id(uint32 domain_id);
int iterate(int (*cb)(rpl_gtid *, void *), void *data, 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); int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra);
bool domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid); bool domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid);
int load(THD *thd, char *state_from_master, size_t len, bool reset, int load(THD *thd, char *state_from_master, size_t len, bool reset,
...@@ -228,6 +231,9 @@ struct rpl_binlog_state ...@@ -228,6 +231,9 @@ struct rpl_binlog_state
mysql_mutex_t LOCK_binlog_state; mysql_mutex_t LOCK_binlog_state;
my_bool initialized; my_bool initialized;
/* Auxiliary buffer to sort gtid list. */
DYNAMIC_ARRAY gtid_sort_array;
rpl_binlog_state(); rpl_binlog_state();
~rpl_binlog_state(); ~rpl_binlog_state();
...@@ -271,6 +277,9 @@ struct slave_connection_state ...@@ -271,6 +277,9 @@ struct slave_connection_state
/* Mapping from domain_id to the entry with GTID requested for that domain. */ /* Mapping from domain_id to the entry with GTID requested for that domain. */
HASH hash; HASH hash;
/* Auxiliary buffer to sort gtid list. */
DYNAMIC_ARRAY gtid_sort_array;
slave_connection_state(); slave_connection_state();
~slave_connection_state(); ~slave_connection_state();
......
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