From 0b1b62235c94fb54e44e7a4230f3296254366307 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Sat, 18 Jan 2025 20:06:34 -0700 Subject: [PATCH 1/2] MDEV-7611: create multi_source.mariadb-dump_slave Create a Multi-Source Replication test for these `mariadb-dump --dump-slave` bugs: * MDEV-7611 (not fixed as of this commit) * MDEV-5624 (fixed a long time ago) --- .../multi_source/mariadb-dump_slave.result | 47 +++++++++++++++++++ .../multi_source/mariadb-dump_slave.test | 42 +++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 mysql-test/suite/multi_source/mariadb-dump_slave.result create mode 100644 mysql-test/suite/multi_source/mariadb-dump_slave.test diff --git a/mysql-test/suite/multi_source/mariadb-dump_slave.result b/mysql-test/suite/multi_source/mariadb-dump_slave.result new file mode 100644 index 0000000000000..3c2486171fff1 --- /dev/null +++ b/mysql-test/suite/multi_source/mariadb-dump_slave.result @@ -0,0 +1,47 @@ +connect replica,127.0.0.1,root,,,$SERVER_MYPORT_1; +connect active_primary,127.0.0.1,root,,,$SERVER_MYPORT_2; +connect inactive_primary,127.0.0.1,root,,,$SERVER_MYPORT_3; +connection replica; +CHANGE MASTER 'active_repl' TO master_port=MYPORT_2, master_host='127.0.0.1', master_user='root'; +START REPLICA 'active_repl'; +CHANGE MASTER 'inactive_repl' TO master_port=MYPORT_3, master_host='127.0.0.1', master_user='root'; +STOP REPLICA 'inactive_repl'; +Warnings: +Note 1255 Slave already has been stopped +# Basic +MYSQL_DUMP --compact --dump-slave --include-master-host-port test +/*M!999999\- enable the sandbox mode */ +CHANGE MASTER 'active_repl' TO MASTER_HOST='127.0.0.1', MASTER_PORT=MYPORT_2, MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; +CHANGE MASTER 'inactive_repl' TO MASTER_HOST='127.0.0.1', MASTER_PORT=MYPORT_3, MASTER_LOG_FILE='', MASTER_LOG_POS=BINLOG_START; + +-- SET GLOBAL gtid_slave_pos=''; +# MDEV-7611 mysqldump --dump-slave always starts stopped slave +MYSQL_DUMP --compact --dump-slave test +/*M!999999\- enable the sandbox mode */ +CHANGE MASTER 'active_repl' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; +CHANGE MASTER 'inactive_repl' TO MASTER_LOG_FILE='', MASTER_LOG_POS=BINLOG_START; + +-- SET GLOBAL gtid_slave_pos=''; +START REPLICA 'active_repl'; +Warnings: +Note 1254 Slave is already running +STOP REPLICA 'inactive_repl'; +Warnings: +Note 1255 Slave already has been stopped +# MDEV-5624 mysqldump --dump-slave option does not restart the replication if the dump has failed +MYSQL_DUMP --compact --dump-slave no_such_db +/*M!999999\- enable the sandbox mode */ +CHANGE MASTER 'active_repl' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; +CHANGE MASTER 'inactive_repl' TO MASTER_LOG_FILE='', MASTER_LOG_POS=BINLOG_START; + +START REPLICA 'active_repl'; +Warnings: +Note 1254 Slave is already running +STOP REPLICA 'inactive_repl'; +Warnings: +Note 1255 Slave already has been stopped +# Cleanup +include/reset_master_slave.inc +disconnect replica; +disconnect active_primary; +disconnect inactive_primary; diff --git a/mysql-test/suite/multi_source/mariadb-dump_slave.test b/mysql-test/suite/multi_source/mariadb-dump_slave.test new file mode 100644 index 0000000000000..d10673691b1da --- /dev/null +++ b/mysql-test/suite/multi_source/mariadb-dump_slave.test @@ -0,0 +1,42 @@ +# Interactions with --dump-slave; based on `main.rpl_mysqldump_slave` + +--source include/have_log_bin.inc + +--connect (replica,127.0.0.1,root,,,$SERVER_MYPORT_1) +--connect (active_primary,127.0.0.1,root,,,$SERVER_MYPORT_2) +--connect (inactive_primary,127.0.0.1,root,,,$SERVER_MYPORT_3) +--connection replica + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +--eval CHANGE MASTER 'active_repl' TO master_port=$SERVER_MYPORT_2, master_host='127.0.0.1', master_user='root' +START REPLICA 'active_repl'; +--replace_result $SERVER_MYPORT_3 MYPORT_3 +--eval CHANGE MASTER 'inactive_repl' TO master_port=$SERVER_MYPORT_3, master_host='127.0.0.1', master_user='root' +STOP REPLICA 'inactive_repl'; + +--echo # Basic +--echo MYSQL_DUMP --compact --dump-slave --include-master-host-port test +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--replace_result $SERVER_MYPORT_2 MYPORT_2 $SERVER_MYPORT_3 MYPORT_3 +--exec $MYSQL_DUMP --compact --dump-slave --include-master-host-port test + +--echo # MDEV-7611 mysqldump --dump-slave always starts stopped slave +--echo MYSQL_DUMP --compact --dump-slave test +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--exec $MYSQL_DUMP --compact --dump-slave test +START REPLICA 'active_repl'; +STOP REPLICA 'inactive_repl'; + +--echo # MDEV-5624 mysqldump --dump-slave option does not restart the replication if the dump has failed +--echo MYSQL_DUMP --compact --dump-slave no_such_db +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--error 2 +--exec $MYSQL_DUMP --compact --dump-slave no_such_db +START REPLICA 'active_repl'; +STOP REPLICA 'inactive_repl'; + +--echo # Cleanup +--source include/reset_master_slave.inc +--disconnect replica +--disconnect active_primary +--disconnect inactive_primary From d6c19dfd710eb8d0406a00ff181589f37b30e549 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Mon, 20 Jan 2025 22:49:08 -0700 Subject: [PATCH 2/2] MDEV-7611 mysqldump --dump-slave always starts stopped slave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pausing replicas for `mariadb-dump --dump-slave`, store the names of replicas paused in a dynamically-`malloc`ed buffer; use that (instead of a new SHOW _SLAVE_ STATUS) to resume replicas when the program ends. When making a dump with --dump-slave option, upon completion mysqldump starts slave threads even if they were not stopped by mysqldump itself. This behavior breaks delayed/manually synchronized slaves which have not to be running all the time. ⸺ MDEV-7611 Co-authored-by: Max Samoilenko --- client/mysqldump.c | 64 +++++++++---------- mysql-test/main/mysqldump.result | 1 - .../rpl/r/rpl_mysqldump_gtid_slave_pos.result | 1 - .../rpl/t/rpl_mysqldump_gtid_slave_pos.test | 1 - 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 1cb41b66e304f..0c394048e96cf 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -184,7 +184,8 @@ static DYNAMIC_STRING dynamic_where; static MYSQL_RES *get_table_name_result= NULL; static MEM_ROOT glob_root; static MYSQL_RES *routine_res, *routine_list_res; - +static size_t n_stopped_replicas= 0; +static char (*stopped_replicas)[NAME_CHAR_LEN]= NULL; #include FILE *md_result_file= 0; @@ -1854,6 +1855,7 @@ static void free_resources() mysql_close(mysql); mysql= 0; } + my_free(stopped_replicas); my_free(order_by); my_free(opt_password); my_free(current_host); @@ -6097,12 +6099,22 @@ static int do_stop_slave_sql(MYSQL *mysql_con) { MYSQL_RES *slave; MYSQL_ROW row; + // do_stop_slave_sql() should only be called once + DBUG_ASSERT(!stopped_replicas); if (mysql_query_with_error_report(mysql_con, &slave, multi_source ? "SHOW ALL SLAVES STATUS" : "SHOW SLAVE STATUS")) return(1); + stopped_replicas= my_malloc(PSI_NOT_INSTRUMENTED, + slave->row_count*NAME_CHAR_LEN + 1, MYF(MY_WME)); + if (!stopped_replicas) + { + mysql_free_result(slave); + fputs("Error: Not enough memory to store current replica status\n", stderr); + return 1; + } /* Loop over all slaves */ while ((row= mysql_fetch_row(slave))) @@ -6123,6 +6135,8 @@ static int do_stop_slave_sql(MYSQL *mysql_con) mysql_free_result(slave); return 1; } + strmov(stopped_replicas[n_stopped_replicas++], + multi_source ? row[0] : ""); } } } @@ -6250,43 +6264,29 @@ static int do_show_slave_status(MYSQL *mysql_con, int have_mariadb_gtid, static int do_start_slave_sql(MYSQL *mysql_con) { - MYSQL_RES *slave; - MYSQL_ROW row; int error= 0; DBUG_ENTER("do_start_slave_sql"); - - /* We need to check if the slave sql is stopped in the first place */ - if (mysql_query_with_error_report(mysql_con, &slave, - multi_source ? - "SHOW ALL SLAVES STATUS" : - "SHOW SLAVE STATUS")) - DBUG_RETURN(1); - - while ((row= mysql_fetch_row(slave))) + for (; n_stopped_replicas--;) { - DBUG_PRINT("info", ("Connection: '%s' status: '%s'", - multi_source ? row[0] : "", row[11 + multi_source])); - if (row[11 + multi_source]) + /* + do_start_slave_sql() should only be called + sometime after do_stop_slave_sql() suceeds + */ + char* stopped_replica= stopped_replicas[n_stopped_replicas]; + char query[sizeof("START SLAVE ''") + NAME_CHAR_LEN]; + DBUG_PRINT("info", ("Connection: '%.*s'", NAME_CHAR_LEN, stopped_replica)); + // if SLAVE SQL is running, start it anyway to warn unexpected state change + if (multi_source) + sprintf(query, "START SLAVE '%.*s'", NAME_CHAR_LEN, stopped_replica); + + if (mysql_query_with_error_report(mysql_con, 0, + multi_source ? query : "START SLAVE")) { - /* if SLAVE SQL is not running, we don't start it */ - if (strcmp(row[11 + multi_source], "Yes")) - { - char query[160]; - if (multi_source) - sprintf(query, "START SLAVE '%.80s'", row[0]); - else - strmov(query, "START SLAVE"); - - if (mysql_query_with_error_report(mysql_con, 0, query)) - { - fprintf(stderr, "%s: Error: Unable to start slave '%s'\n", - my_progname_short, multi_source ? row[0] : ""); - error= 1; - } - } + fprintf(stderr, "%s: Error: Unable to start slave '%.*s'\n", + my_progname_short, NAME_CHAR_LEN, stopped_replica); + error= 1; } } - mysql_free_result(slave); DBUG_RETURN(error); } diff --git a/mysql-test/main/mysqldump.result b/mysql-test/main/mysqldump.result index 93e0f9ee89cf9..7af28dc9dce28 100644 --- a/mysql-test/main/mysqldump.result +++ b/mysql-test/main/mysqldump.result @@ -5497,7 +5497,6 @@ proc one DROP DATABASE bug25717383; mariadb-dump: Got error: 2005: "Unknown MySQL server host 'unknownhost'" when trying to connect -mariadb-dump: Couldn't execute 'SHOW SLAVE STATUS': MySQL server has gone away (2006) Usage: mariadb-dump [OPTIONS] database [tables] OR mariadb-dump [OPTIONS] --databases DB1 [DB2 DB3...] OR mariadb-dump [OPTIONS] --all-databases diff --git a/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result b/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result index 9340498c53730..77a050c623070 100644 --- a/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result +++ b/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result @@ -50,7 +50,6 @@ after initial slave got in sync include/stop_slave.inc # 3. A include/stop_slave.inc -include/stop_slave.inc # 4. set statement sql_log_bin=0 for delete from mysql.gtid_slave_pos; insert into mysql.gtid_slave_pos values (99 + 2, 1, 1, 1); diff --git a/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test b/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test index 820fc56134b60..f49f77371ff0e 100644 --- a/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test +++ b/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test @@ -71,7 +71,6 @@ select @@global.gtid_slave_pos as "after initial slave got in sync"; --echo # 3. A # Two dumps prepared to be restored in the following loop --exec $MYSQL_DUMP_SLAVE --dump-slave --gtid mysql gtid_slave_pos > $MYSQLTEST_VARDIR/tmp/dump_2.sql ---source include/stop_slave.inc --exec $MYSQL_DUMP_SLAVE --master-data --gtid mysql gtid_slave_pos > $MYSQLTEST_VARDIR/tmp/dump_1.sql