[Commits] 596accb: MDEV-4987: Sort by domain_id when list of GTIDs are output

nirbhay at mariadb.com nirbhay at mariadb.com
Tue Feb 3 05:55:19 EET 2015


revision-id: 596accbf4e0817c60721343fe97fdb0a543287d3
parent(s): d8eba59d9c30046ac949290a6147da058102d8f8
committer: Nirbhay Choubey
branch nick: 10.1-b4987
timestamp: 2015-02-02 22:54:18 -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 |  94 +++++++++++++++++++++++
 mysql-test/suite/rpl/t/rpl_gtid_sort.test   |  62 +++++++++++++++
 sql/rpl_gtid.cc                             | 112 ++++++++++++++++++++++++----
 sql/rpl_gtid.h                              |  11 ++-
 4 files changed, 264 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..00f206e
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_gtid_sort.result
@@ -0,0 +1,94 @@
+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);
+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%';
+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
+gtid_binlog_state	0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1
+gtid_current_pos	0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1
+gtid_domain_id	4294967295
+gtid_ignore_duplicates	OFF
+gtid_seq_no	0
+gtid_slave_pos	
+gtid_strict_mode	OFF
+last_gtid	4294967295-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,2147483648-1-1,4294967295-1-1
+gtid_binlog_state	0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-1-1
+gtid_current_pos	0-1-1,1-1-1,10-1-1,100-1-1,99999-1-1,2147483648-1-1,4294967295-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,2147483648-1-1,4294967295-1-1
+gtid_strict_mode	OFF
+last_gtid	
+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%';
+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
+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
+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
+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,2147483648-1-1,4294967295-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..b46afdc
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_gtid_sort.test
@@ -0,0 +1,62 @@
+--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);
+
+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%';
+--save_master_pos
+
+--connection server_2
+SHOW VARIABLES LIKE '%GTID%';
+--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(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%';
+
+# 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..8b339e0 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -247,6 +247,7 @@
 {
   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(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
 }
 
 
@@ -292,6 +293,7 @@
     return;
   truncate_hash();
   my_hash_free(&hash);
+  delete_dynamic(&gtid_sort_array);
   mysql_mutex_destroy(&LOCK_slave_state);
 }
 
@@ -705,7 +707,20 @@ 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)
+{
+  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 @@ 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(&gtid_hash, &my_charset_bin, 32, offsetof(rpl_gtid, domain_id),
                sizeof(uint32), NULL, NULL, HASH_UNIQUE);
@@ -741,6 +804,8 @@ class Gtid_db_intact : public Table_check_intact
       goto err;
 
   mysql_mutex_lock(&LOCK_slave_state);
+  locked= true;
+  reset_dynamic(&gtid_sort_array);
 
   for (i= 0; i < hash.records; ++i)
   {
@@ -775,31 +840,38 @@ class Gtid_db_intact : public Table_check_intact
         memcpy(&best_gtid, gtid, sizeof(best_gtid));
       if (my_hash_delete(&gtid_hash, rec))
       {
-        mysql_mutex_unlock(&LOCK_slave_state);
         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;
     }
   }
 
-  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(&gtid_hash, i);
-    if ((res= (*cb)(gtid, data)))
+    if ((res= sort ? insert_dynamic(&gtid_sort_array, (const void *) gtid) :
+         (*cb)(gtid, data)))
+    {
       goto err;
+    }
+  }
+
+  if (sort && rpl_slave_state_tostring_helper(&gtid_sort_array, cb, data))
+  {
+    goto err;
   }
 
   res= 0;
 
 err:
+  if (locked) mysql_mutex_unlock(&LOCK_slave_state);
   my_hash_free(&gtid_hash);
 
   return res;
@@ -840,7 +912,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 +1103,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(&gtid_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(&gtid_sort_array);
     mysql_mutex_destroy(&LOCK_binlog_state);
   }
 }
@@ -1547,21 +1622,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(&gtid_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(&gtid_sort_array, (const void *) e->last_gtid))
+    {
+      mysql_mutex_unlock(&LOCK_binlog_state);
       return true;
+    }
   }
+  rpl_slave_state_tostring_helper(&gtid_sort_array, str);
   mysql_mutex_unlock(&LOCK_binlog_state);
 
   return false;
@@ -1572,10 +1651,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(&gtid_sort_array);
+
   for (i= 0; i < hash.records; ++i)
   {
     element *e= (element *)my_hash_element(&hash, i);
@@ -1596,7 +1676,7 @@ void rpl_binlog_state::free()
       else
         gtid= e->last_gtid;
 
-      if (rpl_slave_state_tostring_helper(str, gtid, &first))
+      if (insert_dynamic(&gtid_sort_array, (const void *) gtid))
       {
         res= true;
         goto end;
@@ -1604,6 +1684,8 @@ void rpl_binlog_state::free()
     }
   }
 
+  rpl_slave_state_tostring_helper(&gtid_sort_array, str);
+
 end:
   mysql_mutex_unlock(&LOCK_binlog_state);
   return res;
@@ -1615,12 +1697,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(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
 }
 
 
 slave_connection_state::~slave_connection_state()
 {
   my_hash_free(&hash);
+  delete_dynamic(&gtid_sort_array);
 }
 
 
@@ -1730,7 +1814,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..bd58d09 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();
 


More information about the commits mailing list