1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

MDEV-15393 gtid_slave_pos duplicate key errors after mysqldump restore

When mysqldump is run to dump the `mysql` system database, it generates
INSERT statements into the table `mysql.gtid_slave_pos`.
After running the backup script
those inserts did not produce the expected gtid state on slave. In
particular the maximum of mysql.gtid_slave_pos.sub_id did not make
into
   rpl_global_gtid_slave_state.last_sub_id

an in-memory object that is supposed to match the current state of the
table. And that was regardless of whether --gtid option was specified
or not. Later when the backup recipient server starts as slave
in *non-gtid* mode this desychronization may lead to a duplicate key
error.

This effect is corrected for --gtid mode mysqldump/mariadb-dump only
as the following.  The fixes ensure the insert block of the dump
script is followed with a "summing-up" SET @global.gtid_slave_pos
assignment.

For the implemenation part, note a deferred print-out of
SET-gtid_slave_pos and associated comments is prefered over relocating
of the entire blocks if (opt_master,slave_data &&
do_show_master,slave_status) ...  because of compatiblity
concern. Namely an error inside do_show_*() is handled in the new code
the same way, as early as, as before.

A regression test can be run in how-to-reproduce mode as well.
One affected mtr test observed.
rpl_mysqldump_slave.result "mismatch" shows now the new deferring print
of SET-gtid_slave_pos policy in action.
This commit is contained in:
Andrei
2024-07-15 17:50:37 +03:00
parent b8b6cab2d7
commit b8f92ade57
4 changed files with 396 additions and 41 deletions

View File

@ -5985,8 +5985,11 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
} /* dump_selected_tables */
const char fmt_gtid_pos[]= "%sSET GLOBAL gtid_slave_pos='%s';\n";
static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
int have_mariadb_gtid, int use_gtid)
int have_mariadb_gtid, int use_gtid,
char *set_gtid_pos)
{
MYSQL_ROW row;
MYSQL_RES *UNINIT_VAR(master);
@ -6047,15 +6050,21 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
/* gtid */
if (have_mariadb_gtid)
{
print_comment(md_result_file, 0,
"\n-- Preferably use GTID to start replication from GTID "
"position:\n\n");
if (use_gtid)
{
fprintf(md_result_file,
"%sCHANGE MASTER TO MASTER_USE_GTID=slave_pos;\n",
comment_prefix);
fprintf(md_result_file,
"%sSET GLOBAL gtid_slave_pos='%s';\n",
/*
When --gtid is specified defer print of SET gtid_slave_pos until
after its placeholder table is guaranteed to have been dumped.
*/
print_comment(md_result_file, 0,
"\n-- A corresponding to the above master-data "
"CHANGE-MASTER settings to the slave gtid state is printed "
"later in the file.\n");
}
sprintf(set_gtid_pos, fmt_gtid_pos,
(!use_gtid ? "-- " : comment_prefix), gtid_pos);
}
@ -6071,6 +6080,11 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
fprintf(md_result_file,
"%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
(use_gtid ? "-- " : comment_prefix), file, offset);
if (have_mariadb_gtid && !use_gtid)
print_comment(md_result_file, 0,
"\n-- A corresponding to the above master-data CHANGE-MASTER "
"settings to the slave gtid state is printed as comments "
"later in the file.\n");
check_io(md_result_file);
if (!consistent_binlog_pos)
@ -6140,8 +6154,8 @@ static int add_slave_statements(void)
return(0);
}
static int do_show_slave_status(MYSQL *mysql_con, int use_gtid,
int have_mariadb_gtid)
static int do_show_slave_status(MYSQL *mysql_con, int have_mariadb_gtid,
int use_gtid, char* set_gtid_pos)
{
MYSQL_RES *UNINIT_VAR(slave);
MYSQL_ROW row;
@ -6181,10 +6195,12 @@ static int do_show_slave_status(MYSQL *mysql_con, int use_gtid,
mysql_free_result(slave);
return 1;
}
/* defer print similarly to do_show_master_status */
print_comment(md_result_file, 0,
"-- GTID position to start replication:\n");
fprintf(md_result_file, "%sSET GLOBAL gtid_slave_pos='%s';\n",
gtid_comment_prefix, gtid_pos);
"\n-- A corresponding to the below dump-slave "
"CHANGE-MASTER settings to the slave gtid state is printed "
"later in the file.\n");
sprintf(set_gtid_pos, fmt_gtid_pos, gtid_comment_prefix, gtid_pos);
}
if (use_gtid)
print_comment(md_result_file, 0,
@ -6905,6 +6921,34 @@ static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size)
die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
}
/**
Print earlier prepared SET @@global.gtid_slave_pos.
@param set_gtid_pos[in] formatted sql set statement
**/
static void do_print_set_gtid_slave_pos(const char *set_gtid_pos,
my_bool is_master_data)
{
DBUG_ASSERT(opt_master_data || opt_slave_data);
if (is_master_data)
{
print_comment(md_result_file, 0,
"\n-- The deferred gtid setting for slave corresponding to "
"the master-data CHANGE-MASTER follows\n");
print_comment(md_result_file, 0,
"\n-- Preferably use GTID to start replication from GTID "
"position:\n\n");
}
else
{
print_comment(md_result_file, 0,
"\n-- The deferred gtid setting for slave corresponding to "
"the dump-slave CHANGE-MASTER follows\n");
print_comment(md_result_file, 0,
"-- GTID position to start replication:\n");
}
fprintf(md_result_file, "%s", set_gtid_pos);
}
int main(int argc, char **argv)
{
@ -6913,6 +6957,12 @@ int main(int argc, char **argv)
int exit_code;
int consistent_binlog_pos= 0;
int have_mariadb_gtid= 0;
/*
to hold SET @@global.gtid_slave_pos which is deferred to print
until the function epilogue.
*/
char master_set_gtid_pos[3 + sizeof(fmt_gtid_pos) + MAX_GTID_LENGTH]= {0};
char slave_set_gtid_pos[3 + sizeof(fmt_gtid_pos) + MAX_GTID_LENGTH]= {0};
MY_INIT(argv[0]);
sf_leaking_memory=1; /* don't report memory leaks on early exits */
@ -7016,10 +7066,12 @@ int main(int argc, char **argv)
goto err;
if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos,
have_mariadb_gtid, opt_use_gtid))
have_mariadb_gtid,
opt_use_gtid, master_set_gtid_pos))
goto err;
if (opt_slave_data && do_show_slave_status(mysql, opt_use_gtid,
have_mariadb_gtid))
if (opt_slave_data && do_show_slave_status(mysql,
have_mariadb_gtid,
opt_use_gtid, slave_set_gtid_pos))
goto err;
if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
goto err;
@ -7087,6 +7139,11 @@ int main(int argc, char **argv)
if (opt_system & OPT_SYSTEM_TIMEZONES)
dump_all_timezones();
if (opt_master_data && master_set_gtid_pos[0])
do_print_set_gtid_slave_pos(master_set_gtid_pos, TRUE);
if (opt_slave_data && slave_set_gtid_pos[0])
do_print_set_gtid_slave_pos(slave_set_gtid_pos, FALSE);
/* add 'START SLAVE' to end of dump */
if (opt_slave_apply && add_slave_statements())
goto err;