[Commits] Rev 3450: MDEV-26: Global transaction ID. in http://bazaar.launchpad.net/~maria-captains/maria/10.0

knielsen at knielsen-hq.org knielsen at knielsen-hq.org
Thu Feb 14 15:42:05 EET 2013


At http://bazaar.launchpad.net/~maria-captains/maria/10.0

------------------------------------------------------------
revno: 3450
revision-id: knielsen at knielsen-hq.org-20130214134205-403yjqvzva6xk52j
parent: knielsen at knielsen-hq.org-20130213123646-6kzi7kilctvmvc42
committer: knielsen at knielsen-hq.org
branch nick: work-10.0-mdev26
timestamp: Thu 2013-02-14 14:42:05 +0100
message:
  MDEV-26: Global transaction ID.
  
  Slave now loads the GTID state from the master when connecting with
  old-style filename/offset position.
  
  This allows the user to use MASTER_GTID_POS=AUTO on next CHANGE MASTER
  without any other action needed.
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2013-02-11 15:44:38 +0000
+++ b/sql/log_event.cc	2013-02-14 13:42:05 +0000
@@ -6162,8 +6162,6 @@ rpl_slave_state::record_gtid(THD *thd, c
   list_element *elist= 0, *next;
   element *elem;
 
-  DBUG_ASSERT(in_transaction /* ToDo: new transaction for DDL etc. */);
-
   mysql_reset_thd_for_next_command(thd, 0);
 
   tlist.init_one_table(STRING_WITH_LEN("mysql"),
@@ -6236,14 +6234,14 @@ rpl_slave_state::record_gtid(THD *thd, c
       */
       ha_rollback_trans(thd, FALSE);
       close_thread_tables(thd);
-      if (in_transaction)
+      if (!in_transaction)
         ha_rollback_trans(thd, TRUE);
     }
     else
     {
       ha_commit_trans(thd, FALSE);
       close_thread_tables(thd);
-      if (in_transaction)
+      if (!in_transaction)
         ha_commit_trans(thd, TRUE);
     }
   }
@@ -6376,6 +6374,89 @@ rpl_slave_state::tostring(String *dest,
 }
 
 
+/*
+  Parse a GTID at the start of a string, and update the pointer to point
+  at the first character after the parsed GTID.
+
+  GTID can be in short form with domain_id=0 implied, SERVERID-SEQNO.
+  Or long form, DOMAINID-SERVERID-SEQNO.
+
+  Returns 0 on ok, non-zero on parse error.
+*/
+static int
+gtid_parser_helper(char **ptr, char *end, rpl_gtid *out_gtid)
+{
+  char *q;
+  char *p= *ptr;
+  uint64 v1, v2, v3;
+  int err= 0;
+
+  q= end;
+  v1= (uint64)my_strtoll10(p, &q, &err);
+  if (err != 0 || v1 > (uint32)0xffffffff || q == end || *q != '-')
+    return 1;
+  p= q+1;
+  q= end;
+  v2= (uint64)my_strtoll10(p, &q, &err);
+  if (err != 0)
+    return 1;
+  if (q == end || *q != '-')
+  {
+    /* Short form SERVERID-SEQNO, domain_id=0 implied. */
+    out_gtid->domain_id= 0;
+    out_gtid->server_id= v1;
+    out_gtid->seq_no= v2;
+    *ptr= q;
+    return 0;
+  }
+
+  /* Long form DOMAINID-SERVERID-SEQNO. */
+  if (v2 > (uint32)0xffffffff)
+    return 1;
+  p= q+1;
+  q= end;
+  v3= (uint64)my_strtoll10(p, &q, &err);
+  if (err != 0)
+    return 1;
+
+  out_gtid->domain_id= v1;
+  out_gtid->server_id= v2;
+  out_gtid->seq_no= v3;
+  *ptr= q;
+  return 0;
+}
+
+
+/*
+  Update the slave replication state with the GTID position obtained from
+  master when connecting with old-style (filename,offset) position.
+
+  Returns 0 if ok, non-zero if error.
+*/
+int
+rpl_slave_state::load(THD *thd, char *state_from_master)
+{
+  char *end= state_from_master + strlen(state_from_master);
+
+  for (;;)
+  {
+    rpl_gtid gtid;
+    uint64 sub_id;
+
+    if (gtid_parser_helper(&state_from_master, end, &gtid) ||
+        !(sub_id= next_subid(gtid.domain_id)) ||
+        record_gtid(thd, &gtid, sub_id, false) ||
+        update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no))
+      return 1;
+    if (state_from_master == end)
+      break;
+    if (*state_from_master != ',')
+      return 1;
+  }
+  return 0;
+}
+
+
 bool
 rpl_slave_state::is_empty()
 {
@@ -6638,52 +6719,29 @@ slave_connection_state::~slave_connectio
 int
 slave_connection_state::load(char *slave_request, size_t len)
 {
-  char *p, *q, *end;
-  uint64 v;
-  uint32 domain_id, server_id;
-  uint64 seq_no;
+  char *p, *end;
   uchar *rec;
   rpl_gtid *gtid;
-  int err= 0;
 
   my_hash_reset(&hash);
   p= slave_request;
   end= slave_request + len;
   for (;;)
   {
-    q= end;
-    v= (uint64)my_strtoll10(p, &q, &err);
-    if (err != 0 || v > (uint32)0xffffffff || *q != '-')
-      return 1;
-    domain_id= (uint32)v;
-    p= q+1;
-    q= end;
-    v= (uint64)my_strtoll10(p, &q, &err);
-    if (err != 0 || v > (uint32)0xffffffff || *q != '-')
-      return 1;
-    server_id= (uint32)v;
-    p= q+1;
-    q= end;
-    seq_no= (uint64)my_strtoll10(p, &q, &err);
-    if (err != 0)
-      return 1;
-
     if (!(rec= (uchar *)my_malloc(sizeof(*gtid), MYF(MY_WME))))
       return 1;
     gtid= (rpl_gtid *)rec;
-    gtid->domain_id= domain_id;
-    gtid->server_id= server_id;
-    gtid->seq_no= seq_no;
-    if (my_hash_insert(&hash, rec))
+    if (gtid_parser_helper(&p, end, gtid) ||
+        my_hash_insert(&hash, rec))
     {
       my_free(rec);
       return 1;
     }
-    if (q == end)
+    if (p == end)
       break;                                         /* Finished. */
-    if (*q != ',')
+    if (*p != ',')
       return 1;
-    p= q+1;
+    ++p;
   }
 
   return 0;
@@ -7639,30 +7697,21 @@ int Xid_log_event::do_apply_event(Relay_
       mysql.rpl_slave_state is non-transactional and the row is not removed
       by rollback.
     */
-    rpl_slave_state::element *elem=
-      rpl_global_gtid_slave_state.get_element(gtid.domain_id);
-    rpl_slave_state::list_element *lelem=
-      (rpl_slave_state::list_element *)my_malloc(sizeof(*lelem), MYF(MY_WME));
-    if (elem && lelem)
-    {
-      lelem->sub_id= sub_id;
-      lelem->server_id= gtid.server_id;
-      lelem->seq_no= gtid.seq_no;
-      elem->add(lelem);
-    }
-    else
+    rpl_global_gtid_slave_state.lock();
+    err= rpl_global_gtid_slave_state.update(gtid.domain_id, gtid.server_id,
+                                            sub_id, gtid.seq_no);
+    rpl_global_gtid_slave_state.unlock();
+    if (err)
     {
-      if (lelem)
-        my_free(lelem);
       sql_print_warning("Slave: Out of memory during slave state maintenance. "
                         "Some no longer necessary rows in table "
                         "mysql.rpl_slave_state may be left undeleted.");
+      /*
+        Such failure is not fatal. We will fail to delete the row for this
+        GTID, but it will do no harm and will be removed automatically on next
+        server restart.
+      */
     }
-    /*
-      Such failure is not fatal. We will fail to delete the row for this GTID,
-      but it will do no harm and will be removed automatically on next server
-      restart.
-    */
   }
 
   /*

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2013-02-11 15:44:38 +0000
+++ b/sql/log_event.h	2013-02-14 13:42:05 +0000
@@ -3009,6 +3009,7 @@ struct rpl_slave_state
                       bool in_transaction);
   uint64 next_subid(uint32 domain_id);
   int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra);
+  int load(THD *thd, char *state_from_master);
   bool is_empty();
 
   void lock() { DBUG_ASSERT(inited); mysql_mutex_lock(&LOCK_slave_state); }

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2013-01-25 14:21:49 +0000
+++ b/sql/slave.cc	2013-02-14 13:42:05 +0000
@@ -1835,6 +1835,60 @@ when it try to get the value of TIME_ZON
       }
     }
   }
+  else
+  {
+    /*
+      If we are not using GTID to connect this time, then instead request
+      the corresponding GTID position from the master, so that the user
+      can reconnect the next time using MASTER_GTID_POS=AUTO.
+    */
+    char quote_buf[2*sizeof(mi->master_log_name)+1];
+    char str_buf[28+2*sizeof(mi->master_log_name)+10];
+    String query(str_buf, sizeof(str_buf), system_charset_info);
+    query.length(0);
+
+    query.append("SELECT binlog_gtid_pos('");
+    escape_quotes_for_mysql(&my_charset_bin, quote_buf, sizeof(quote_buf),
+                            mi->master_log_name, strlen(mi->master_log_name));
+    query.append(quote_buf);
+    query.append("',");
+    query.append_ulonglong(mi->master_log_pos);
+    query.append(")");
+
+    if (!mysql_real_query(mysql, query.c_ptr_safe(), query.length()) &&
+        (master_res= mysql_store_result(mysql)) &&
+        (master_row= mysql_fetch_row(master_res)) &&
+        (master_row[0] != NULL))
+    {
+      rpl_global_gtid_slave_state.load(mi->io_thd, master_row[0]);
+    }
+    else if (check_io_slave_killed(mi->io_thd, mi, NULL))
+      goto slave_killed_err;
+    else if (is_network_error(mysql_errno(mysql)))
+    {
+      mi->report(WARNING_LEVEL, mysql_errno(mysql),
+                 "Get master GTID position failed with error: %s", mysql_error(mysql));
+      goto network_err;
+    }
+    else
+    {
+      /*
+        ToDo: If the master does not have the binlog_gtid_pos() function, it
+        just means that it is an old master with no GTID support, so we should
+        do nothing.
+
+        However, if binlog_gtid_pos() exists, but fails or returns NULL, then
+        it means that the requested position is not valid. We could use this
+        to catch attempts to replicate from within the middle of an event,
+        avoiding strange failures or possible corruption.
+      */
+    }
+    if (master_res)
+    {
+      mysql_free_result(master_res);
+      master_res= NULL;
+    }
+  }
 
 err:
   if (errmsg)



More information about the commits mailing list