[Commits] Rev 3679: MDEV-4488: When master is on the list of ignore_server_ids, GTID position on slave is not updated in http://bazaar.launchpad.net/~maria-captains/maria/10.0

knielsen at knielsen-hq.org knielsen at knielsen-hq.org
Thu Aug 22 13:36:42 EEST 2013


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

------------------------------------------------------------
revno: 3679
revision-id: knielsen at knielsen-hq.org-20130822103642-ktwgw2oj7qh09400
parent: knielsen at knielsen-hq.org-20130820114450-91f91xkg2omt3yrh
committer: knielsen at knielsen-hq.org
branch nick: work-10.0-mdev26
timestamp: Thu 2013-08-22 12:36:42 +0200
message:
  MDEV-4488: When master is on the list of ignore_server_ids, GTID position on slave is not updated
  
  The ignored events are not written to the relay log, but instead a fake
  Rotate event is generated to handle update of position.
  
  Extend this for Gtid so we similarly generate a fake Gtid_list event
  to update the GTID position.
  
  Also fix an unrelated test issue that got triggered by the added test cases.
=== added file 'mysql-test/suite/rpl/r/rpl_gtid_ignored.result'
--- a/mysql-test/suite/rpl/r/rpl_gtid_ignored.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_gtid_ignored.result	2013-08-22 10:36:42 +0000
@@ -0,0 +1,70 @@
+include/rpl_init.inc [topology=1->2]
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= 1;
+include/stop_slave.inc
+SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+include/start_slave.inc
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+**** MDEV-4488: GTID position should be updated for events that are ignored due to server id ***
+include/stop_slave.inc
+CHANGE MASTER TO ignore_server_ids=(1);
+include/start_slave.inc
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+RESULT
+OK
+SELECT * FROM t1 ORDER BY a;
+a
+1
+include/stop_slave.inc
+CHANGE MASTER TO ignore_server_ids=();
+include/start_slave.inc
+RESULT
+OK
+SELECT * FROM t1 ORDER BY a;
+a
+1
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+RESULT
+OK
+a
+1
+4
+5
+*** Test the same thing when IO thread exits before SQL thread reaches end of log. ***
+include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= "+d,inject_slave_sql_before_apply_event";
+CHANGE MASTER TO ignore_server_ids=(1);
+include/start_slave.inc
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+include/wait_for_slave_param.inc [Read_Master_Log_Pos]
+STOP SLAVE IO_THREAD;
+SET debug_sync = "now SIGNAL continue";
+RESULT
+OK
+RESULT
+OK
+include/stop_slave.inc
+CHANGE MASTER TO ignore_server_ids=();
+SET GLOBAL debug_dbug= @old_dbug;
+include/start_slave.inc
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+SELECT * FROM t1 ORDER BY a;
+a
+1
+4
+5
+8
+9
+DROP TABLE t1;
+SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
+include/rpl_end.inc

=== modified file 'mysql-test/suite/rpl/r/rpl_gtid_mdev4484.result'
--- a/mysql-test/suite/rpl/r/rpl_gtid_mdev4484.result	2013-05-29 12:23:40 +0000
+++ b/mysql-test/suite/rpl/r/rpl_gtid_mdev4484.result	2013-08-22 10:36:42 +0000
@@ -7,10 +7,11 @@ INSERT INTO t1 VALUES (1);
 include/stop_slave.inc
 SET @old_dbug= @@GLOBAL.debug_dbug;
 SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete";
-include/start_slave.inc
 SET sql_log_bin= 0;
 CALL mtr.add_suppression("Can't find file");
+ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
 SET sql_log_bin= 1;
+include/start_slave.inc
 INSERT INTO t1 VALUES (2);
 include/wait_for_slave_sql_error.inc [errno=1942]
 STOP SLAVE IO_THREAD;

=== added file 'mysql-test/suite/rpl/t/rpl_gtid_ignored.test'
--- a/mysql-test/suite/rpl/t/rpl_gtid_ignored.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_gtid_ignored.test	2013-08-22 10:36:42 +0000
@@ -0,0 +1,136 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+
+--let $rpl_topology=1->2
+--source include/rpl_init.inc
+
+--connection server_1
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+
+SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= 1;
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode=1;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+--source include/start_slave.inc
+
+--connection server_1
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--echo **** MDEV-4488: GTID position should be updated for events that are ignored due to server id ***
+--source include/stop_slave.inc
+CHANGE MASTER TO ignore_server_ids=(1);
+--source include/start_slave.inc
+
+--connection server_1
+# These inserts should be ignored (not applied) on the slave, but the
+# gtid_slave_pos should still be updated.
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+--save_master_pos
+--let gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos`
+
+--connection server_2
+--sync_with_master
+--let $wait_condition= SELECT @@GLOBAL.gtid_slave_pos = '$gtid_pos'
+--source include/wait_condition.inc
+--disable_query_log
+eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT;
+--enable_query_log
+
+SELECT * FROM t1 ORDER BY a;
+
+--source include/stop_slave.inc
+CHANGE MASTER TO ignore_server_ids=();
+--source include/start_slave.inc
+--sync_with_master
+--disable_query_log
+eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT;
+--enable_query_log
+
+SELECT * FROM t1 ORDER BY a;
+
+--connection server_1
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+--let gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos`
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--disable_query_log
+eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT;
+SELECT * FROM t1 ORDER BY a;
+--enable_query_log
+
+
+--echo *** Test the same thing when IO thread exits before SQL thread reaches end of log. ***
+--connection server_2
+--source include/stop_slave.inc
+SET @old_dbug= @@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug= "+d,inject_slave_sql_before_apply_event";
+CHANGE MASTER TO ignore_server_ids=(1);
+--source include/start_slave.inc
+
+--connection server_1
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+--let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
+--let gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos`
+--save_master_pos
+
+--connection server_2
+# Wait for IO thread to have read all events from master, and for SQL thread to
+# sit in the debug_sync point.
+
+--let $slave_param= Read_Master_Log_Pos
+--let $slave_param_value= $master_pos
+--source include/wait_for_slave_param.inc
+
+# Now stop the IO thread, and let the SQL thread continue. The IO thread
+# should write a Gtid_list event that the SQL thread can use to update the
+# gtid_slave_pos with the GTIDs of the skipped events.
+STOP SLAVE IO_THREAD;
+SET debug_sync = "now SIGNAL continue";
+
+--sync_with_master
+--let $wait_condition= SELECT @@GLOBAL.gtid_slave_pos = '$gtid_pos'
+--source include/wait_condition.inc
+--disable_query_log
+eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT;
+--let $slave_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1)
+eval SELECT IF('$slave_pos' = '$master_pos', 'OK', "ERROR: Expected $master_pos got $slave_pos") AS RESULT;
+--enable_query_log
+
+
+--source include/stop_slave.inc
+CHANGE MASTER TO ignore_server_ids=();
+SET GLOBAL debug_dbug= @old_dbug;
+--source include/start_slave.inc
+
+--connection server_1
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+SELECT * FROM t1 ORDER BY a;
+
+# Clean up.
+--connection server_1
+DROP TABLE t1;
+SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
+--connection server_2
+SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
+
+--source include/rpl_end.inc

=== modified file 'mysql-test/suite/rpl/t/rpl_gtid_mdev4484.test'
--- a/mysql-test/suite/rpl/t/rpl_gtid_mdev4484.test	2013-05-29 12:23:40 +0000
+++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4484.test	2013-08-22 10:36:42 +0000
@@ -18,10 +18,14 @@ INSERT INTO t1 VALUES (1);
 --source include/stop_slave.inc
 SET @old_dbug= @@GLOBAL.debug_dbug;
 SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete";
---source include/start_slave.inc
 SET sql_log_bin= 0;
 CALL mtr.add_suppression("Can't find file");
+# Since we inject an error updating mysql.gtid_slave_pos, we will get different
+# output depending on whether it is InnoDB or MyISAM (roll back or no roll
+# back). So fix it to make sure we are consistent.
+ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
 SET sql_log_bin= 1;
+--source include/start_slave.inc
 
 --connection master
 INSERT INTO t1 VALUES (2);

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2013-07-17 19:24:29 +0000
+++ b/sql/log_event.cc	2013-08-22 10:36:42 +0000
@@ -6334,7 +6334,7 @@ Gtid_log_event::print(FILE *file, PRINT_
 
 Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len,
                const Format_description_log_event *description_event)
-  : Log_event(buf, description_event), count(0), list(0)
+  : Log_event(buf, description_event), count(0), list(0), sub_id_list(0)
 {
   uint32 i;
   uint32 val;
@@ -6363,6 +6363,31 @@ Gtid_list_log_event::Gtid_list_log_event
     list[i].seq_no= uint8korr(buf);
     buf+= 8;
   }
+
+#ifdef MYSQL_SERVER
+  if ((gl_flags & FLAG_IGN_GTIDS))
+  {
+    uint32 i;
+    if (!(sub_id_list= (uint64 *)my_malloc(count*sizeof(uint64), MYF(MY_WME))))
+    {
+      my_free(list);
+      list= NULL;
+      return;
+    }
+    for (i= 0; i < count; ++i)
+    {
+      if (!(sub_id_list[i]=
+            rpl_global_gtid_slave_state.next_sub_id(list[i].domain_id)))
+      {
+        my_free(list);
+        my_free(sub_id_list);
+        list= NULL;
+        sub_id_list= NULL;
+        return;
+      }
+    }
+  }
+#endif
 }
 
 
@@ -6370,7 +6395,7 @@ Gtid_list_log_event::Gtid_list_log_event
 
 Gtid_list_log_event::Gtid_list_log_event(rpl_binlog_state *gtid_set,
                                          uint32 gl_flags_)
-  : count(gtid_set->count()), gl_flags(gl_flags_), list(0)
+  : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
 {
   cache_type= EVENT_NO_CACHE;
   /* Failure to allocate memory will be caught by is_valid() returning false. */
@@ -6381,6 +6406,45 @@ Gtid_list_log_event::Gtid_list_log_event
 }
 
 
+Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set,
+                                         uint32 gl_flags_)
+  : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
+{
+  cache_type= EVENT_NO_CACHE;
+  /* Failure to allocate memory will be caught by is_valid() returning false. */
+  if (count < (1<<28) &&
+      (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
+                                    MYF(MY_WME))))
+  {
+    gtid_set->get_gtid_list(list, count);
+    if (gl_flags & FLAG_IGN_GTIDS)
+    {
+      uint32 i;
+
+      if (!(sub_id_list= (uint64 *)my_malloc(count * sizeof(uint64),
+                                             MYF(MY_WME))))
+      {
+        my_free(list);
+        list= NULL;
+        return;
+      }
+      for (i= 0; i < count; ++i)
+      {
+        if (!(sub_id_list[i]=
+              rpl_global_gtid_slave_state.next_sub_id(list[i].domain_id)))
+        {
+          my_free(list);
+          my_free(sub_id_list);
+          list= NULL;
+          sub_id_list= NULL;
+          return;
+        }
+      }
+    }
+  }
+}
+
+
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
 bool
 Gtid_list_log_event::to_packet(String *packet)
@@ -6432,7 +6496,20 @@ Gtid_list_log_event::write(IO_CACHE *fil
 int
 Gtid_list_log_event::do_apply_event(Relay_log_info const *rli)
 {
-  int ret= Log_event::do_apply_event(rli);
+  int ret;
+  if (gl_flags & FLAG_IGN_GTIDS)
+  {
+    uint32 i;
+    for (i= 0; i < count; ++i)
+    {
+      if ((ret= rpl_global_gtid_slave_state.record_gtid(thd, &list[i],
+                                                        sub_id_list[i],
+                                                        false, false)))
+        return ret;
+      rpl_global_gtid_slave_state.update_state_hash(sub_id_list[i], &list[i]);
+    }
+  }
+  ret= Log_event::do_apply_event(rli);
   if (rli->until_condition == Relay_log_info::UNTIL_GTID &&
       (gl_flags & FLAG_UNTIL_REACHED))
   {

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2013-07-17 19:24:29 +0000
+++ b/sql/log_event.h	2013-08-22 10:36:42 +0000
@@ -3197,12 +3197,15 @@ class Gtid_list_log_event: public Log_ev
   uint32 count;
   uint32 gl_flags;
   struct rpl_gtid *list;
+  uint64 *sub_id_list;
 
   static const uint element_size= 4+4+8;
   static const uint32 FLAG_UNTIL_REACHED= (1<<28);
+  static const uint32 FLAG_IGN_GTIDS= (1<<29);
 
 #ifdef MYSQL_SERVER
   Gtid_list_log_event(rpl_binlog_state *gtid_set, uint32 gl_flags);
+  Gtid_list_log_event(slave_connection_state *gtid_set, uint32 gl_flags);
 #ifdef HAVE_REPLICATION
   void pack_info(THD *thd, Protocol *protocol);
 #endif
@@ -3211,7 +3214,7 @@ class Gtid_list_log_event: public Log_ev
 #endif
   Gtid_list_log_event(const char *buf, uint event_len,
                       const Format_description_log_event *description_event);
-  ~Gtid_list_log_event() { my_free(list); }
+  ~Gtid_list_log_event() { my_free(list); my_free(sub_id_list); }
   Log_event_type get_type_code() { return GTID_LIST_EVENT; }
   int get_data_size() {
     /*

=== modified file 'sql/rpl_gtid.cc'
--- a/sql/rpl_gtid.cc	2013-08-16 13:10:25 +0000
+++ b/sql/rpl_gtid.cc	2013-08-22 10:36:42 +0000
@@ -1419,6 +1419,15 @@ slave_connection_state::remove(const rpl
 }
 
 
+void
+slave_connection_state::remove_if_present(const rpl_gtid *in_gtid)
+{
+  uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id), 0);
+  if (rec)
+    my_hash_delete(&hash, rec);
+}
+
+
 int
 slave_connection_state::to_string(String *out_str)
 {
@@ -1442,3 +1451,22 @@ slave_connection_state::append_to_string
   }
   return 0;
 }
+
+
+int
+slave_connection_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
+{
+  uint32 i, pos;
+
+  pos= 0;
+  for (i= 0; i < hash.records; ++i)
+  {
+    entry *e;
+    if (pos >= list_size)
+      return 1;
+    e= (entry *)my_hash_element(&hash, i);
+    memcpy(&gtid_list[pos++], &e->gtid, sizeof(e->gtid));
+  }
+
+  return 0;
+}

=== modified file 'sql/rpl_gtid.h'
--- a/sql/rpl_gtid.h	2013-08-16 13:10:25 +0000
+++ b/sql/rpl_gtid.h	2013-08-22 10:36:42 +0000
@@ -195,9 +195,11 @@ struct slave_connection_state
   entry *find_entry(uint32 domain_id);
   int update(const rpl_gtid *in_gtid);
   void remove(const rpl_gtid *gtid);
+  void remove_if_present(const rpl_gtid *in_gtid);
   ulong count() const { return hash.records; }
   int to_string(String *out_str);
   int append_to_string(String *out_str);
+  int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size);
 };
 
 extern bool rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid,

=== modified file 'sql/rpl_rli.h'
--- a/sql/rpl_rli.h	2013-06-06 15:51:28 +0000
+++ b/sql/rpl_rli.h	2013-08-22 10:36:42 +0000
@@ -303,6 +303,8 @@ class Relay_log_info : public Slave_repo
   */
   char ign_master_log_name_end[FN_REFLEN];
   ulonglong ign_master_log_pos_end;
+  /* Similar for ignored GTID events. */
+  slave_connection_state ign_gtids;
 
   /* 
     Indentifies where the SQL Thread should create temporary files for the

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2013-08-20 11:44:50 +0000
+++ b/sql/slave.cc	2013-08-22 10:36:42 +0000
@@ -2222,34 +2222,66 @@ static void write_ignored_events_info_to
 
   DBUG_ASSERT(thd == mi->io_thd);
   mysql_mutex_lock(log_lock);
-  if (rli->ign_master_log_name_end[0])
+  if (rli->ign_master_log_name_end[0] || rli->ign_gtids.count())
   {
-    DBUG_PRINT("info",("writing a Rotate event to track down ignored events"));
-    Rotate_log_event *ev= new Rotate_log_event(rli->ign_master_log_name_end,
-                                               0, rli->ign_master_log_pos_end,
-                                               Rotate_log_event::DUP_NAME);
-    rli->ign_master_log_name_end[0]= 0;
-    /* can unlock before writing as slave SQL thd will soon see our Rotate */
+    Rotate_log_event *rev;
+    Gtid_list_log_event *glev;
+    if (rli->ign_master_log_name_end[0])
+    {
+      rev= new Rotate_log_event(rli->ign_master_log_name_end,
+                                0, rli->ign_master_log_pos_end,
+                                Rotate_log_event::DUP_NAME);
+      rli->ign_master_log_name_end[0]= 0;
+      if (unlikely(!(bool)rev))
+        mi->report(ERROR_LEVEL, ER_SLAVE_CREATE_EVENT_FAILURE,
+                   ER(ER_SLAVE_CREATE_EVENT_FAILURE),
+                   "Rotate_event (out of memory?),"
+                   " SHOW SLAVE STATUS may be inaccurate");
+    }
+    if (rli->ign_gtids.count())
+    {
+      glev= new Gtid_list_log_event(&rli->ign_gtids,
+                                    Gtid_list_log_event::FLAG_IGN_GTIDS);
+      rli->ign_gtids.reset();
+      if (unlikely(!(bool)glev))
+        mi->report(ERROR_LEVEL, ER_SLAVE_CREATE_EVENT_FAILURE,
+                   ER(ER_SLAVE_CREATE_EVENT_FAILURE),
+                   "Gtid_list_event (out of memory?),"
+                   " gtid_slave_pos may be inaccurate");
+    }
+
+    /* Can unlock before writing as slave SQL thd will soon see our event. */
     mysql_mutex_unlock(log_lock);
-    if (likely((bool)ev))
+    if (rev)
     {
-      ev->server_id= 0; // don't be ignored by slave SQL thread
-      if (unlikely(rli->relay_log.append(ev)))
+      DBUG_PRINT("info",("writing a Rotate event to track down ignored events"));
+      rev->server_id= 0; // don't be ignored by slave SQL thread
+      if (unlikely(rli->relay_log.append(rev)))
         mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
                    ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
                    "failed to write a Rotate event"
                    " to the relay log, SHOW SLAVE STATUS may be"
                    " inaccurate");
+      delete rev;
+    }
+    if (glev)
+    {
+      DBUG_PRINT("info",("writing a Gtid_list event to track down ignored events"));
+      glev->server_id= 0; // don't be ignored by slave SQL thread
+      glev->set_artificial_event(); // Don't mess up Exec_Master_Log_Pos
+      if (unlikely(rli->relay_log.append(glev)))
+        mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
+                   ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
+                   "failed to write a Gtid_list event to the relay log, "
+                   "gtid_slave_pos may be inaccurate");
+      delete glev;
+    }
+    if (likely (rev || glev))
+    {
       rli->relay_log.harvest_bytes_written(&rli->log_space_total);
       if (flush_master_info(mi, TRUE, TRUE))
         sql_print_error("Failed to flush master info file");
-      delete ev;
     }
-    else
-      mi->report(ERROR_LEVEL, ER_SLAVE_CREATE_EVENT_FAILURE,
-                 ER(ER_SLAVE_CREATE_EVENT_FAILURE),
-                 "Rotate_event (out of memory?),"
-                 " SHOW SLAVE STATUS may be inaccurate");
   }
   else
     mysql_mutex_unlock(log_lock);
@@ -3097,6 +3129,12 @@ int apply_event_and_update_pos(Log_event
     rli->slave_skip_counter--;
   }
   mysql_mutex_unlock(&rli->data_lock);
+  DBUG_EXECUTE_IF("inject_slave_sql_before_apply_event",
+    {
+      DBUG_ASSERT(!debug_sync_set_action
+                  (thd, STRING_WITH_LEN("now WAIT_FOR continue")));
+      DBUG_SET_INITIAL("-d,inject_slave_sql_before_apply_event");
+    };);
   if (reason == Log_event::EVENT_SKIP_NOT)
     exec_res= ev->apply_event(rli);
 
@@ -4822,6 +4860,8 @@ static int queue_event(Master_info* mi,c
   ulong s_id;
   bool unlock_data_lock= TRUE;
   bool gtid_skip_enqueue= false;
+  bool got_gtid_event= false;
+  rpl_gtid event_gtid;
 
   /*
     FD_q must have been prepared for the first R_a event
@@ -5140,6 +5180,14 @@ static int queue_event(Master_info* mi,c
   {
     uchar dummy_flag;
 
+    if (Gtid_log_event::peek(buf, event_len, checksum_alg,
+                             &event_gtid.domain_id, &event_gtid.server_id,
+                             &event_gtid.seq_no, &dummy_flag))
+    {
+      error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+      goto err;
+    }
+    got_gtid_event= true;
     if (mi->using_gtid == Master_info::USE_GTID_NO)
       goto default_action;
     if (unlikely(!mi->gtid_event_seen))
@@ -5147,8 +5195,6 @@ static int queue_event(Master_info* mi,c
       mi->gtid_event_seen= true;
       if (mi->gtid_reconnect_event_skip_count)
       {
-        rpl_gtid gtid;
-
         /*
           If we are reconnecting, and we need to skip a partial event group
           already queued to the relay log before the reconnect, then we check
@@ -5157,21 +5203,14 @@ static int queue_event(Master_info* mi,c
 
           The only way we should be able to receive a different GTID than what
           we expect is if the binlog on the master (or more likely the whole
-          master server) was replaced with a different one, one the same IP
+          master server) was replaced with a different one, on the same IP
           address, _and_ the new master happens to have domains in a different
           order so we get the GTID from a different domain first. Still, it is
           best to protect against this case.
         */
-        if (Gtid_log_event::peek(buf, event_len, checksum_alg,
-                                 &gtid.domain_id, &gtid.server_id,
-                                 &gtid.seq_no, &dummy_flag))
-        {
-          error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
-          goto err;
-        }
-        if (gtid.domain_id != mi->last_queued_gtid.domain_id ||
-            gtid.server_id != mi->last_queued_gtid.server_id ||
-            gtid.seq_no != mi->last_queued_gtid.seq_no)
+        if (event_gtid.domain_id != mi->last_queued_gtid.domain_id ||
+            event_gtid.server_id != mi->last_queued_gtid.server_id ||
+            event_gtid.seq_no != mi->last_queued_gtid.seq_no)
         {
           bool first;
           error= ER_SLAVE_UNEXPECTED_MASTER_SWITCH;
@@ -5181,7 +5220,7 @@ static int queue_event(Master_info* mi,c
                                           &first);
           error_msg.append(STRING_WITH_LEN(", received: "));
           first= true;
-          rpl_slave_state_tostring_helper(&error_msg, &gtid, &first);
+          rpl_slave_state_tostring_helper(&error_msg, &event_gtid, &first);
           goto err;
         }
       }
@@ -5261,6 +5300,16 @@ static int queue_event(Master_info* mi,c
 
   mysql_mutex_lock(log_lock);
   s_id= uint4korr(buf + SERVER_ID_OFFSET);
+  /*
+    Write the event to the relay log, unless we reconnected in the middle
+    of an event group and now need to skip the initial part of the group that
+    we already wrote before reconnecting.
+  */
+  if (unlikely(gtid_skip_enqueue))
+  {
+    mi->master_log_pos+= inc_pos;
+  }
+  else
   if ((s_id == global_system_variables.server_id &&
        !mi->rli.replicate_same_server_id) ||
       /*
@@ -5303,6 +5352,8 @@ static int queue_event(Master_info* mi,c
       memcpy(rli->ign_master_log_name_end, mi->master_log_name, FN_REFLEN);
       DBUG_ASSERT(rli->ign_master_log_name_end[0]);
       rli->ign_master_log_pos_end= mi->master_log_pos;
+      if (got_gtid_event)
+        rli->ign_gtids.update(&event_gtid);
     }
     rli->relay_log.signal_update(); // the slave SQL thread needs to re-check
     DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored",
@@ -5310,16 +5361,7 @@ static int queue_event(Master_info* mi,c
   }
   else
   {
-    /*
-      Write the event to the relay log, unless we reconnected in the middle
-      of an event group and now need to skip the initial part of the group that
-      we already wrote before reconnecting.
-    */
-    if (unlikely(gtid_skip_enqueue))
-    {
-      mi->master_log_pos+= inc_pos;
-    }
-    else if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
+    if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
     {
       mi->master_log_pos+= inc_pos;
       DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
@@ -5330,6 +5372,8 @@ static int queue_event(Master_info* mi,c
       error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
     }
     rli->ign_master_log_name_end[0]= 0; // last event is not ignored
+    if (got_gtid_event)
+      rli->ign_gtids.remove_if_present(&event_gtid);
     if (save_buf != NULL)
       buf= save_buf;
   }
@@ -5932,6 +5976,25 @@ static Log_event* next_event(Relay_log_i
           DBUG_RETURN(ev);
         }
 
+        if (rli->ign_gtids.count())
+        {
+          /* We generate and return a Gtid_list, to update gtid_slave_pos. */
+          DBUG_PRINT("info",("seeing ignored end gtids"));
+          ev= new Gtid_list_log_event(&rli->ign_gtids,
+                                      Gtid_list_log_event::FLAG_IGN_GTIDS);
+          rli->ign_gtids.reset();
+          mysql_mutex_unlock(log_lock);
+          if (unlikely(!ev))
+          {
+            errmsg= "Slave SQL thread failed to create a Gtid_list event "
+              "(out of memory?), gtid_slave_pos may be inaccurate";
+            goto err;
+          }
+          ev->server_id= 0; // don't be ignored by slave SQL thread
+          ev->set_artificial_event(); // Don't mess up Exec_Master_Log_Pos
+          DBUG_RETURN(ev);
+        }
+
         /*
           We can, and should release data_lock while we are waiting for
           update. If we do not, show slave status will block



More information about the commits mailing list