[Commits] 101d7eb: MDEV-4987: Sort by domain_id when list of GTIDs are output
nirbhay at mariadb.com
nirbhay at mariadb.com
Sun Feb 1 04:49:15 EET 2015
revision-id: 101d7eb963816514362da8a98fc7db7135181910
parent(s): 0105bf349a44f33fff3410af1db31d4c6116f14a
committer: Nirbhay Choubey
branch nick: 10.1-b4987
timestamp: 2015-01-31 21:48:14 -0500
message:
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.
---
mysql-test/suite/rpl/r/rpl_gtid_sort.result | 88 +++++++++++++++++++++++
mysql-test/suite/rpl/t/rpl_gtid_sort.test | 57 +++++++++++++++
sql/rpl_gtid.cc | 104 ++++++++++++++++++++++++----
sql/rpl_gtid.h | 11 ++-
4 files changed, 245 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 0000000..279bd18
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_gtid_sort.result
@@ -0,0 +1,88 @@
+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%';
+Variable_name Value
+gtid_binlog_pos
+gtid_binlog_state
+gtid_current_pos
+gtid_domain_id 0
+gtid_ignore_duplicates OFF
+gtid_seq_no 0
+gtid_slave_pos
+gtid_strict_mode OFF
+last_gtid
+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);
+SHOW VARIABLES LIKE '%GTID%';
+Variable_name Value
+gtid_binlog_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_binlog_state 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_current_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_domain_id 100
+gtid_ignore_duplicates OFF
+gtid_seq_no 0
+gtid_slave_pos
+gtid_strict_mode OFF
+last_gtid 100-1-1
+SHOW VARIABLES LIKE '%GTID%';
+Variable_name Value
+gtid_binlog_pos
+gtid_binlog_state
+gtid_current_pos
+gtid_domain_id 0
+gtid_ignore_duplicates OFF
+gtid_seq_no 0
+gtid_slave_pos
+gtid_strict_mode OFF
+last_gtid
+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%';
+Variable_name Value
+gtid_binlog_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_binlog_state 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_current_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_domain_id 0
+gtid_ignore_duplicates OFF
+gtid_seq_no 0
+gtid_slave_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_strict_mode OFF
+last_gtid
+SELECT * FROM t1;
+a
+1
+3
+4
+5
+SET @@SESSION.gtid_domain_id=1000;
+INSERT INTO t1 VALUES(6);
+SET @@SESSION.gtid_domain_id=89;
+INSERT INTO t1 VALUES(7);
+SET @@SESSION.gtid_domain_id=10100000;
+INSERT INTO t1 VALUES(8);
+SHOW VARIABLES LIKE '%GTID%';
+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
+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
+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
+gtid_domain_id 10100000
+gtid_ignore_duplicates OFF
+gtid_seq_no 0
+gtid_slave_pos 0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1
+gtid_strict_mode OFF
+last_gtid 10100000-2-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 0000000..d3b8c6d
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_gtid_sort.test
@@ -0,0 +1,57 @@
+--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%';
+
+--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);
+
+SHOW VARIABLES LIKE '%GTID%';
+--save_master_pos
+
+--connection server_2
+SHOW VARIABLES LIKE '%GTID%';
+#SET GLOBAL gtid_slave_pos="";
+--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%';
+SELECT * FROM t1;
+
+SET @@SESSION.gtid_domain_id=1000;
+INSERT INTO t1 VALUES(6);
+
+SET @@SESSION.gtid_domain_id=89;
+INSERT INTO t1 VALUES(7);
+
+SET @@SESSION.gtid_domain_id=10100000;
+INSERT INTO t1 VALUES(8);
+
+SHOW VARIABLES LIKE '%GTID%';
+
+# 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 e5620ec..a0471f3 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -247,11 +247,13 @@
{
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_cache, sizeof(rpl_gtid), 8, 8, MYF(0));
}
rpl_slave_state::~rpl_slave_state()
{
+ delete_dynamic(>id_cache);
}
@@ -705,7 +707,13 @@ class Gtid_db_intact : public Table_check_intact
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)
+{
+ return (((rpl_gtid *)id1)->domain_id - ((rpl_gtid *)id2)->domain_id);
+}
+/* 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 +730,64 @@ class Gtid_db_intact : public Table_check_intact
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 +797,8 @@ class Gtid_db_intact : public Table_check_intact
goto err;
mysql_mutex_lock(&LOCK_slave_state);
+ locked= true;
+ reset_dynamic(>id_cache);
for (i= 0; i < hash.records; ++i)
{
@@ -775,31 +833,37 @@ class Gtid_db_intact : public Table_check_intact
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_cache, (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_cache, (const void *) gtid) :
+ (*cb)(gtid, data)))
+ {
goto err;
+ }
+ }
+
+ if (sort && rpl_slave_state_tostring_helper(>id_cache, cb, data))
+ {
+ goto err;
}
res= 0;
err:
+ if (locked) mysql_mutex_unlock(&LOCK_slave_state);
my_hash_free(>id_hash);
return res;
@@ -840,7 +904,8 @@ struct rpl_slave_state_tostring_data {
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 +1095,7 @@ struct rpl_slave_state_tostring_data {
{
my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
+ my_init_dynamic_array(>id_cache, 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 +1129,7 @@ void rpl_binlog_state::free()
initialized= 0;
reset_nolock();
my_hash_free(&hash);
+ delete_dynamic(>id_cache);
mysql_mutex_destroy(&LOCK_binlog_state);
}
}
@@ -1547,21 +1614,25 @@ void rpl_binlog_state::free()
return res;
}
-
bool
rpl_binlog_state::append_pos(String *str)
{
uint32 i;
- bool first= true;
mysql_mutex_lock(&LOCK_binlog_state);
+ reset_dynamic(>id_cache);
+
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_cache, (const void *) e->last_gtid))
+ {
+ mysql_mutex_unlock(&LOCK_binlog_state);
return true;
+ }
}
+ rpl_slave_state_tostring_helper(>id_cache, str);
mysql_mutex_unlock(&LOCK_binlog_state);
return false;
@@ -1572,10 +1643,11 @@ void rpl_binlog_state::free()
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_cache);
+
for (i= 0; i < hash.records; ++i)
{
element *e= (element *)my_hash_element(&hash, i);
@@ -1596,7 +1668,7 @@ void rpl_binlog_state::free()
else
gtid= e->last_gtid;
- if (rpl_slave_state_tostring_helper(str, gtid, &first))
+ if (insert_dynamic(>id_cache, (const void *) gtid))
{
res= true;
goto end;
@@ -1604,6 +1676,8 @@ void rpl_binlog_state::free()
}
}
+ rpl_slave_state_tostring_helper(>id_cache, str);
+
end:
mysql_mutex_unlock(&LOCK_binlog_state);
return res;
@@ -1615,12 +1689,14 @@ void rpl_binlog_state::free()
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_cache, sizeof(rpl_gtid), 8, 8, MYF(0));
}
slave_connection_state::~slave_connection_state()
{
my_hash_free(&hash);
+ delete_dynamic(>id_cache);
}
@@ -1730,7 +1806,7 @@ void rpl_binlog_state::free()
{
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 b203f34..ae892ff 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;
+ /* Temporary buffer to sort gtid list. */
+ DYNAMIC_ARRAY gtid_cache;
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;
+ /* Temporary buffer to sort gtid list. */
+ DYNAMIC_ARRAY gtid_cache;
+
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;
+ /* Temporary buffer to sort gtid list. */
+ DYNAMIC_ARRAY gtid_cache;
+
slave_connection_state();
~slave_connection_state();
More information about the commits
mailing list