Skip to content

Commit b8f92ad

Browse files
committed
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.
1 parent b8b6cab commit b8f92ad

File tree

4 files changed

+396
-41
lines changed

4 files changed

+396
-41
lines changed

client/mysqldump.c

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5985,8 +5985,11 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
59855985
} /* dump_selected_tables */
59865986

59875987

5988+
const char fmt_gtid_pos[]= "%sSET GLOBAL gtid_slave_pos='%s';\n";
5989+
59885990
static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
5989-
int have_mariadb_gtid, int use_gtid)
5991+
int have_mariadb_gtid, int use_gtid,
5992+
char *set_gtid_pos)
59905993
{
59915994
MYSQL_ROW row;
59925995
MYSQL_RES *UNINIT_VAR(master);
@@ -6047,15 +6050,21 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
60476050
/* gtid */
60486051
if (have_mariadb_gtid)
60496052
{
6050-
print_comment(md_result_file, 0,
6051-
"\n-- Preferably use GTID to start replication from GTID "
6052-
"position:\n\n");
60536053
if (use_gtid)
6054+
{
60546055
fprintf(md_result_file,
60556056
"%sCHANGE MASTER TO MASTER_USE_GTID=slave_pos;\n",
60566057
comment_prefix);
6057-
fprintf(md_result_file,
6058-
"%sSET GLOBAL gtid_slave_pos='%s';\n",
6058+
/*
6059+
When --gtid is specified defer print of SET gtid_slave_pos until
6060+
after its placeholder table is guaranteed to have been dumped.
6061+
*/
6062+
print_comment(md_result_file, 0,
6063+
"\n-- A corresponding to the above master-data "
6064+
"CHANGE-MASTER settings to the slave gtid state is printed "
6065+
"later in the file.\n");
6066+
}
6067+
sprintf(set_gtid_pos, fmt_gtid_pos,
60596068
(!use_gtid ? "-- " : comment_prefix), gtid_pos);
60606069
}
60616070

@@ -6071,6 +6080,11 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
60716080
fprintf(md_result_file,
60726081
"%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
60736082
(use_gtid ? "-- " : comment_prefix), file, offset);
6083+
if (have_mariadb_gtid && !use_gtid)
6084+
print_comment(md_result_file, 0,
6085+
"\n-- A corresponding to the above master-data CHANGE-MASTER "
6086+
"settings to the slave gtid state is printed as comments "
6087+
"later in the file.\n");
60746088
check_io(md_result_file);
60756089

60766090
if (!consistent_binlog_pos)
@@ -6140,8 +6154,8 @@ static int add_slave_statements(void)
61406154
return(0);
61416155
}
61426156

6143-
static int do_show_slave_status(MYSQL *mysql_con, int use_gtid,
6144-
int have_mariadb_gtid)
6157+
static int do_show_slave_status(MYSQL *mysql_con, int have_mariadb_gtid,
6158+
int use_gtid, char* set_gtid_pos)
61456159
{
61466160
MYSQL_RES *UNINIT_VAR(slave);
61476161
MYSQL_ROW row;
@@ -6181,10 +6195,12 @@ static int do_show_slave_status(MYSQL *mysql_con, int use_gtid,
61816195
mysql_free_result(slave);
61826196
return 1;
61836197
}
6198+
/* defer print similarly to do_show_master_status */
61846199
print_comment(md_result_file, 0,
6185-
"-- GTID position to start replication:\n");
6186-
fprintf(md_result_file, "%sSET GLOBAL gtid_slave_pos='%s';\n",
6187-
gtid_comment_prefix, gtid_pos);
6200+
"\n-- A corresponding to the below dump-slave "
6201+
"CHANGE-MASTER settings to the slave gtid state is printed "
6202+
"later in the file.\n");
6203+
sprintf(set_gtid_pos, fmt_gtid_pos, gtid_comment_prefix, gtid_pos);
61886204
}
61896205
if (use_gtid)
61906206
print_comment(md_result_file, 0,
@@ -6905,6 +6921,34 @@ static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size)
69056921
die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
69066922
}
69076923

6924+
/**
6925+
Print earlier prepared SET @@global.gtid_slave_pos.
6926+
6927+
@param set_gtid_pos[in] formatted sql set statement
6928+
**/
6929+
static void do_print_set_gtid_slave_pos(const char *set_gtid_pos,
6930+
my_bool is_master_data)
6931+
{
6932+
DBUG_ASSERT(opt_master_data || opt_slave_data);
6933+
if (is_master_data)
6934+
{
6935+
print_comment(md_result_file, 0,
6936+
"\n-- The deferred gtid setting for slave corresponding to "
6937+
"the master-data CHANGE-MASTER follows\n");
6938+
print_comment(md_result_file, 0,
6939+
"\n-- Preferably use GTID to start replication from GTID "
6940+
"position:\n\n");
6941+
}
6942+
else
6943+
{
6944+
print_comment(md_result_file, 0,
6945+
"\n-- The deferred gtid setting for slave corresponding to "
6946+
"the dump-slave CHANGE-MASTER follows\n");
6947+
print_comment(md_result_file, 0,
6948+
"-- GTID position to start replication:\n");
6949+
}
6950+
fprintf(md_result_file, "%s", set_gtid_pos);
6951+
}
69086952

69096953
int main(int argc, char **argv)
69106954
{
@@ -6913,6 +6957,12 @@ int main(int argc, char **argv)
69136957
int exit_code;
69146958
int consistent_binlog_pos= 0;
69156959
int have_mariadb_gtid= 0;
6960+
/*
6961+
to hold SET @@global.gtid_slave_pos which is deferred to print
6962+
until the function epilogue.
6963+
*/
6964+
char master_set_gtid_pos[3 + sizeof(fmt_gtid_pos) + MAX_GTID_LENGTH]= {0};
6965+
char slave_set_gtid_pos[3 + sizeof(fmt_gtid_pos) + MAX_GTID_LENGTH]= {0};
69166966
MY_INIT(argv[0]);
69176967

69186968
sf_leaking_memory=1; /* don't report memory leaks on early exits */
@@ -7016,10 +7066,12 @@ int main(int argc, char **argv)
70167066
goto err;
70177067

70187068
if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos,
7019-
have_mariadb_gtid, opt_use_gtid))
7069+
have_mariadb_gtid,
7070+
opt_use_gtid, master_set_gtid_pos))
70207071
goto err;
7021-
if (opt_slave_data && do_show_slave_status(mysql, opt_use_gtid,
7022-
have_mariadb_gtid))
7072+
if (opt_slave_data && do_show_slave_status(mysql,
7073+
have_mariadb_gtid,
7074+
opt_use_gtid, slave_set_gtid_pos))
70237075
goto err;
70247076
if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
70257077
goto err;
@@ -7087,6 +7139,11 @@ int main(int argc, char **argv)
70877139
if (opt_system & OPT_SYSTEM_TIMEZONES)
70887140
dump_all_timezones();
70897141

7142+
if (opt_master_data && master_set_gtid_pos[0])
7143+
do_print_set_gtid_slave_pos(master_set_gtid_pos, TRUE);
7144+
if (opt_slave_data && slave_set_gtid_pos[0])
7145+
do_print_set_gtid_slave_pos(slave_set_gtid_pos, FALSE);
7146+
70907147
/* add 'START SLAVE' to end of dump */
70917148
if (opt_slave_apply && add_slave_statements())
70927149
goto err;

mysql-test/main/rpl_mysqldump_slave.result

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,25 @@ connection master;
88
use test;
99
connection slave;
1010
/*M!999999\- enable the sandbox mode */
11-
-- SET GLOBAL gtid_slave_pos='';
1211
CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
1312

13+
-- SET GLOBAL gtid_slave_pos='';
1414
/*M!999999\- enable the sandbox mode */
1515
STOP ALL SLAVES;
16-
-- SET GLOBAL gtid_slave_pos='';
1716
CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
1817

18+
-- SET GLOBAL gtid_slave_pos='';
1919
START ALL SLAVES;
2020
/*M!999999\- enable the sandbox mode */
2121
STOP ALL SLAVES;
22-
-- SET GLOBAL gtid_slave_pos='';
2322
CHANGE MASTER '' TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_MYPORT, MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
2423

24+
-- SET GLOBAL gtid_slave_pos='';
2525
START ALL SLAVES;
2626
start slave;
2727
Warnings:
2828
Note 1254 Slave is already running
2929
/*M!999999\- enable the sandbox mode */
30-
-- SET GLOBAL gtid_slave_pos='';
3130
CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
3231

3332
start slave;
@@ -46,72 +45,72 @@ DROP TABLE t2;
4645
1. --dump-slave=1 --gtid
4746

4847
/*M!999999\- enable the sandbox mode */
49-
SET GLOBAL gtid_slave_pos='0-1-1001';
5048
CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos;
5149
-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
5250

51+
SET GLOBAL gtid_slave_pos='0-1-1001';
5352

5453
1a. --dump-slave=1
5554

5655
/*M!999999\- enable the sandbox mode */
57-
-- SET GLOBAL gtid_slave_pos='0-1-1001';
5856
CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
5957

58+
-- SET GLOBAL gtid_slave_pos='0-1-1001';
6059

6160
2. --dump-slave=2 --gtid
6261

6362
/*M!999999\- enable the sandbox mode */
64-
-- SET GLOBAL gtid_slave_pos='0-1-1001';
6563
-- CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos;
6664
-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
6765

66+
-- SET GLOBAL gtid_slave_pos='0-1-1001';
6867

6968
2. --dump-slave=2
7069

7170
/*M!999999\- enable the sandbox mode */
72-
-- SET GLOBAL gtid_slave_pos='0-1-1001';
7371
-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
7472

73+
-- SET GLOBAL gtid_slave_pos='0-1-1001';
7574
*** Test mysqldump --master-data GTID/non-gtid functionality.
7675

7776
1. --master-data=1 --gtid
7877

7978
/*M!999999\- enable the sandbox mode */
8079
CHANGE MASTER TO MASTER_USE_GTID=slave_pos;
81-
SET GLOBAL gtid_slave_pos='0-2-1003';
8280
-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
81+
SET GLOBAL gtid_slave_pos='0-2-1003';
8382

8483
1a. --master-data=1
8584

8685
/*M!999999\- enable the sandbox mode */
87-
-- SET GLOBAL gtid_slave_pos='0-2-1003';
8886
CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
87+
-- SET GLOBAL gtid_slave_pos='0-2-1003';
8988

9089
2. --master-data=2 --gtid
9190

9291
/*M!999999\- enable the sandbox mode */
9392
-- CHANGE MASTER TO MASTER_USE_GTID=slave_pos;
94-
-- SET GLOBAL gtid_slave_pos='0-2-1003';
9593
-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
94+
-- SET GLOBAL gtid_slave_pos='0-2-1003';
9695

9796
2a. --master-data=2
9897

9998
/*M!999999\- enable the sandbox mode */
100-
-- SET GLOBAL gtid_slave_pos='0-2-1003';
10199
-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
100+
-- SET GLOBAL gtid_slave_pos='0-2-1003';
102101

103102
3. --master-data --single-transaction --gtid
104103

105104
/*M!999999\- enable the sandbox mode */
106105
CHANGE MASTER TO MASTER_USE_GTID=slave_pos;
107-
SET GLOBAL gtid_slave_pos='0-2-1003';
108106
-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
107+
SET GLOBAL gtid_slave_pos='0-2-1003';
109108

110109
3a. --master-data --single-transaction
111110

112111
/*M!999999\- enable the sandbox mode */
113-
-- SET GLOBAL gtid_slave_pos='0-2-1003';
114112
CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
113+
-- SET GLOBAL gtid_slave_pos='0-2-1003';
115114

116115
4. --master-data=2 --dump-slave=2 --single-transaction --gtid (MDEV-4827)
117116

@@ -130,11 +129,9 @@ CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START
130129
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
131130
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
132131
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
133-
134-
-- Preferably use GTID to start replication from GTID position:
135-
136132
-- CHANGE MASTER TO MASTER_USE_GTID=slave_pos;
137-
-- SET GLOBAL gtid_slave_pos='0-2-1003';
133+
134+
-- A corresponding to the above master-data CHANGE-MASTER settings to the slave gtid state is printed later in the file.
138135

139136
--
140137
-- Alternately, following is the position of the binary logging from SHOW MASTER STATUS at point of backup.
@@ -149,14 +146,24 @@ CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START
149146
-- Use this position when creating a clone of, or replacement server, from where the backup was taken.
150147
-- This new server will connects to the same primary server(s).
151148
--
152-
-- GTID position to start replication:
153-
-- SET GLOBAL gtid_slave_pos='0-1-1001';
149+
150+
-- A corresponding to the below dump-slave CHANGE-MASTER settings to the slave gtid state is printed later in the file.
154151

155152
-- Use only the MASTER_USE_GTID=slave_pos or MASTER_LOG_FILE/MASTER_LOG_POS in the statements below.
156153

157154
-- CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos;
158155
-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
159156

157+
158+
-- The deferred gtid setting for slave corresponding to the master-data CHANGE-MASTER follows
159+
160+
-- Preferably use GTID to start replication from GTID position:
161+
162+
-- SET GLOBAL gtid_slave_pos='0-2-1003';
163+
164+
-- The deferred gtid setting for slave corresponding to the dump-slave CHANGE-MASTER follows
165+
-- GTID position to start replication:
166+
-- SET GLOBAL gtid_slave_pos='0-1-1001';
160167
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
161168

162169
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
@@ -187,10 +194,6 @@ CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START
187194
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
188195
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
189196

190-
-- Preferably use GTID to start replication from GTID position:
191-
192-
-- SET GLOBAL gtid_slave_pos='0-2-1003';
193-
194197
--
195198
-- Alternately, following is the position of the binary logging from SHOW MASTER STATUS at point of backup.
196199
-- Use this when creating a replica of the primary server where the backup was made.
@@ -199,15 +202,27 @@ CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START
199202

200203
-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START;
201204

205+
-- A corresponding to the above master-data CHANGE-MASTER settings to the slave gtid state is printed as comments later in the file.
206+
202207
--
203208
-- The following is the SQL position of the replication taken from SHOW SLAVE STATUS at the time of backup.
204209
-- Use this position when creating a clone of, or replacement server, from where the backup was taken.
205210
-- This new server will connects to the same primary server(s).
206211
--
207-
-- GTID position to start replication:
208-
-- SET GLOBAL gtid_slave_pos='0-1-1001';
212+
213+
-- A corresponding to the below dump-slave CHANGE-MASTER settings to the slave gtid state is printed later in the file.
209214
-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START;
210215

216+
217+
-- The deferred gtid setting for slave corresponding to the master-data CHANGE-MASTER follows
218+
219+
-- Preferably use GTID to start replication from GTID position:
220+
221+
-- SET GLOBAL gtid_slave_pos='0-2-1003';
222+
223+
-- The deferred gtid setting for slave corresponding to the dump-slave CHANGE-MASTER follows
224+
-- GTID position to start replication:
225+
-- SET GLOBAL gtid_slave_pos='0-1-1001';
211226
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
212227

213228
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
@@ -232,8 +247,8 @@ change master to master_use_gtid=slave_pos;
232247
connection master;
233248
# Ensuring the binlog dump thread is killed on primary...
234249
/*M!999999\- enable the sandbox mode */
235-
-- SET GLOBAL gtid_slave_pos='0-1-1005';
236250
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=BINLOG_START;
251+
-- SET GLOBAL gtid_slave_pos='0-1-1005';
237252
connection slave;
238253
include/start_slave.inc
239254
include/rpl_end.inc

0 commit comments

Comments
 (0)