List:Commits« Previous MessageNext Message »
From:andrei.elkin Date:April 28 2008 12:09pm
Subject:bk commit into 6.0 tree (aelkin:1.2634) BUG#25998
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of aelkin.  When aelkin does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-04-28 15:08:14+03:00, aelkin@mysql1000.(none) +9 -0
  Bug #25998 problems about circle replication
  Bug #27808 Infinite looping in circular replication
  
  In case of the circular multi-master replication after withdrawing one of the members events
  generated by the removed server could become unstoppable (bug#25998).
  That's because the originator had been a part of the event flow termination.
  Other possibility of the unstoppable event is the cluster replication (bug#27808).
  In that case no withdrawing is necessary at all.
  
  In order to fix both artifacts it is enough to introduce a new option for CHANGE MASTER.
  
  MASTER_IGNORE_SERVER_ID= some_server_id
  
  can be repeated multiple times to list all the servers from which events would not be put into
  relay log and therefore would not be executed.
  
  Fixed with implementing the feature.
  
  Properties of the feature:
  
   a. reporting an error if the id of an ignored server is the slave itself and
      its configuration on startup was with --replicate-same-server-id;
   b. overriding the old MASTER_IGNORE_SERVER_ID list by the following 
      CHANGE MASTER ... MASTER_IGNORE_SERVER_ID=;
   c. the old setup preserving by CHANGE MASTER w/o MASTER_IGNORE_SERVER_ID;
   d. resetting the ignored server ids with RESET SLAVE;
   e. implementing a new status variable 
      show status like "slave_replicate_ignore_server_id"
   f. Differently from --replicate-same-server-id handling, the sql thread is not
      concerned with the ignored server id, because it's supposed that
      the relay log constists only of events that can not be unstoppable.
      IO thread takes care of an unstoppable event can not penetrate
      into the relay log.
   g. Rotate and FD events originated by the current master listed
      in the ignored list are still relay-logged. Their termination remains to be
      a duty of the current master.

  sql/lex.h@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +1 -0
    new keyword

  sql/mysqld.cc@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +35 -1
    new status variable declaration and the display method

  sql/rpl_mi.cc@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +40 -4
    initialization, storing into master info, reading from the file, deallocation
    of the list of ignored server id:s.

  sql/rpl_mi.h@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +12 -1
    a new method answering filtering question

  sql/share/errmsg.txt@stripped, 2008-04-28 15:08:12+03:00, aelkin@mysql1000.(none) +2 -0
    a new error message about possible clashing of options.

  sql/slave.cc@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +101 -6
    a helper function to read an array of variable size of intergers.
    Refining io-thread's filtering condition to consult with the list of ignored servers.
    Note, that FD and Rotate events from an ignored server are still accepted.

  sql/sql_lex.h@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +1 -0
    parser time storage for variable size array of server ids

  sql/sql_repl.cc@stripped, 2008-04-28 15:08:11+03:00, aelkin@mysql1000.(none) +35 -13
    failing change master do not forget to free lex's dynamical storage with parsed
    ignored server_ids;
    resetting the old list of ignored server if the parser detected the new list;
    shifting some pieces of code in order to comply with the above logics to provide as less as possible
    changes.

  sql/sql_yacc.yy@stripped, 2008-04-28 15:08:12+03:00, aelkin@mysql1000.(none) +8 -0
    allocation a dyn array for possible list of ignored server ids;
    filling the array;

diff -Nrup a/sql/lex.h b/sql/lex.h
--- a/sql/lex.h	2008-04-01 13:56:38 +03:00
+++ b/sql/lex.h	2008-04-28 15:08:11 +03:00
@@ -321,6 +321,7 @@ static SYMBOL symbols[] = {
   { "MASTER_SSL_VERIFY_SERVER_CERT", SYM(MASTER_SSL_VERIFY_SERVER_CERT_SYM)},
   { "MASTER_USER",           SYM(MASTER_USER_SYM)},
   { "MASTER_HEARTBEAT_PERIOD", SYM(MASTER_HEARTBEAT_PERIOD_SYM)},
+  { "MASTER_IGNORE_SERVER_ID", SYM(MASTER_IGNORE_SERVER_ID_SYM)},
   { "MATCH",		SYM(MATCH)},
   { "MAX_CONNECTIONS_PER_HOUR", SYM(MAX_CONNECTIONS_PER_HOUR)},
   { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR)},
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2008-04-01 16:18:59 +03:00
+++ b/sql/mysqld.cc	2008-04-28 15:08:11 +03:00
@@ -7049,6 +7049,39 @@ static int show_heartbeat_period(THD *th
   return 0;
 }
 
+static int show_slave_ignore_server_id(THD *thd, SHOW_VAR *var, char *buff)
+{
+  pthread_mutex_lock(&LOCK_active_mi);
+  if (active_mi)
+  {
+    ulong i, cur_len, slen;
+    var->type= SHOW_CHAR;
+    var->value= buff;
+    for (i= 0, buff[0]= 0,cur_len= 0;
+         i < active_mi->ignore_server_ids.elements; i++,  cur_len=strlen(buff))
+    {
+      ulong s_id;
+      char sbuff[SHOW_VAR_FUNC_BUFF_SIZE];
+      get_dynamic(&active_mi->ignore_server_ids, (uchar*) &s_id, i);
+      my_sprintf(sbuff, (sbuff, (i==0? "%lu" : ", %lu"), s_id));
+      if (cur_len + (slen= strlen(sbuff)) + 4 > SHOW_VAR_FUNC_BUFF_SIZE)
+      {
+        /*
+          break the loop whenever remained space could not fit
+          ellipses on the next cycle
+        */
+        my_sprintf(buff + cur_len, (buff + cur_len, "..."));
+        break;
+      }
+      my_sprintf(buff + cur_len, (buff + cur_len, "%s", sbuff));
+    }
+  }
+  else
+    var->type= SHOW_UNDEF;
+  pthread_mutex_unlock(&LOCK_active_mi);
+  return 0;
+}
+
 
 #endif /* HAVE_REPLICATION */
 
@@ -7412,9 +7445,10 @@ SHOW_VAR status_vars[]= {
   {"Select_scan",	       (char*) offsetof(STATUS_VAR, select_scan_count), SHOW_LONG_STATUS},
   {"Slave_open_temp_tables",   (char*) &slave_open_temp_tables, SHOW_LONG},
 #ifdef HAVE_REPLICATION
-  {"Slave_retried_transactions",(char*) &show_slave_retried_trans, SHOW_FUNC},
+  {"Slave_replicate_ignore_server_id",   (char*) &show_slave_ignore_server_id, SHOW_FUNC},
   {"Slave_heartbeat_period",   (char*) &show_heartbeat_period, SHOW_FUNC},
   {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_FUNC},
+  {"Slave_retried_transactions",(char*) &show_slave_retried_trans, SHOW_FUNC},
   {"Slave_running",            (char*) &show_slave_running,     SHOW_FUNC},
 #endif
   {"Slow_launch_threads",      (char*) &slow_launch_threads,    SHOW_LONG},
diff -Nrup a/sql/rpl_mi.cc b/sql/rpl_mi.cc
--- a/sql/rpl_mi.cc	2008-03-15 00:21:24 +02:00
+++ b/sql/rpl_mi.cc	2008-04-28 15:08:11 +03:00
@@ -28,6 +28,7 @@ int init_intvar_from_file(int* var, IO_C
 int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
 			  const char *default_val);
 int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
+int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
 
 Master_info::Master_info()
   :Slave_reporting_capability("I/O"),
@@ -39,6 +40,7 @@ Master_info::Master_info()
   host[0] = 0; user[0] = 0; password[0] = 0;
   ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
   ssl_cipher[0]= 0; ssl_key[0]= 0;
+  my_init_dynamic_array(&ignore_server_ids, sizeof(::server_id), 16, 16);
 
   bzero((char*) &file, sizeof(file));
   pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
@@ -50,6 +52,7 @@ Master_info::Master_info()
 
 Master_info::~Master_info()
 {
+  delete_dynamic(&ignore_server_ids);
   pthread_mutex_destroy(&run_lock);
   pthread_mutex_destroy(&data_lock);
   pthread_cond_destroy(&data_cond);
@@ -57,7 +60,6 @@ Master_info::~Master_info()
   pthread_cond_destroy(&stop_cond);
 }
 
-
 void init_master_log_pos(Master_info* mi)
 {
   DBUG_ENTER("init_master_log_pos");
@@ -87,8 +89,11 @@ enum {
   /* 6.0 added value of master_heartbeat_period */
   LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16,
 
+  /* 6.0 added value of master_ignore_server_id */
+  LINE_FOR_MASTER_IGNORE_SERVER_ID= 17,
+
   /* Number of lines currently used when saving master info file */
-  LINES_IN_MASTER_INFO= LINE_FOR_MASTER_HEARTBEAT_PERIOD
+  LINES_IN_MASTER_INFO= LINE_FOR_MASTER_IGNORE_SERVER_ID
 };
 
 
@@ -280,6 +285,17 @@ file '%s')", fname);
       if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD &&
           init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0))
         goto errwithmsg;
+      /*
+        Starting from 6.0 list of server_id of ignorable servers might be
+        in the file
+      */
+      if (lines >= LINE_FOR_MASTER_IGNORE_SERVER_ID &&
+          init_dynarray_intvar_from_file(&mi->ignore_server_ids, &mi->file))
+      {
+        sql_print_error("Failed to initialize master info ignore_server_ids");
+        goto errwithmsg;
+      }
+
     }
 
 #ifndef HAVE_OPENSSL
@@ -379,16 +395,35 @@ int flush_master_info(Master_info* mi, b
   */
   char heartbeat_buf[sizeof(mi->heartbeat_period) * 4]; // buffer to suffice always
   my_sprintf(heartbeat_buf, (heartbeat_buf, "%.3f", mi->heartbeat_period));
+  /*
+    produce a line listing the total number and all the ignored server_id:s
+  */
+  char ignore_server_ids_buf[(sizeof(::server_id) * 3 + 1) *
+                             (1 + mi->ignore_server_ids.elements)];
+  {
+    my_sprintf(ignore_server_ids_buf,
+               (ignore_server_ids_buf, "%u", mi->ignore_server_ids.elements));
+    for (ulong i= 0; i < mi->ignore_server_ids.elements; i++)
+    {
+      ulong s_id;
+      ulong cur_len= strlen(ignore_server_ids_buf);
+      get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i);
+      my_sprintf(ignore_server_ids_buf + cur_len,
+                 (ignore_server_ids_buf + cur_len,
+                   " %lu", s_id));
+    }
+  }
   my_b_seek(file, 0L);
   my_b_printf(file,
-              "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n",
+              "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n",
               LINES_IN_MASTER_INFO,
               mi->master_log_name, llstr(mi->master_log_pos, lbuf),
               mi->host, mi->user,
               mi->password, mi->port, mi->connect_retry,
               (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
               mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert,
-              heartbeat_buf);
+              heartbeat_buf,
+              ignore_server_ids_buf);
   DBUG_RETURN(-flush_io_cache(file));
 }
 
@@ -399,6 +434,7 @@ void end_master_info(Master_info* mi)
 
   if (!mi->inited)
     DBUG_VOID_RETURN;
+  reset_dynamic(&mi->ignore_server_ids);
   end_relay_log_info(&mi->rli);
   if (mi->fd >= 0)
   {
diff -Nrup a/sql/rpl_mi.h b/sql/rpl_mi.h
--- a/sql/rpl_mi.h	2008-02-03 11:00:47 +02:00
+++ b/sql/rpl_mi.h	2008-04-28 15:08:11 +03:00
@@ -60,7 +60,17 @@ class Master_info : public Slave_reporti
  public:
   Master_info();
   ~Master_info();
-
+  bool repl_server_id_ignore_p(uint s_id)
+  {
+    for (uint i= 0; i < ignore_server_ids.elements; i++)
+    {
+      ulong id;
+      get_dynamic(&ignore_server_ids, (uchar*) &id, i);
+      if (id == s_id)
+        return TRUE;
+    }
+    return FALSE;
+  }
   /* the variables below are needed because we can change masters on the fly */
   char master_log_name[FN_REFLEN];
   char host[HOSTNAME_LENGTH+1];
@@ -85,6 +95,7 @@ class Master_info : public Slave_reporti
   uint connect_retry;
   float heartbeat_period;         // interface with CHANGE MASTER or master.info
   ulonglong received_heartbeats;  // counter of received heartbeat events
+  DYNAMIC_ARRAY ignore_server_ids;
 #ifndef DBUG_OFF
   int events_till_disconnect;
 #endif
diff -Nrup a/sql/share/errmsg.txt b/sql/share/errmsg.txt
--- a/sql/share/errmsg.txt	2008-04-14 19:58:40 +03:00
+++ b/sql/share/errmsg.txt	2008-04-28 15:08:12 +03:00
@@ -6252,3 +6252,5 @@ ER_SLAVE_HEARTBEAT_FAILURE
   eng "Unexpected master's heartbeat data: %s"
 ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
   eng "The requested value for the heartbeat period %s %s"
+ER_SLAVE_IGNORE_SERVER_ID
+  eng "The requested server id %d clashes with the slave startup option --replicate-same-server-id"
diff -Nrup a/sql/slave.cc b/sql/slave.cc
--- a/sql/slave.cc	2008-04-01 13:56:42 +03:00
+++ b/sql/slave.cc	2008-04-28 15:08:11 +03:00
@@ -759,6 +759,97 @@ int init_floatvar_from_file(float* var, 
   DBUG_RETURN(1);
 }
 
+/**
+   A master info read method
+
+   This function is called from @c init_master_info() @c along with
+   relatives to restore some of @c active_mi @c members.
+   Particularly, this function is responsible for restoring
+   MASTER_IGNORE_SERVER_ID list of servers whose events the slave is
+   going to ignore (to not log them in the relay log).
+   Items being read are supposed to be decimal output of values of a
+   type shorter or equal of @c long @c, except for the number of the
+   items that is of @c uint @c, and separated by the single space.
+
+   @param arr
+          @c DYNAMIC_ARRAY @c pointer to storage for servers id
+   @param f
+          @c IO_CACHE @c pointer to the source file
+
+   @retval 0           All OK
+   @retval non-zero    An error
+*/
+
+int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f)
+{
+  int ret= 0;
+  char buf[16 * (sizeof(long)*4 + 1)]; // static buffer to use most of times
+  char *buf_act= buf; // actual buffer can be dynamic if static is short
+  char *token;
+  uint num_items;     // number of items of `arr'
+  size_t read_size;
+  DBUG_ENTER("init_dynarray_intvar_from_file");
+
+  if ((read_size= my_b_gets(f, buf_act, sizeof(buf))) == 0)
+  {
+    return 0; // no line in master.info
+  }
+  if (read_size + 1 == sizeof(buf) && buf[sizeof(buf) - 2] != '\n')
+  {
+    /*
+      short read happpend; allocate sufficient memory and make the 2nd read
+    */
+    char buf_work[(sizeof(long)*3 + 1)*16];
+    memcpy(buf_work, buf, sizeof(buf_work));
+    num_items= atoi(strtok(buf_work, " "));
+    size_t snd_size;
+    /*
+      max size lower bound approximate estimation bases on the formula:
+      (the items number + items themselves) * 
+          (decimal size + space) - 1 + `\n' + '\0'
+    */
+    size_t max_size= (1 + num_items) * (sizeof(long)*3 + 1) + 1;
+    buf_act= (char*) my_malloc(max_size, MYF(MY_WME));
+    memcpy(buf_act, buf, read_size);
+    snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size);
+    if (snd_size == 0 ||
+        (snd_size + 1 == max_size - read_size) &&  buf[max_size - 2] != '\n')
+    {
+      /*
+        failure to make the 2nd read or short read again
+      */
+      ret= 1;
+      goto err;
+    }
+  }
+  token= strtok(buf_act, " ");
+  if (token == NULL)
+  {
+    ret= 1;
+    goto err;
+  }
+  num_items= atoi(token);
+  for (uint i=0; i < num_items; i++)
+  {
+    token= strtok(NULL, " ");
+    if (token == NULL)
+    {
+      ret= 1;
+      goto err;
+    }
+    else
+    {
+      ulong val= atol(token);
+      insert_dynamic(arr, (uchar *) &val);
+    }
+  }
+err:
+  if (buf_act != buf)
+    my_free(buf_act, MYF(0));
+  DBUG_RETURN(ret);
+}
+
+
 static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info)
 {
   if (io_slave_killed(thd, mi))
@@ -3069,6 +3160,7 @@ static int queue_event(Master_info* mi,c
   ulong inc_pos;
   Relay_log_info *rli= &mi->rli;
   pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
+  ulong s_id;
   DBUG_ENTER("queue_event");
 
   LINT_INIT(inc_pos);
@@ -3215,9 +3307,11 @@ static int queue_event(Master_info* mi,c
   */
 
   pthread_mutex_lock(log_lock);
-
-  if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
-      !mi->rli.replicate_same_server_id)
+  s_id= uint4korr(buf + SERVER_ID_OFFSET);
+  if ((s_id == ::server_id && !mi->rli.replicate_same_server_id) ||
+      (mi->repl_server_id_ignore_p(s_id) &&
+       buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT &&
+       buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT))
   {
     /*
       Do not write it to the relay log.
@@ -3233,7 +3327,8 @@ static int queue_event(Master_info* mi,c
       the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment
       mi->master_log_pos.
     */
-    if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
+    if (!(s_id == ::server_id && !mi->rli.replicate_same_server_id) ||
+        buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
         buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT &&
         buf[EVENT_TYPE_OFFSET]!=STOP_EVENT)
     {
@@ -3243,8 +3338,8 @@ static int queue_event(Master_info* mi,c
       rli->ign_master_log_pos_end= mi->master_log_pos;
     }
     rli->relay_log.signal_update(); // the slave SQL thread needs to re-check
-    DBUG_PRINT("info", ("master_log_pos: %lu, event originating from the same server, ignored",
-                        (ulong) mi->master_log_pos));
+    DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored",
+                        (ulong) mi->master_log_pos, uint4korr(buf + SERVER_ID_OFFSET)));
   }
   else
   {
diff -Nrup a/sql/sql_lex.h b/sql/sql_lex.h
--- a/sql/sql_lex.h	2008-04-01 13:56:44 +03:00
+++ b/sql/sql_lex.h	2008-04-28 15:08:11 +03:00
@@ -211,6 +211,7 @@ typedef struct st_lex_master_info
   char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher;
   char *relay_log_name;
   ulong relay_log_pos;
+  DYNAMIC_ARRAY repl_ignore_server_ids; 
 } LEX_MASTER_INFO;
 
 
diff -Nrup a/sql/sql_repl.cc b/sql/sql_repl.cc
--- a/sql/sql_repl.cc	2008-03-08 12:14:45 +02:00
+++ b/sql/sql_repl.cc	2008-04-28 15:08:11 +03:00
@@ -1195,26 +1195,27 @@ bool change_master(THD* thd, Master_info
   int thread_mask;
   const char* errmsg= 0;
   bool need_relay_log_purge= 1;
+  bool ret= FALSE;
   DBUG_ENTER("change_master");
 
   lock_slave_threads(mi);
   init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
+  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
   if (thread_mask) // We refuse if any slave thread is running
   {
     my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
-    unlock_slave_threads(mi);
-    DBUG_RETURN(TRUE);
+    ret= TRUE;
+    goto err;
   }
 
   thd_proc_info(thd, "Changing master");
-  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
   // TODO: see if needs re-write
   if (init_master_info(mi, master_info_file, relay_log_info_file, 0,
 		       thread_mask))
   {
     my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
-    unlock_slave_threads(mi);
-    DBUG_RETURN(TRUE);
+    ret= TRUE;
+    goto err;
   }
 
   /*
@@ -1259,6 +1260,25 @@ bool change_master(THD* thd, Master_info
     mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD,
                                       (slave_net_timeout/2.0));
   mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd
+  /*
+    reset the last time server_id list if the current CHANGE MASTER 
+    is mentioning MASTER_IGNORE_SERVER_ID
+  */
+  if (lex_mi->repl_ignore_server_ids.elements > 0)
+    reset_dynamic(&mi->ignore_server_ids);
+  for (uint i= 0; i < lex_mi->repl_ignore_server_ids.elements; i++)
+  {
+    ulong s_id;
+    get_dynamic(&lex_mi->repl_ignore_server_ids, (uchar*) &s_id, i);
+    if (s_id == ::server_id && replicate_same_server_id)
+    {
+      my_error(ER_SLAVE_IGNORE_SERVER_ID, MYF(0), s_id);
+      ret= TRUE;
+      goto err;
+    }
+    else
+      insert_dynamic(&mi->ignore_server_ids, (uchar*) &s_id);
+  }
   if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
     mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
 
@@ -1336,8 +1356,8 @@ bool change_master(THD* thd, Master_info
   if (flush_master_info(mi, 0))
   {
     my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file");
-    unlock_slave_threads(mi);
-    DBUG_RETURN(TRUE);
+    ret= TRUE;
+    goto err;
   }
   if (need_relay_log_purge)
   {
@@ -1348,8 +1368,8 @@ bool change_master(THD* thd, Master_info
 			 &errmsg))
     {
       my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
-      unlock_slave_threads(mi);
-      DBUG_RETURN(TRUE);
+      ret= TRUE;
+      goto err;
     }
   }
   else
@@ -1364,8 +1384,8 @@ bool change_master(THD* thd, Master_info
 			   &msg, 0))
     {
       my_error(ER_RELAY_LOG_INIT, MYF(0), msg);
-      unlock_slave_threads(mi);
-      DBUG_RETURN(TRUE);
+      ret= TRUE;
+      goto err;
     }
   }
   /*
@@ -1402,10 +1422,12 @@ bool change_master(THD* thd, Master_info
   pthread_cond_broadcast(&mi->data_cond);
   pthread_mutex_unlock(&mi->rli.data_lock);
 
-  unlock_slave_threads(mi);
   thd_proc_info(thd, 0);
   my_ok(thd);
-  DBUG_RETURN(FALSE);
+err:
+  unlock_slave_threads(mi);
+  delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time alloc
+  DBUG_RETURN(ret);
 }
 
 int reset_master(THD* thd)
diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy	2008-04-01 16:19:00 +03:00
+++ b/sql/sql_yacc.yy	2008-04-28 15:08:12 +03:00
@@ -892,6 +892,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  MASTER_SYM
 %token  MASTER_USER_SYM
 %token  MASTER_HEARTBEAT_PERIOD_SYM
+%token  MASTER_IGNORE_SERVER_ID_SYM
 %token  MATCH                         /* SQL-2003-R */
 %token  MAX_CONNECTIONS_PER_HOUR
 %token  MAX_QUERIES_PER_HOUR
@@ -1636,6 +1637,9 @@ change:
             LEX *lex = Lex;
             lex->sql_command = SQLCOM_CHANGE_MASTER;
             bzero((char*) &lex->mi, sizeof(lex->mi));
+            lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_UNCHANGED;
+            my_init_dynamic_array(&Lex->mi.repl_ignore_server_ids,
+                                  sizeof(::server_id), 16, 16);
           }
           master_defs
           {}
@@ -1735,6 +1739,10 @@ master_def:
               Lex->mi.heartbeat_opt=  LEX_MASTER_INFO::LEX_MI_DISABLE;
             }
             Lex->mi.heartbeat_opt=  LEX_MASTER_INFO::LEX_MI_ENABLE;
+          }
+        | MASTER_IGNORE_SERVER_ID_SYM EQ ulong_num
+          {
+            insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($3));
           }
         |
         master_file_def
Thread
bk commit into 6.0 tree (aelkin:1.2634) BUG#25998andrei.elkin28 Apr