Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDEV-7611 mysqldump --dump-slave always starts stopped slave #3780

Open
wants to merge 2 commits into
base: 10.5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 32 additions & 32 deletions client/mysqldump.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <sslopt-vars.h>
FILE *md_result_file= 0;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Comment on lines +6110 to +6111
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that it’s wrong wasting memory on short names and already-stopped replicas, but I feel that it’s more wrong spending extra effort reallocing unpredictably.

I’d like to iterate the MYSQL_RES an additional time before the following loop to sum up name sizes of (only) active replications.
Question: How to rewind it from mysql_fetch_row()s?


Note I didn’t check size overflow here because of the Broken Windows Theory:

if (!(tmp=(char*) my_malloc(PSI_NOT_INSTRUMENTED, length*2+1, MYF(MY_WME))))

result= my_malloc(PSI_NOT_INSTRUMENTED, result_length + 10, 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)))
Expand All @@ -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] : "");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pedantically supporting no-multi-source on a best effort basis
(But those pre-10.0 versions were long-EOL… 😕)

server/client/mysqldump.c

Lines 7010 to 7015 in 6aa47fa

/* Check if the server support multi source */
if (mysql_get_server_version(mysql) >= 100000)
{
multi_source= 2;
have_mariadb_gtid= 1;
}

}
}
}
Expand Down Expand Up @@ -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--;)
Comment on lines 6265 to +6269
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To use the new list instead of SHOW SLAVE STATUS, I essentially rewrote do_start_slave_sql

{
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The program runs SHOW SLAVE STATUS multiple times thoughout the various step functions:

  • do_show_slave_status
  • do_stop_slave_sql
  • do_start_slave_sql (before this PR)

Perhaps the intent is in case replication configs change in the middle of mariadb-dump?

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);
}

Expand Down
1 change: 0 additions & 1 deletion mysql-test/main/mysqldump.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 47 additions & 0 deletions mysql-test/suite/multi_source/mariadb-dump_slave.result
Original file line number Diff line number Diff line change
@@ -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;
42 changes: 42 additions & 0 deletions mysql-test/suite/multi_source/mariadb-dump_slave.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Interactions with --dump-slave; based on `main.rpl_mysqldump_slave`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and multi_source.gtid_slave_pos for the setup


--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
1 change: 0 additions & 1 deletion mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines 73 to -74
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was aware 😄.


--exec $MYSQL_DUMP_SLAVE --master-data --gtid mysql gtid_slave_pos > $MYSQLTEST_VARDIR/tmp/dump_1.sql

Expand Down