MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Magne Mahre Date:November 4 2009 1:31pm
Subject:bzr commit into mysql-5.5-next-mr-runtime branch (magne.mahre:2911)
Bug#8368
View as plain text  
#At file:///data/z/mysql-next-mr-runtime/ based on revid:magne.mahre@stripped

 2911 Magne Mahre	2009-11-04
      BUG #8368  "mysqldump needs --slave-data option"
        
      Added this option, named as "--dump-slave". The purpose of this option is to be
      able to produce a dump from a slave used for making backups of the master. Originally,
      dumping from the main master was fine, but as more data accumulated, the dump process
      would take over 30 minutes, locking up the master database hence website for 30 minutes.
      A slave dedicated to producing backups was the answer, but I needed a dump that could be
      
      used to restore a slave instantly and in order to do that, it has to have three things 
      contained in the dump:
        
        1. "STOP SLAVE;" at the beginning
        2. "CHANGE MASTER TO ...<the master - info from 'show slave status'>"
        3. "START SLAVE;" at the end
        
      These options in this changeset contain this.
        
        --stop-slave adds "STOP SLAVE" to the beginning of the dump and "STOP SLAVE" 
        to the end of the dump.
        
        --include-host gives the user the option to have the host explicitely added
        to the "CHANGE MASTER TO ..." line.
        
        --dump-slave adds the "CHANGE MASTER ..." to the dump representing not the slave's
        master binlog info, but the slave's master's info from "SHOW SLAVE STATUS" 
     @ client/client_priv.h
        Added OPT_SLAVE_DATA to client_priv.h
     @ client/mysqldump.c
        * Added --dump-slave option (name per Brian)
        * Added --stop-slave to print "STOP SLAVE;" into the dump
        * Added --include-host option to include "MASTER_HOST=..." and "MASTER_PORT=..."
          to the dump since unlike --master-data, the host can't be assumed to be
          the local host
        * Added do_start_slave and do_stop_slave to stop the slave sql thread upon
          start of the dump process, and to start the slave sql upon finish of dump process -
          to keep the log information frozen during this time.
        * Added do_show_slave_status for obtaining slave information needed to compose 
          "CHANGE MASTER ..." output to the master of this slave.
        * Added necessary long options and defines required for new options

    added:
      mysql-test/r/rpl_mysqldump_slave.result
      mysql-test/t/rpl_mysqldump_slave.test
    modified:
      client/client_priv.h
      client/mysqldump.c
=== modified file 'client/client_priv.h'
--- a/client/client_priv.h	2009-11-04 12:20:02 +0000
+++ b/client/client_priv.h	2009-11-04 13:31:03 +0000
@@ -62,6 +62,9 @@ enum options_client
   OPT_MYSQL_NUMBER_OF_QUERY,
   OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE,
   OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_CREATE_SLAP_SCHEMA,
+  OPT_MYSQLDUMP_SLAVE_APPLY,
+  OPT_MYSQLDUMP_SLAVE_DATA,
+  OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT,
   OPT_SLAP_CSV, OPT_SLAP_CREATE_STRING,
   OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE, OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
   OPT_SLAP_AUTO_GENERATE_ADD_AUTO,

=== modified file 'client/mysqldump.c'
--- a/client/mysqldump.c	2009-11-03 09:22:22 +0000
+++ b/client/mysqldump.c	2009-11-04 13:31:03 +0000
@@ -98,6 +98,8 @@ static my_bool  verbose= 0, opt_no_creat
                 opt_complete_insert= 0, opt_drop_database= 0,
                 opt_replace_into= 0,
                 opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1,
+                opt_slave_apply= 0, 
+                opt_include_master_host_port= 0,
                 opt_events= 0,
                 opt_alltspcs=0, opt_notspcs= 0;
 static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0;
@@ -118,7 +120,10 @@ static my_bool server_supports_switching
 static ulong opt_compatible_mode= 0;
 #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
 #define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
+#define MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL 1
+#define MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL 2
 static uint opt_mysql_port= 0, opt_master_data;
+static uint opt_slave_data;
 static uint my_end_arg;
 static char * opt_mysql_unix_port=0;
 static int   first_error=0;
@@ -206,6 +211,10 @@ static struct my_option my_long_options[
   {"allow-keywords", OPT_KEYWORDS,
    "Allow creation of column names that are keywords.", (uchar**) &opt_keywords,
    (uchar**) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"apply-slave-statements", OPT_MYSQLDUMP_SLAVE_APPLY,
+   "Adds 'STOP SLAVE' prior to 'CHANGE MASTER' and 'START SLAVE' to bottom of dump.",
+   (uchar**) &opt_slave_apply, (uchar**) &opt_slave_apply, 0, GET_BOOL, NO_ARG,
+   0, 0, 0, 0, 0, 0},
 #ifdef __NETWARE__
   {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -264,6 +273,19 @@ static struct my_option my_long_options[
   {"disable-keys", 'K',
    "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (uchar**) &opt_disable_keys,
    (uchar**) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+  {"dump-slave", OPT_MYSQLDUMP_SLAVE_DATA,
+   "This causes the binary log position and filename of the master to be "
+   "appended to the dumped data output. Setting the value to 1, will print"
+   "it as a CHANGE MASTER command in the dumped data output; if equal"
+   " to 2, that command will be prefixed with a comment symbol. "
+   "This option will turn --lock-all-tables on, unless "
+   "--single-transaction is specified too (in which case a "
+   "global read lock is only taken a short time at the beginning of the dump "
+   "- don't forget to read about --single-transaction below). In all cases "
+   "any action on logs will happen at the exact moment of the dump."
+   "Option automatically turns --lock-tables off.",
+   (uchar**) &opt_slave_data, (uchar**) &opt_slave_data, 0,
+   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0},
   {"events", 'E', "Dump events.",
      (uchar**) &opt_events, (uchar**) &opt_events, 0, GET_BOOL,
      NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -317,6 +339,12 @@ static struct my_option my_long_options[
    "use the directive multiple times, once for each table.  Each table must "
    "be specified with both database and table names, e.g. --ignore-table=database.table",
    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"include-master-host-port", OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT,
+   "Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE MASTER TO..' in dump produced with --dump-slave.",
+   (uchar**) &opt_include_master_host_port, 
+   (uchar**) &opt_include_master_host_port, 
+   0, GET_BOOL, NO_ARG,
+   0, 0, 0, 0, 0, 0},
   {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
    (uchar**) &opt_ignore, (uchar**) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
    0, 0},
@@ -764,6 +792,10 @@ get_one_option(int optid, const struct m
     if (!argument) /* work like in old versions */
       opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
     break;
+  case (int) OPT_MYSQLDUMP_SLAVE_DATA:
+    if (!argument) /* work like in old versions */
+      opt_slave_data= MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL;
+    break;
   case (int) OPT_OPTIMIZE:
     extended_insert= opt_drop= opt_lock= quick= create_options=
       opt_disable_keys= lock_tables= opt_set_charset= 1;
@@ -896,6 +928,14 @@ static int get_options(int *argc, char *
     return(EX_USAGE);
   }
 
+  /* We don't delete master logs if slave data option */
+  if (opt_slave_data)
+  {
+    opt_lock_all_tables= !opt_single_transaction;
+    opt_master_data= 0;
+    opt_delete_master_logs= 0;
+  }
+
   /* Ensure consistency of the set of binlog & locking options */
   if (opt_delete_master_logs && !opt_master_data)
     opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL;
@@ -906,7 +946,10 @@ static int get_options(int *argc, char *
     return(EX_USAGE);
   }
   if (opt_master_data)
+  {
     opt_lock_all_tables= !opt_single_transaction;
+    opt_slave_data= 0;
+  }
   if (opt_single_transaction || opt_lock_all_tables)
     lock_tables= 0;
   if (enclosed && opt_enclosed)
@@ -4333,6 +4376,130 @@ static int do_show_master_status(MYSQL *
   return 0;
 }
 
+static int do_stop_slave_sql(MYSQL *mysql_con)
+{
+  MYSQL_RES *slave;
+  /* We need to check if the slave sql is running in the first place */
+  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
+    return(1);
+  else
+  {
+    MYSQL_ROW row= mysql_fetch_row(slave);
+    if (row && row[11])
+    {
+      /* if SLAVE SQL is not running, we don't stop it */
+      if (!strcmp(row[11],"No"))
+      {
+        mysql_free_result(slave);
+        /* Silently assume that they don't have the slave running */
+        return(0);
+      }
+    }
+  }
+  mysql_free_result(slave);
+
+  /* now, stop slave if running */
+  if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
+    return(1);
+
+  return(0);
+}
+
+static int add_stop_slave(void)
+{
+  if (opt_comments)
+    fprintf(md_result_file,
+            "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n");
+  fprintf(md_result_file, "STOP SLAVE;\n");
+  return(0);
+}
+
+static int add_slave_statements(void)
+{
+  if (opt_comments)
+    fprintf(md_result_file,
+            "\n--\n-- start slave statement to make a recovery dump)\n--\n\n");
+  fprintf(md_result_file, "START SLAVE;\n");
+  return(0);
+}
+
+static int do_show_slave_status(MYSQL *mysql_con)
+{
+  MYSQL_RES *slave;
+  const char *comment_prefix=
+    (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
+  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
+  {
+    if (!ignore_errors)
+    {
+      /* SHOW SLAVE STATUS reports nothing and --force is not enabled */
+      my_printf_error(0, "Error: Slave not set up", MYF(0));
+    }
+    mysql_free_result(slave);
+    return 1;
+  }
+  else
+  {
+    MYSQL_ROW row= mysql_fetch_row(slave);
+    if (row && row[9] && row[21])
+    {
+      /* SHOW MASTER STATUS reports file and position */
+      if (opt_comments)
+        fprintf(md_result_file,
+                "\n--\n-- Position to start replication or point-in-time "
+                "recovery from (the master of this slave)\n--\n\n");
+
+      fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);
+
+      if (opt_include_master_host_port)
+      {
+        if (row[1])
+          fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]);
+        if (row[3])
+          fprintf(md_result_file, "MASTER_PORT='%s', ", row[3]);
+      }
+      fprintf(md_result_file,
+              "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);
+
+      check_io(md_result_file);
+    }
+    mysql_free_result(slave);
+  }
+  return 0;
+}
+
+static int do_start_slave_sql(MYSQL *mysql_con)
+{
+  MYSQL_RES *slave;
+  /* We need to check if the slave sql is stopped in the first place */
+  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
+    return(1);
+  else
+  {
+    MYSQL_ROW row= mysql_fetch_row(slave);
+    if (row && row[11])
+    {
+      /* if SLAVE SQL is not running, we don't start it */
+      if (!strcmp(row[11],"Yes"))
+      {
+        mysql_free_result(slave);
+        /* Silently assume that they don't have the slave running */
+        return(0);
+      }
+    }
+  }
+  mysql_free_result(slave);
+
+  /* now, start slave if stopped */
+  if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
+  {
+    my_printf_error(0, "Error: Unable to start slave", MYF(0));
+    return 1;
+  }
+  return(0);
+}
+
+
 
 static int do_flush_tables_read_lock(MYSQL *mysql_con)
 {
@@ -4995,6 +5162,9 @@ int main(int argc, char **argv)
   if (!path)
     write_header(md_result_file, *argv);
 
+  if (opt_slave_data && do_stop_slave_sql(mysql))
+    goto err;
+
   if ((opt_lock_all_tables || opt_master_data) &&
       do_flush_tables_read_lock(mysql))
     goto err;
@@ -5013,8 +5183,13 @@ int main(int argc, char **argv)
       goto err;
     flush_logs= 0; /* not anymore; that would not be sensible */
   }
+  /* Add 'STOP SLAVE to beginning of dump */
+  if (opt_slave_apply && add_stop_slave())
+    goto err;
   if (opt_master_data && do_show_master_status(mysql))
     goto err;
+  if (opt_slave_data && do_show_slave_status(mysql))
+    goto err;
   if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
     goto err;
 
@@ -5042,6 +5217,14 @@ int main(int argc, char **argv)
     dump_databases(argv);
   }
 
+  /* if --dump-slave , start the slave sql thread */
+  if (opt_slave_data && do_start_slave_sql(mysql))
+    goto err;
+
+  /* add 'START SLAVE' to end of dump */
+  if (opt_slave_apply && add_slave_statements())
+    goto err;
+
   /* ensure dumped data flushed */
   if (md_result_file && fflush(md_result_file))
   {

=== added file 'mysql-test/r/rpl_mysqldump_slave.result'
--- a/mysql-test/r/rpl_mysqldump_slave.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/rpl_mysqldump_slave.result	2009-11-04 13:31:03 +0000
@@ -0,0 +1,17 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+#
+# New --dump-slave, --apply-slave-statements functionality
+#
+use test;
+CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=107;
+STOP SLAVE;
+CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=107;
+START SLAVE;
+STOP SLAVE;
+CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT='MASTER_MYPORT', MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=107;
+START SLAVE;

=== added file 'mysql-test/t/rpl_mysqldump_slave.test'
--- a/mysql-test/t/rpl_mysqldump_slave.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/rpl_mysqldump_slave.test	2009-11-04 13:31:03 +0000
@@ -0,0 +1,25 @@
+source include/master-slave.inc;
+
+--echo #
+--echo # New --dump-slave, --apply-slave-statements functionality
+--echo #
+
+# There is a gap between when START SLAVE returns and when MASTER_LOG_FILE and
+# MASTER_LOG_POS are set.  Ensure that we don't call SHOW SLAVE STATUS during
+# that gap.
+--sync_slave_with_master
+
+connection master;
+use test;
+
+connection slave;
+
+# Execute mysqldump with --dump-slave
+--exec $MYSQL_DUMP_SLAVE --compact --dump-slave test
+
+# Execute mysqldump with --dump-slave and --apply-slave-statements 
+--exec $MYSQL_DUMP_SLAVE --compact --dump-slave --apply-slave-statements test
+
+--replace_result $MASTER_MYPORT MASTER_MYPORT
+# Execute mysqldump with --dump-slave ,--apply-slave-statements and --include-master-host-port
+--exec $MYSQL_DUMP_SLAVE --compact --dump-slave --apply-slave-statements --include-master-host-port test


Attachment: [text/bzr-bundle] bzr/magne.mahre@sun.com-20091104133103-j23l5kvsvrssvwlh.bundle
Thread
bzr commit into mysql-5.5-next-mr-runtime branch (magne.mahre:2911)Bug#8368Magne Mahre4 Nov