MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:March 3 2009 7:30am
Subject:bzr commit into mysql-6.0-rpl branch (alfranio.correia:2819)
View as plain text  
#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/wl-2775/mysql-6.0-rpl/ based on revid:alfranio.correia@stripped

 2819 Alfranio Correia	2009-03-03
      Refactored master information.
added:
  sql/rpl_mi_file.cc
  sql/rpl_mi_file.h
modified:
  sql/Makefile.am
  sql/rpl_mi.cc
  sql/rpl_mi.h
  sql/slave.cc
  sql/slave.h
  sql/sql_repl.cc

=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am	2009-03-02 21:53:42 +0000
+++ b/sql/Makefile.am	2009-03-03 07:29:54 +0000
@@ -83,7 +83,7 @@ noinst_HEADERS =	item.h item_func.h item
 			ha_partition.h rpl_constants.h \
 			opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \
 			rpl_reporting.h \
-			log.h sql_show.h rpl_rli.h rpl_rli_file.h rpl_mi.h \
+			log.h sql_show.h rpl_rli.h rpl_rli_file.h rpl_mi.h rpl_mi_file.h \
 			sql_select.h structs.h table.h sql_udf.h hash_filo.h \
 			lex.h lex_symbol.h sql_acl.h sql_crypt.h  \
 			sql_repl.h slave.h rpl_filter.h rpl_injector.h \
@@ -134,7 +134,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
 			sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
 			slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \
-			rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_rli_file.cc rpl_mi.cc \
+			rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_rli_file.cc rpl_mi.cc rpl_mi_file.cc \
 			rpl_reporting.cc \
                         sql_union.cc sql_derived.cc \
 			sql_client.cc \

=== modified file 'sql/rpl_mi.cc'
--- a/sql/rpl_mi.cc	2009-03-02 21:53:42 +0000
+++ b/sql/rpl_mi.cc	2009-03-03 07:29:54 +0000
@@ -21,49 +21,19 @@
 
 #ifdef HAVE_REPLICATION
 
-#define DEFAULT_CONNECT_RETRY 60
-
-// Defined in slave.cc
-int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
-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);
-
-int init_master_file_info(Master_info *mi, 
-                          const char* master_info_fname,
-                          bool abort_if_no_master_info_file,
-                          int thread_mask);
-void close_master_file_info(Master_info *mi);
-int flush_master_file_info(Master_info *mi, bool flush_relay_log_cache);
-int reset_master_file_info(Master_info *mi);
-char static *master_file = 0;
-
-
 Master_info::Master_info(Relay_log_info *param_rli)
   :Slave_reporting_capability("I/O"),
-   ssl(0), ssl_verify_server_cert(0), fd(-1),  io_thd(0), 
+   ssl(0), ssl_verify_server_cert(0), io_thd(0), 
    rli(param_rli), port(MYSQL_PORT),
    connect_retry(DEFAULT_CONNECT_RETRY), heartbeat_period(0),
    received_heartbeats(0), inited(0), master_id(0),
-   abort_slave(0), slave_running(0), slave_run_id(0),
-   sync_counter(0)
+   abort_slave(0), slave_running(0), slave_run_id(0)
 {
-   create_master_info= (transact_replication ? init_master_file_info :\
-                      init_master_file_info),
-   save_master_info= (transact_replication ? flush_master_file_info :\
-                      flush_master_file_info),
-   close_master_info= (transact_replication ? close_master_file_info :\
-                       close_master_file_info);
-   erase_master_info= (transact_replication ? reset_master_file_info :\
-                       reset_master_file_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));
   /*
     We have to use MYF_NO_DEADLOCK_DETECTION because mysqld doesn't
     lock run_lock and data_lock consistently.
@@ -153,401 +123,4 @@ void init_master_log_pos(Master_info* mi
   DBUG_VOID_RETURN;
 }
 
-
-enum {
-  LINES_IN_MASTER_INFO_WITH_SSL= 14,
-
-  /* 5.1.16 added value of master_ssl_verify_server_cert */
-  LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
-
-  /* 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_REPLICATE_IGNORE_SERVER_IDS= 17,
-
-  /* Number of lines currently used when saving master info file */
-  LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS
-};
-
-
-int init_master_file_info(Master_info* mi, 
-                     const char* master_info_fname,
-                     bool abort_if_no_master_info_file,
-                     int thread_mask)
-{
-  int fd,error;
-  char fname[FN_REFLEN+128];
-  DBUG_ENTER("init_master_file_info");
-
-  if (mi->inited)
-  {
-    /*
-      We have to reset read position of relay-log-bin as we may have
-      already been reading from 'hotlog' when the slave was stopped
-      last time. If this case pos_in_file would be set and we would
-      get a crash when trying to read the signature for the binary
-      relay log.
-
-      We only rewind the read position if we are starting the SQL
-      thread. The handle_slave_sql thread assumes that the read
-      position is at the beginning of the file, and will read the
-      "signature" and then fast-forward to the last position read.
-    */
-    if (thread_mask & SLAVE_SQL)
-    {
-      my_b_seek(mi->rli->cur_log, (my_off_t) 0);
-    }
-    DBUG_RETURN(0);
-  }
-
-  mi->mysql=0;
-  mi->file_id=1;
-  fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
-  master_file = (char *) master_info_fname;
-
-  /*
-    We need a mutex while we are changing master info parameters to
-    keep other threads from reading bogus info
-  */
-
-  pthread_mutex_lock(&mi->data_lock);
-  fd = mi->fd;
-
-  /* does master.info exist ? */
-
-  if (access(fname,F_OK))
-  {
-    if (abort_if_no_master_info_file)
-    {
-      pthread_mutex_unlock(&mi->data_lock);
-      DBUG_RETURN(0);
-    }
-    /*
-      if someone removed the file from underneath our feet, just close
-      the old descriptor and re-create the old file
-    */
-    if (fd >= 0)
-      my_close(fd, MYF(MY_WME));
-    if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
-    {
-      sql_print_error("Failed to create a new master info file (\
-file '%s', errno %d)", fname, my_errno);
-      goto err;
-    }
-    if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0,
-                      MYF(MY_WME)))
-    {
-      sql_print_error("Failed to create a cache on master info file (\
-file '%s')", fname);
-      goto err;
-    }
-
-    mi->fd = fd;
-    init_master_log_pos(mi);
-
-  }
-  else // file exists
-  {
-    if (fd >= 0)
-      reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
-    else
-    {
-      if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
-      {
-        sql_print_error("Failed to open the existing master info file (\
-file '%s', errno %d)", fname, my_errno);
-        goto err;
-      }
-      if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,
-                        0, MYF(MY_WME)))
-      {
-        sql_print_error("Failed to create a cache on master info file (\
-file '%s')", fname);
-        goto err;
-      }
-    }
-
-    mi->fd = fd;
-    int port, connect_retry, master_log_pos, lines;
-    int ssl= 0, ssl_verify_server_cert= 0;
-    float master_heartbeat_period= 0.0;
-    char *first_non_digit;
-
-    /*
-       Starting from 4.1.x master.info has new format. Now its
-       first line contains number of lines in file. By reading this
-       number we will be always distinguish to which version our
-       master.info corresponds to. We can't simply count lines in
-       file since versions before 4.1.x could generate files with more
-       lines than needed.
-       If first line doesn't contain a number or contain number less than
-       LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
-       from pre 4.1.1 version.
-       There is no ambiguity when reading an old master.info, as before
-       4.1.1, the first line contained the binlog's name, which is either
-       empty or has an extension (contains a '.'), so can't be confused
-       with an integer.
-
-       So we're just reading first line and trying to figure which version
-       is this.
-    */
-
-    /*
-       The first row is temporarily stored in mi->master_log_name,
-       if it is line count and not binlog name (new format) it will be
-       overwritten by the second row later.
-    */
-    if (init_strvar_from_file(mi->master_log_name,
-                              sizeof(mi->master_log_name), &mi->file,
-                              ""))
-      goto errwithmsg;
-
-    lines= strtoul(mi->master_log_name, &first_non_digit, 10);
-
-    if (mi->master_log_name[0]!='\0' &&
-        *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
-    {
-      /* Seems to be new format => read master log name from next line */
-      if (init_strvar_from_file(mi->master_log_name,
-            sizeof(mi->master_log_name), &mi->file, ""))
-        goto errwithmsg;
-    }
-    else
-      lines= 7;
-
-    if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
-        init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, 0) ||
-        init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, "test") ||
-        init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
-                              &mi->file, 0 ) ||
-        init_intvar_from_file(&port, &mi->file, MYSQL_PORT) ||
-        init_intvar_from_file(&connect_retry, &mi->file, DEFAULT_CONNECT_RETRY))
-      goto errwithmsg;
-
-    /*
-      If file has ssl part use it even if we have server without
-      SSL support. But these option will be ignored later when
-      slave will try connect to master, so in this case warning
-      is printed.
-    */
-    if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
-    {
-      if (init_intvar_from_file(&ssl, &mi->file, 0) ||
-          init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
-                                &mi->file, 0) ||
-          init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
-                                &mi->file, 0) ||
-          init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
-                                &mi->file, 0) ||
-          init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
-                                &mi->file, 0) ||
-          init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
-                               &mi->file, 0))
-      goto errwithmsg;
-
-      /*
-        Starting from 5.1.16 ssl_verify_server_cert might be
-        in the file
-      */
-      if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT &&
-          init_intvar_from_file(&ssl_verify_server_cert, &mi->file, 0))
-        goto errwithmsg;
-      /*
-        Starting from 6.0 master_heartbeat_period might be
-        in the file
-      */
-      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_REPLICATE_IGNORE_SERVER_IDS &&
-          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
-    if (ssl)
-      sql_print_warning("SSL information in the master info file "
-                      "('%s') are ignored because this MySQL slave was "
-                      "compiled without SSL support.", fname);
-#endif /* HAVE_OPENSSL */
-
-    /*
-      This has to be handled here as init_intvar_from_file can't handle
-      my_off_t types
-    */
-    mi->master_log_pos= (my_off_t) master_log_pos;
-    mi->port= (uint) port;
-    mi->connect_retry= (uint) connect_retry;
-    mi->ssl= (my_bool) ssl;
-    mi->ssl_verify_server_cert= ssl_verify_server_cert;
-    mi->heartbeat_period= master_heartbeat_period;
-  }
-  DBUG_PRINT("master_info",("log_file_name: %s  position: %ld",
-                            mi->master_log_name,
-                            (ulong) mi->master_log_pos));
-
-  mi->rli->mi = mi;
-  if (mi->rli->init_relay_log_info())
-    goto err;
-
-  mi->inited = 1;
-  // now change cache READ -> WRITE - must do this before flush_master_info
-  reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1);
-  if ((error=test(mi->flush_master_info(1))))
-    sql_print_error("Failed to flush master info file");
-  pthread_mutex_unlock(&mi->data_lock);
-  DBUG_RETURN(error);
-
-errwithmsg:
-  sql_print_error("Error reading master configuration");
-
-err:
-  if (fd >= 0)
-  {
-    my_close(fd, MYF(0));
-    end_io_cache(&mi->file);
-  }
-  mi->fd= -1;
-  pthread_mutex_unlock(&mi->data_lock);
-  DBUG_RETURN(1);
-}
-
-
-/*
-  RETURN
-     2 - flush relay log failed
-     1 - flush master info failed
-     0 - all ok
-*/
-int flush_master_file_info(Master_info* mi, bool flush_relay_log_cache)
-{
-  IO_CACHE* file = &mi->file;
-  char lbuf[22];
-  int err= 0;
-
-  DBUG_ENTER("flush_master_file_info");
-  DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));
-
-  /*
-    Flush the relay log to disk. If we don't do it, then the relay log while
-    have some part (its last kilobytes) in memory only, so if the slave server
-    dies now, with, say, from master's position 100 to 150 in memory only (not
-    on disk), and with position 150 in master.info, then when the slave
-    restarts, the I/O thread will fetch binlogs from 150, so in the relay log
-    we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
-    SQL thread will jump from 100 to 150, and replication will silently break.
-
-    When we come to this place in code, relay log may or not be initialized;
-    the caller is responsible for setting 'flush_relay_log_cache' accordingly.
-  */
-  if (flush_relay_log_cache)
-  {
-    IO_CACHE *log_file= mi->rli->relay_log.get_log_file();
-    if (flush_io_cache(log_file))
-      DBUG_RETURN(2);
-  }
-
-  /*
-    We flushed the relay log BEFORE the master.info file, because if we crash
-    now, we will get a duplicate event in the relay log at restart. If we
-    flushed in the other order, we would get a hole in the relay log.
-    And duplicate is better than hole (with a duplicate, in later versions we
-    can add detection and scrap one event; with a hole there's nothing we can
-    do).
-  */
-
-  /*
-     In certain cases this code may create master.info files that seems
-     corrupted, because of extra lines filled with garbage in the end
-     file (this happens if new contents take less space than previous
-     contents of file). But because of number of lines in the first line
-     of file we don't care about this garbage.
-  */
-  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;
-  {
-    ignore_server_ids_buf=
-      (char *) my_malloc((sizeof(::server_id) * 3 + 1) *
-                         (1 + mi->ignore_server_ids.elements), MYF(MY_WME));
-    if (!ignore_server_ids_buf)
-      DBUG_RETURN(1);
-    for (ulong i= 0, cur_len= my_sprintf(ignore_server_ids_buf,
-                                         (ignore_server_ids_buf, "%u",
-                                          mi->ignore_server_ids.elements));
-         i < mi->ignore_server_ids.elements; i++)
-    {
-      ulong s_id;
-      get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i);
-      cur_len +=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%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,
-              ignore_server_ids_buf);
-  my_free(ignore_server_ids_buf, MYF(0));
-  err= flush_io_cache(file);
-  if (sync_masterinfo_period && !err && 
-      ++(mi->sync_counter) >= sync_masterinfo_period)
-  {
-    err= my_sync(mi->fd, MYF(MY_WME));
-    mi->sync_counter= 0;
-  }
-  DBUG_RETURN(-err);
-}
-
-void close_master_file_info(Master_info* mi)
-{
-  DBUG_ENTER("end_master_file_info");
-
-  if (!mi->inited)
-    DBUG_VOID_RETURN;
-  mi->rli->end_relay_log_info();
-  if (mi->fd >= 0)
-  {
-    end_io_cache(&mi->file);
-    (void)my_close(mi->fd, MYF(MY_WME));
-    mi->fd = -1;
-  }
-  mi->inited = 0;
-
-  DBUG_VOID_RETURN;
-}
-
-int reset_master_file_info(Master_info* mi) 
-{
-  MY_STAT stat_area;
-  char fname[FN_REFLEN];
-  int error= 0;
-
-  fn_format(fname, master_file, mysql_data_home, "", 4+32);
-  if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
-    error= 1;
-
-  return (error);
-}
-
-
 #endif /* HAVE_REPLICATION */

=== modified file 'sql/rpl_mi.h'
--- a/sql/rpl_mi.h	2009-03-02 21:53:42 +0000
+++ b/sql/rpl_mi.h	2009-03-03 07:29:54 +0000
@@ -22,6 +22,7 @@
 #include "rpl_reporting.h"
 #include "my_sys.h"
 
+#define DEFAULT_CONNECT_RETRY 60
 
 /*****************************************************************************
 
@@ -60,16 +61,9 @@ class Master_info : public Slave_reporti
 {
  public:
   Master_info(Relay_log_info *rli);
-  ~Master_info();
+  virtual ~Master_info();
   bool shall_ignore_server_id(ulong s_id);
 
-  int (*create_master_info)(Master_info *mi, const char* master_info_fname,
-		          bool abort_if_no_master_info_file,
-		          int thread_mask);
-  void (*close_master_info)(Master_info *mi);
-  int (*save_master_info)(Master_info *mi, bool flush_relay_log_cache);
-  int (*erase_master_info)(Master_info *mi);
-
   /* the variables below are needed because we can change masters on the fly */
   char master_log_name[FN_REFLEN];
   char host[HOSTNAME_LENGTH+1];
@@ -81,8 +75,6 @@ class Master_info : public Slave_reporti
   my_bool ssl_verify_server_cert;
 
   my_off_t master_log_pos;
-  File fd; // we keep the file open, so we need to remember the file pointer
-  IO_CACHE file;
 
   pthread_mutex_t data_lock,run_lock;
   pthread_cond_t data_cond,start_cond,stop_cond;
@@ -114,36 +106,34 @@ class Master_info : public Slave_reporti
   */
   long clock_diff_with_master;
 
-  /*
-   * Keeps track of the number of events before fsyncing.
-   * The option --sync-master-info determines how many
-   * events should happen before fsyncing.
-   */
-  uint sync_counter;
-
-  int init_master_info(const char* master_info_fname,
-		       bool abort_if_no_master_info_file,
+  int init_master_info(bool abort_if_no_master_info_file,
 		       int thread_mask)
   {
-     return (*create_master_info)(this, master_info_fname,
-		                abort_if_no_master_info_file,
+     return create_master_info(abort_if_no_master_info_file,
 		                thread_mask);
   }
 
   void end_master_info()
   {
-    (*close_master_info)(this);
+    close_master_info();
   }
 
   int flush_master_info(bool flush_relay_log_cache)
   {
-     return (*save_master_info)(this, flush_relay_log_cache);
+     return save_master_info(flush_relay_log_cache);
   }
 
   int reset_master_info()
   {
-     return (*erase_master_info)(this);
+     return erase_master_info();
   }
+
+  virtual int create_master_info (bool abort_if_no_master_info_file,
+		          int thread_mask) { return (-1); };
+  virtual void close_master_info() {};
+  virtual int save_master_info (bool flush_relay_log_cache) {return (-1); };
+  virtual int erase_master_info() { return (-1); };
+
 };
 
 void init_master_log_pos(Master_info* mi);

=== added file 'sql/rpl_mi_file.cc'
--- a/sql/rpl_mi_file.cc	1970-01-01 00:00:00 +0000
+++ b/sql/rpl_mi_file.cc	2009-03-03 07:29:54 +0000
@@ -0,0 +1,432 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <my_global.h> // For HAVE_REPLICATION
+#include "mysql_priv.h"
+#include <my_dir.h>
+
+#include <rpl_mi_file.h>
+
+#ifdef HAVE_REPLICATION
+
+// Defined in slave.cc
+int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
+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);
+
+enum {
+  LINES_IN_MASTER_INFO_WITH_SSL= 14,
+
+  /* 5.1.16 added value of master_ssl_verify_server_cert */
+  LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
+
+  /* 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_REPLICATE_IGNORE_SERVER_IDS= 17,
+
+  /* Number of lines currently used when saving master info file */
+  LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS
+};
+
+Master_file_info::Master_file_info(Relay_log_info *param_rli, 
+                                   const char* param_info_fname)
+  :Master_info(param_rli),
+  info_fname(param_info_fname), info_fd(-1),
+  sync_counter(0)
+{
+  DBUG_ENTER("Master_file_info::Master_file_info");
+
+  bzero((char*) &info_file, sizeof(info_file));
+
+  DBUG_VOID_RETURN;
+}
+
+int Master_file_info::create_master_info(bool abort_if_no_master_info_file,
+                                         int thread_mask)
+{
+  int error;
+  char fname[FN_REFLEN+128];
+  DBUG_ENTER("Master_file_info::create_master_info");
+
+  if (inited)
+  {
+    /*
+      We have to reset read position of relay-log-bin as we may have
+      already been reading from 'hotlog' when the slave was stopped
+      last time. If this case pos_in_file would be set and we would
+      get a crash when trying to read the signature for the binary
+      relay log.
+
+      We only rewind the read position if we are starting the SQL
+      thread. The handle_slave_sql thread assumes that the read
+      position is at the beginning of the file, and will read the
+      "signature" and then fast-forward to the last position read.
+    */
+    if (thread_mask & SLAVE_SQL)
+    {
+      my_b_seek(rli->cur_log, (my_off_t) 0);
+    }
+    DBUG_RETURN(0);
+  }
+
+  mysql= 0;
+  file_id= 1;
+  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
+
+  /*
+    We need a mutex while we are changing master info parameters to
+    keep other threads from reading bogus info
+  */
+
+  pthread_mutex_lock(&data_lock);
+
+  /* does master.info exist ? */
+
+  if (access(fname,F_OK))
+  {
+    if (abort_if_no_master_info_file)
+    {
+      pthread_mutex_unlock(&data_lock);
+      DBUG_RETURN(0);
+    }
+    /*
+      if someone removed the file from underneath our feet, just close
+      the old descriptor and re-create the old file
+    */
+    if (info_fd >= 0)
+      my_close(info_fd, MYF(MY_WME));
+    if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+    {
+      sql_print_error("Failed to create a new master info file (\
+file '%s', errno %d)", fname, my_errno);
+      goto err;
+    }
+    if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
+                      MYF(MY_WME)))
+    {
+      sql_print_error("Failed to create a cache on master info file (\
+file '%s')", fname);
+      goto err;
+    }
+
+    init_master_log_pos(this);
+  }
+  else // file exists
+  {
+    if (info_fd >= 0)
+      reinit_io_cache(&info_file, READ_CACHE, 0L,0,0);
+    else
+    {
+      if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+      {
+        sql_print_error("Failed to open the existing master info file (\
+file '%s', errno %d)", fname, my_errno);
+        goto err;
+      }
+      if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,
+                        0, MYF(MY_WME)))
+      {
+        sql_print_error("Failed to create a cache on master info file (\
+file '%s')", fname);
+        goto err;
+      }
+    }
+
+    int var_port, var_connect_retry, var_master_log_pos, lines;
+    int var_ssl= 0, var_ssl_verify_server_cert= 0;
+    float var_master_heartbeat_period= 0.0;
+    char *first_non_digit;
+
+    /*
+       Starting from 4.1.x master.info has new format. Now its
+       first line contains number of lines in file. By reading this
+       number we will be always distinguish to which version our
+       master.info corresponds to. We can't simply count lines in
+       file since versions before 4.1.x could generate files with more
+       lines than needed.
+       If first line doesn't contain a number or contain number less than
+       LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
+       from pre 4.1.1 version.
+       There is no ambiguity when reading an old master.info, as before
+       4.1.1, the first line contained the binlog's name, which is either
+       empty or has an extension (contains a '.'), so can't be confused
+       with an integer.
+
+       So we're just reading first line and trying to figure which version
+       is this.
+    */
+
+    /*
+       The first row is temporarily stored in master_log_name,
+       if it is line count and not binlog name (new format) it will be
+       overwritten by the second row later.
+    */
+    if (init_strvar_from_file(master_log_name,
+                              sizeof(master_log_name), &info_file,
+                              ""))
+      goto errwithmsg;
+
+    lines= strtoul(master_log_name, &first_non_digit, 10);
+
+    if (master_log_name[0]!='\0' &&
+        *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
+    {
+      /* Seems to be new format => read master log name from next line */
+      if (init_strvar_from_file(master_log_name,
+            sizeof(master_log_name), &info_file, ""))
+        goto errwithmsg;
+    }
+    else
+      lines= 7;
+
+    if (init_intvar_from_file(&var_master_log_pos, &info_file, 4) ||
+        init_strvar_from_file(host, sizeof(host), &info_file, 0) ||
+        init_strvar_from_file(user, sizeof(user), &info_file, "test") ||
+        init_strvar_from_file(password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
+                              &info_file, 0 ) ||
+        init_intvar_from_file(&var_port, &info_file, MYSQL_PORT) ||
+        init_intvar_from_file(&var_connect_retry, &info_file, DEFAULT_CONNECT_RETRY))
+      goto errwithmsg;
+
+    /*
+      If file has ssl part use it even if we have server without
+      SSL support. But these option will be ignored later when
+      slave will try connect to master, so in this case warning
+      is printed.
+    */
+    if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
+    {
+      if (init_intvar_from_file(&var_ssl, &info_file, 0) ||
+          init_strvar_from_file(ssl_ca, sizeof(ssl_ca),
+                                &info_file, 0) ||
+          init_strvar_from_file(ssl_capath, sizeof(ssl_capath),
+                                &info_file, 0) ||
+          init_strvar_from_file(ssl_cert, sizeof(ssl_cert),
+                                &info_file, 0) ||
+          init_strvar_from_file(ssl_cipher, sizeof(ssl_cipher),
+                                &info_file, 0) ||
+          init_strvar_from_file(ssl_key, sizeof(ssl_key),
+                               &info_file, 0))
+      goto errwithmsg;
+
+      /*
+        Starting from 5.1.16 ssl_verify_server_cert might be
+        in the file
+      */
+      if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT &&
+          init_intvar_from_file(&var_ssl_verify_server_cert, &info_file, 0))
+        goto errwithmsg;
+      /*
+        Starting from 6.0 master_heartbeat_period might be
+        in the file
+      */
+      if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD &&
+          init_floatvar_from_file(&var_master_heartbeat_period, &info_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_REPLICATE_IGNORE_SERVER_IDS &&
+          init_dynarray_intvar_from_file(&ignore_server_ids, &info_file))
+      {
+        sql_print_error("Failed to initialize master info ignore_server_ids");
+        goto errwithmsg;
+      }
+
+    }
+
+#ifndef HAVE_OPENSSL
+    if (var_ssl)
+      sql_print_warning("SSL information in the master info file "
+                      "('%s') are ignored because this MySQL slave was "
+                      "compiled without SSL support.", fname);
+#endif /* HAVE_OPENSSL */
+
+    /*
+      This has to be handled here as init_intvar_from_file can't handle
+      my_off_t types
+    */
+    master_log_pos= (my_off_t) var_master_log_pos;
+    port= (uint) var_port;
+    connect_retry= (uint) var_connect_retry;
+    ssl= (my_bool) var_ssl;
+    ssl_verify_server_cert= var_ssl_verify_server_cert;
+    heartbeat_period= var_master_heartbeat_period;
+  }
+  DBUG_PRINT("master_info",("log_file_name: %s  position: %ld",
+                            master_log_name,
+                            (ulong) master_log_pos));
+
+  rli->mi = this;
+  if (rli->init_relay_log_info())
+    goto err;
+
+  inited = 1;
+  // now change cache READ -> WRITE - must do this before flush_master_info
+  reinit_io_cache(&info_file, WRITE_CACHE, 0L, 0, 1);
+  if ((error=test(flush_master_info(1))))
+    sql_print_error("Failed to flush master info file");
+  pthread_mutex_unlock(&data_lock);
+  DBUG_RETURN(error);
+
+errwithmsg:
+  sql_print_error("Error reading master configuration");
+
+err:
+  if (info_fd >= 0)
+  {
+    my_close(info_fd, MYF(0));
+    end_io_cache(&info_file);
+  }
+  info_fd= -1;
+  pthread_mutex_unlock(&data_lock);
+  DBUG_RETURN(1);
+}
+
+
+/*
+  RETURN
+     2 - flush relay log failed
+     1 - flush master info failed
+     0 - all ok
+*/
+int Master_file_info::save_master_info(bool flush_relay_log_cache)
+{
+  IO_CACHE* file = &info_file;
+  char lbuf[22];
+  int err= 0;
+
+  DBUG_ENTER("Master_file_info::save_master_info");
+  DBUG_PRINT("enter",("master_pos: %ld", (long) master_log_pos));
+
+  /*
+    Flush the relay log to disk. If we don't do it, then the relay log while
+    have some part (its last kilobytes) in memory only, so if the slave server
+    dies now, with, say, from master's position 100 to 150 in memory only (not
+    on disk), and with position 150 in master.info, then when the slave
+    restarts, the I/O thread will fetch binlogs from 150, so in the relay log
+    we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
+    SQL thread will jump from 100 to 150, and replication will silently break.
+
+    When we come to this place in code, relay log may or not be initialized;
+    the caller is responsible for setting 'flush_relay_log_cache' accordingly.
+  */
+  if (flush_relay_log_cache)
+  {
+    IO_CACHE *log_file= rli->relay_log.get_log_file();
+    if (flush_io_cache(log_file))
+      DBUG_RETURN(2);
+  }
+
+  /*
+    We flushed the relay log BEFORE the master.info file, because if we crash
+    now, we will get a duplicate event in the relay log at restart. If we
+    flushed in the other order, we would get a hole in the relay log.
+    And duplicate is better than hole (with a duplicate, in later versions we
+    can add detection and scrap one event; with a hole there's nothing we can
+    do).
+  */
+
+  /*
+     In certain cases this code may create master.info files that seems
+     corrupted, because of extra lines filled with garbage in the end
+     file (this happens if new contents take less space than previous
+     contents of file). But because of number of lines in the first line
+     of file we don't care about this garbage.
+  */
+  char heartbeat_buf[sizeof(heartbeat_period) * 4]; // buffer to suffice always
+  my_sprintf(heartbeat_buf, (heartbeat_buf, "%.3f", heartbeat_period));
+  /*
+    produce a line listing the total number and all the ignored server_id:s
+  */
+  char* ignore_server_ids_buf;
+  {
+    ignore_server_ids_buf=
+      (char *) my_malloc((sizeof(::server_id) * 3 + 1) *
+                         (1 + ignore_server_ids.elements), MYF(MY_WME));
+    if (!ignore_server_ids_buf)
+      DBUG_RETURN(1);
+    for (ulong i= 0, cur_len= my_sprintf(ignore_server_ids_buf,
+                                         (ignore_server_ids_buf, "%u",
+                                          ignore_server_ids.elements));
+         i < ignore_server_ids.elements; i++)
+    {
+      ulong s_id;
+      get_dynamic(&ignore_server_ids, (uchar*) &s_id, i);
+      cur_len +=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%s\n",
+              LINES_IN_MASTER_INFO,
+              master_log_name, llstr(master_log_pos, lbuf),
+              host, user,
+              password, port, connect_retry,
+              (int)(ssl), ssl_ca, ssl_capath, ssl_cert,
+              ssl_cipher, ssl_key, ssl_verify_server_cert,
+              heartbeat_buf,
+              ignore_server_ids_buf);
+  my_free(ignore_server_ids_buf, MYF(0));
+  err= flush_io_cache(file);
+  if (sync_masterinfo_period && !err && 
+      ++(sync_counter) >= sync_masterinfo_period)
+  {
+    err= my_sync(info_fd, MYF(MY_WME));
+    sync_counter= 0;
+  }
+  DBUG_RETURN(-err);
+}
+
+void Master_file_info::close_master_info()
+{
+  DBUG_ENTER("Master_file_info::close_master_info");
+
+  if (!inited)
+    DBUG_VOID_RETURN;
+  rli->end_relay_log_info();
+  if (info_fd >= 0)
+  {
+    end_io_cache(&info_file);
+    (void)my_close(info_fd, MYF(MY_WME));
+    info_fd = -1;
+  }
+  inited = 0;
+
+  DBUG_VOID_RETURN;
+}
+
+int Master_file_info::erase_master_info() 
+{
+  MY_STAT stat_area;
+  char fname[FN_REFLEN];
+  int error= 0;
+
+  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
+  if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
+    error= 1;
+
+  return (error);
+}
+
+
+#endif /* HAVE_REPLICATION */

=== added file 'sql/rpl_mi_file.h'
--- a/sql/rpl_mi_file.h	1970-01-01 00:00:00 +0000
+++ b/sql/rpl_mi_file.h	2009-03-03 07:29:54 +0000
@@ -0,0 +1,49 @@
+/* Copyright (C) 2005 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef RPL_MI_FILE_H
+#define RPL_MI_FILE_H
+
+#include "rpl_mi.h"
+
+class Master_file_info : public Master_info
+{
+  public:
+  
+  const char* info_fname;
+  /*
+    info_fd - file descriptor of the info file. set only during
+    initialization or clean up - safe to read anytime
+  */
+  File info_fd;
+  /* IO_CACHE of the info file - set only during init or end */
+  IO_CACHE info_file;
+  /*
+   Keeps track of the number of events before fsyncing. The option 
+   --sync-master-info determines how many events should be processed
+   before fsyncing.
+  */
+  uint sync_counter;
+
+  Master_file_info(Relay_log_info *param_rli, const char* param_info_fname);
+
+  int create_master_info (bool abort_if_no_master_info_file,
+                          int thread_mask);
+  void close_master_info();
+  int save_master_info (bool flush_relay_log_cache);
+  int erase_master_info();
+};
+
+#endif 

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-03-02 21:53:42 +0000
+++ b/sql/slave.cc	2009-03-03 07:29:54 +0000
@@ -30,6 +30,7 @@
 #include <myisam.h>
 #include "slave.h"
 #include "rpl_mi.h"
+#include "rpl_mi_file.h"
 #include "rpl_rli.h"
 #include "rpl_rli_file.h"
 #include "sql_repl.h"
@@ -246,7 +247,9 @@ int init_slave()
                         : new Relay_log_file_info(relay_log_recovery, 
                                                   relay_log_info_file));
  
-  active_mi= new Master_info(rli);
+  active_mi= (transact_replication ? 
+                        new Master_file_info(rli, master_info_file)
+                        : new Master_file_info(rli, master_info_file));
 
   /*
     If master_host is not specified, try to read it from the master_info file.
@@ -260,8 +263,7 @@ int init_slave()
     goto err;
   }
 
-  if (active_mi->init_master_info(master_info_file,
-                       1, (SLAVE_IO | SLAVE_SQL)))
+  if (active_mi->init_master_info(1, (SLAVE_IO | SLAVE_SQL)))
   {
     sql_print_error("Failed to initialize the master info structure");
     error= 1;
@@ -281,8 +283,6 @@ int init_slave()
     if (start_slave_threads(1 /* need mutex */,
                             0 /* no wait for start*/,
                             active_mi,
-                            master_info_file,
-                            relay_log_info_file,
                             SLAVE_IO | SLAVE_SQL))
     {
       sql_print_error("Failed to create slave threads");
@@ -675,8 +675,7 @@ int start_slave_thread(pthread_handler h
 */
 
 int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
-                        Master_info* mi, const char* master_info_fname,
-                        const char* slave_info_fname, int thread_mask)
+                        Master_info* mi, int thread_mask)
 {
   pthread_mutex_t *lock_io=0,*lock_sql=0,*lock_cond_io=0,*lock_cond_sql=0;
   pthread_cond_t* cond_io=0,*cond_sql=0;
@@ -2242,7 +2241,7 @@ static int exec_relay_log_event(THD* thd
         */
         if (rli->trans_retries < slave_trans_retries)
         {
-          if (rli->mi->init_master_info(0, 0, SLAVE_SQL))
+          if (rli->mi->init_master_info(0, SLAVE_SQL))
             sql_print_error("Failed to initialize the master info structure");
           else if (init_relay_log_pos(rli,
                                       rli->group_relay_log_name,

=== modified file 'sql/slave.h'
--- a/sql/slave.h	2009-03-02 21:53:42 +0000
+++ b/sql/slave.h	2009-03-03 07:29:54 +0000
@@ -149,8 +149,7 @@ int register_slave_on_master(MYSQL* mysq
 int terminate_slave_threads(Master_info* mi, int thread_mask,
 			     bool skip_lock = 0);
 int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
-			Master_info* mi, const char* master_info_fname,
-			const char* slave_info_fname, int thread_mask);
+			Master_info* mi, int thread_mask);
 /*
   cond_lock is usually same as start_lock. It is needed for the case when
   start_lock is 0 which happens if start_slave_thread() is called already

=== modified file 'sql/sql_repl.cc'
--- a/sql/sql_repl.cc	2009-03-02 21:53:42 +0000
+++ b/sql/sql_repl.cc	2009-03-03 07:29:54 +0000
@@ -1094,8 +1094,7 @@ int start_slave(THD* thd , Master_info* 
     thread_mask&= thd->lex->slave_thd_opt;
   if (thread_mask) //some threads are stopped, start them
   {
-    if (mi->init_master_info(master_info_file, 0,
-			 thread_mask))
+    if (mi->init_master_info(0, thread_mask))
       slave_errno=ER_MASTER_INFO;
     else if (server_id_supplied && *mi->host)
     {
@@ -1170,7 +1169,6 @@ int start_slave(THD* thd , Master_info* 
         slave_errno = start_slave_threads(0 /*no mutex */,
 					1 /* wait for start */,
 					mi,
-					master_info_file,relay_log_info_file,
 					thread_mask);
     }
     else
@@ -1419,8 +1417,7 @@ bool change_master(THD* thd, Master_info
   }
 
   // TODO: see if needs re-write
-  if (mi->init_master_info(master_info_file, 0,
-		       thread_mask))
+  if (mi->init_master_info(0, thread_mask))
   {
     my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
     ret= TRUE;

Thread
bzr commit into mysql-6.0-rpl branch (alfranio.correia:2819)Alfranio Correia3 Mar