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.
This commit is contained in:
parent
34d86ac9ff
commit
75a27eeaf7
99
mysql-test/suite/rpl/r/rpl_gtid_sort.result
Normal file
99
mysql-test/suite/rpl/r/rpl_gtid_sort.result
Normal file
@ -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
|
77
mysql-test/suite/rpl/t/rpl_gtid_sort.test
Normal file
77
mysql-test/suite/rpl/t/rpl_gtid_sort.test
Normal file
@ -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
|
112
sql/rpl_gtid.cc
112
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user