Skip to content

Commit 0c2618a

Browse files
author
Sven Sandberg
committed
BUG#20471216: 5.6 WITH GTID_MODE=X CANT CONNECT TO 5.7.6 WITH GTID_MODE=X_PERMISSIVE
Background: In 5.6, GTID_MODE can only take two values: ON and OFF. In 5.7, GTID_MODE can take four values: ON, ON_PERMISSIVE, OFF_PERMISSIVE, and OFF. A 5.7 master should be able to replicate to a 5.6 slave if master uses X_PERMISSIVE and slave uses X. Problem: Due to a sanity check on the slave where the slave explicitly checks the master's GTID_MODE, the slave refuses to start replication. The 5.6 server was actually prepared to handle the new modes introduced by 5.7, but in the end the names of the modes were changed: 5.6 allows a master to have modes UPGRADE_STEP_1 and UPGRADE_STEP_2 but not ON_PERMISSIVE or OFF_PERMISSIVE. Fix: - Allow slave to replicate if the master's GTID_MODE *begins* with ON or OFF. The slave in this case will ignore the remainder of the GTID_MODE string and treat master as being ON or OFF. - Report a warning if the master's GTID_MODE begins with ON or OFF but is not equal to ON or OFF. - Change server to use the names ON_PERMISSIVE and OFF_PERMISSIVE in some error messages. @sql/rpl_slave.cc - Allow master's GTID_MODE to be any string that begins with ON or OFF. - Report a warning if the master's GTID_MODE begins with ON or OFF but is not equal to ON or OFF. @mysql-test/include/assert_grep.inc - Backport this test utility from 5.7. @mysql-test/suite/rpl/t/rpl_gtid_mode.test - Add cases for OFF_PERMISSIVE and ON_PERMISSIVE. @mysql-test/suite/rpl/t/rpl_gtid_mode_off_new_master.test - New test running with gtid_mode=off. @mysql-test/suite/rpl/t/rpl_gtid_mode_on_new_master.test - New test running with gtid_mode=on.
1 parent e7a265b commit 0c2618a

File tree

8 files changed

+372
-5
lines changed

8 files changed

+372
-5
lines changed

mysql-test/include/assert_grep.inc

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# ==== Purpose ====
2+
#
3+
# Grep a file for a pattern, produce a single string out of the
4+
# matching lines, and assert that the string matches a given regular
5+
# expression.
6+
#
7+
# ==== Usage ====
8+
#
9+
# --let $assert_text= TEXT
10+
# --let $assert_file= FILE
11+
# --let $assert_select= REGEX
12+
# [--let $assert_match= REGEX | --let $assert_count= NUMBER]
13+
# [--let $assert_only_after= REGEX]
14+
# --source include/assert_grep.inc
15+
#
16+
# Parameters:
17+
#
18+
# $assert_text
19+
# Text that describes what is being checked. This text is written to
20+
# the query log so it should not contain non-deterministic elements.
21+
#
22+
# $assert_file
23+
# File to search.
24+
#
25+
# $assert_select
26+
# All lines matching this text will be checked.
27+
#
28+
# $assert_match
29+
# The script will find all lines that match $assert_select,
30+
# concatenate them to a long string, and assert that it matches
31+
# $assert_match.
32+
#
33+
# $assert_count
34+
# Instead of asserting that the selected lines match
35+
# $assert_match, assert that there were exactly $assert_count
36+
# matching lines.
37+
#
38+
# $assert_only_after
39+
# Reset all the lines matched and the counter when finding this pattern.
40+
# It is useful for searching things in the mysqld.err log file just
41+
# after the last server restart for example (discarding the log content
42+
# of previous server executions).
43+
44+
45+
if (!$assert_text)
46+
{
47+
--die !!!ERROR IN TEST: you must set $assert_text
48+
}
49+
if (!$assert_file)
50+
{
51+
--die !!!ERROR IN TEST: you must set $assert_file
52+
}
53+
if (!$assert_select)
54+
{
55+
--die !!!ERROR IN TEST: you must set $assert_select
56+
}
57+
if ($assert_match == '')
58+
{
59+
if ($assert_count == '')
60+
{
61+
--die !!!ERROR IN TEST: you must set either $assert_match or $assert_count
62+
}
63+
}
64+
if ($assert_match != '')
65+
{
66+
if ($assert_count != '')
67+
{
68+
--echo assert_text='$assert_text' assert_count='$assert_count'
69+
--die !!!ERROR IN TEST: you must set only one of $assert_match or $assert_count
70+
}
71+
}
72+
73+
74+
--let $include_filename= assert_grep.inc [$assert_text]
75+
--source include/begin_include_file.inc
76+
77+
78+
--let _AG_ASSERT_TEXT= $assert_text
79+
--let _AG_ASSERT_FILE= $assert_file
80+
--let _AG_ASSERT_SELECT= $assert_select
81+
--let _AG_ASSERT_MATCH= $assert_match
82+
--let _AG_ASSERT_COUNT= $assert_count
83+
--let _AG_OUT= `SELECT CONCAT('$MYSQLTEST_VARDIR/tmp/_ag_', UUID())`
84+
--let _AG_ASSERT_ONLY_AFTER= $assert_only_after
85+
86+
87+
--perl
88+
use strict;
89+
use warnings;
90+
my $file= $ENV{'_AG_ASSERT_FILE'};
91+
my $assert_select= $ENV{'_AG_ASSERT_SELECT'};
92+
my $assert_match= $ENV{'_AG_ASSERT_MATCH'};
93+
my $assert_count= $ENV{'_AG_ASSERT_COUNT'};
94+
my $assert_only_after= $ENV{'_AG_ASSERT_ONLY_AFTER'};
95+
my $out= $ENV{'_AG_OUT'};
96+
97+
my $result= '';
98+
my $count= 0;
99+
open(FILE, "$file") or die("Error $? opening $file: $!\n");
100+
while (<FILE>) {
101+
my $line = $_;
102+
if ($assert_only_after && $line =~ /$assert_only_after/) {
103+
$result = "";
104+
$count = 0;
105+
}
106+
if ($line =~ /$assert_select/) {
107+
if ($assert_count ne '') {
108+
$count++;
109+
}
110+
else {
111+
$result .= $line;
112+
}
113+
}
114+
}
115+
close(FILE) or die("Error $? closing $file: $!");
116+
open OUT, "> $out" or die("Error $? opening $out: $!");
117+
if ($assert_count ne '' && ($count != $assert_count)) {
118+
print OUT ($count) or die("Error $? writing $out: $!");
119+
}
120+
elsif ($assert_count eq '' && $result !~ /$assert_match/) {
121+
print OUT ($result) or die("Error $? writing $out: $!");
122+
}
123+
else {
124+
print OUT ("assert_grep.inc ok");
125+
}
126+
close OUT or die("Error $? closing $out: $!");
127+
EOF
128+
129+
130+
--let $_ag_outcome= `SELECT LOAD_FILE('$_AG_OUT')`
131+
if ($_ag_outcome != 'assert_grep.inc ok')
132+
{
133+
--source include/show_rpl_debug_info.inc
134+
--echo include/assert_grep.inc failed!
135+
--echo assert_select: '$assert_select'
136+
--echo assert_match: '$assert_match'
137+
if ($assert_match != '')
138+
{
139+
--echo matching lines: '$_ag_outcome'
140+
}
141+
if ($assert_count != '')
142+
{
143+
--echo number of matching lines: $_ag_outcome
144+
}
145+
--die assert_grep.inc failed.
146+
}
147+
148+
149+
--let $include_filename= include/assert_grep.inc [$assert_text]
150+
--source include/end_include_file.inc

mysql-test/suite/rpl/r/rpl_gtid_mode.result

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ SET GTID_MODE = UPGRADE_STEP_1;
1717
ERROR HY000: Variable 'gtid_mode' is a read only variable
1818
SET GTID_MODE = UPGRADE_STEP_2;
1919
ERROR HY000: Variable 'gtid_mode' is a read only variable
20+
SET GTID_MODE = OFF_PERMISSIVE;
21+
ERROR HY000: Variable 'gtid_mode' is a read only variable
22+
SET GTID_MODE = ON_PERMISSIVE;
23+
ERROR HY000: Variable 'gtid_mode' is a read only variable
2024
SET GTID_MODE = ON;
2125
ERROR HY000: Variable 'gtid_mode' is a read only variable
2226
---- GTID_NEXT must be ANONYMOUS or AUTOMATIC ----
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
include/master-slave.inc
2+
Warnings:
3+
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
4+
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
5+
[connection master]
6+
CALL mtr.add_suppression('Slave I/O: The master uses an unknown GTID_MODE');
7+
CALL mtr.add_suppression('The slave IO thread stops because the master has an unknown');
8+
SET @save_debug= @@GLOBAL.DEBUG;
9+
include/stop_slave.inc
10+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_off_permissive';
11+
include/start_slave.inc
12+
include/assert_grep.inc [Receiver thread should report that off_permissive is unknown]
13+
include/stop_slave.inc
14+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_off_something';
15+
include/start_slave.inc
16+
include/assert_grep.inc [Receiver thread should report that off_something is unknown]
17+
include/stop_slave.inc
18+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_unknown_gtid_mode';
19+
START SLAVE;
20+
include/wait_for_slave_io_error.inc [errno=1593]
21+
SET @@GLOBAL.DEBUG= @save_debug;
22+
include/stop_slave_sql.inc
23+
RESET SLAVE;
24+
include/start_slave.inc
25+
include/rpl_end.inc
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
include/master-slave.inc
2+
Warnings:
3+
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
4+
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
5+
[connection master]
6+
CALL mtr.add_suppression('Slave I/O: The master uses an unknown GTID_MODE');
7+
CALL mtr.add_suppression('The slave IO thread stops because the master has an unknown');
8+
SET @save_debug= @@GLOBAL.DEBUG;
9+
include/stop_slave.inc
10+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_on_permissive';
11+
include/start_slave.inc
12+
include/assert_grep.inc [Receiver thread should report that on_permissive is unknown]
13+
include/stop_slave.inc
14+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_on_something';
15+
include/start_slave.inc
16+
include/assert_grep.inc [Receiver thread should report that on_something is unknown]
17+
include/stop_slave.inc
18+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_unknown_gtid_mode';
19+
START SLAVE;
20+
include/wait_for_slave_io_error.inc [errno=1593]
21+
SET @@GLOBAL.DEBUG= @save_debug;
22+
include/stop_slave_sql.inc
23+
RESET SLAVE;
24+
include/start_slave.inc
25+
include/rpl_end.inc

mysql-test/suite/rpl/t/rpl_gtid_mode.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ SET GTID_MODE = UPGRADE_STEP_1;
8686
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
8787
SET GTID_MODE = UPGRADE_STEP_2;
8888

89+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
90+
SET GTID_MODE = OFF_PERMISSIVE;
91+
92+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
93+
SET GTID_MODE = ON_PERMISSIVE;
94+
8995
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
9096
SET GTID_MODE = ON;
9197

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# ==== Purpose ====
2+
#
3+
# MySQL 5.7 introduced two new values for GTID_MODE: OFF_PERMISSIVE
4+
# and ON_PERMISSIVE. In order for 5.6 to replicate from such a master,
5+
# a slave that uses GTID_MODE=OFF accepts any master GTID_MODE that
6+
# begins with OFF (i.e., regex /OFF.*/), and a slave that uses
7+
# GTID_MODE=ON accepts any master GTID_MODE that begins with ON.
8+
#
9+
# This test verifies that the slave accepts such values for GTID_MODE.
10+
#
11+
# ==== Implementation ====
12+
#
13+
# Use debug symbols to simulate that the master uses unknown values
14+
# for GTID_MODE.
15+
#
16+
# ==== Related bugs and worklogs ====
17+
#
18+
# WL#7083: GTIDs: set gtid_mode=ON online
19+
# - OFF_PERMISSIVE and ON_PERMISSIVE were introduced in 5.7 in this worklog.
20+
# BUG#20471216: 5.6 WITH GTID_MODE=X CANT CONNECT TO 5.7.6 WITH GTID_MODE=X_PERMISSIVE
21+
# - 5.6 was fixed to accept ON_PERMISSIVE and OFF_PERMISSIVE in this bug.
22+
23+
--source include/have_debug.inc
24+
--source include/not_gtid_enabled.inc
25+
--source include/have_binlog_format_row.inc
26+
27+
--source include/master-slave.inc
28+
29+
--connection slave
30+
CALL mtr.add_suppression('Slave I/O: The master uses an unknown GTID_MODE');
31+
CALL mtr.add_suppression('The slave IO thread stops because the master has an unknown');
32+
33+
SET @save_debug= @@GLOBAL.DEBUG;
34+
35+
--source include/stop_slave.inc
36+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_off_permissive';
37+
--source include/start_slave.inc
38+
--let $assert_text= Receiver thread should report that off_permissive is unknown
39+
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.2.err
40+
--let $assert_only_after= Slave I/O thread: connected to master
41+
--let $assert_select= Slave I/O: The master uses an unknown GTID_MODE 'off_permissive'. Treating it as 'OFF'.
42+
--let $assert_count= 1
43+
--source include/assert_grep.inc
44+
45+
--source include/stop_slave.inc
46+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_off_something';
47+
--source include/start_slave.inc
48+
--let $assert_text= Receiver thread should report that off_something is unknown
49+
--let $assert_select= Slave I/O: The master uses an unknown GTID_MODE 'off_something'. Treating it as 'OFF'.
50+
--source include/assert_grep.inc
51+
52+
--source include/stop_slave.inc
53+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_unknown_gtid_mode';
54+
START SLAVE;
55+
--let $slave_io_errno= convert_error(ER_SLAVE_FATAL_ERROR)
56+
--source include/wait_for_slave_io_error.inc
57+
58+
SET @@GLOBAL.DEBUG= @save_debug;
59+
--source include/stop_slave_sql.inc
60+
RESET SLAVE;
61+
--source include/start_slave.inc
62+
63+
--source include/rpl_end.inc
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# See rpl_gtid_mode_off_new_master.test.
2+
3+
--source include/have_debug.inc
4+
--source include/have_gtid.inc
5+
--source include/have_binlog_format_row.inc
6+
7+
--source include/master-slave.inc
8+
9+
--connection slave
10+
CALL mtr.add_suppression('Slave I/O: The master uses an unknown GTID_MODE');
11+
CALL mtr.add_suppression('The slave IO thread stops because the master has an unknown');
12+
13+
SET @save_debug= @@GLOBAL.DEBUG;
14+
15+
--source include/stop_slave.inc
16+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_on_permissive';
17+
--source include/start_slave.inc
18+
--let $assert_text= Receiver thread should report that on_permissive is unknown
19+
--let $assert_file=$MYSQLTEST_VARDIR/log/mysqld.2.err
20+
--let $assert_only_after= Slave I/O thread: connected to master
21+
--let $assert_select= Slave I/O: The master uses an unknown GTID_MODE 'on_permissive'. Treating it as 'ON'.
22+
--let $assert_count= 1
23+
--source include/assert_grep.inc
24+
25+
--source include/stop_slave.inc
26+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_gtid_mode_on_something';
27+
--source include/start_slave.inc
28+
--let $assert_text= Receiver thread should report that on_something is unknown
29+
--let $assert_select= Slave I/O: The master uses an unknown GTID_MODE 'on_something'. Treating it as 'ON'.
30+
--source include/assert_grep.inc
31+
32+
--source include/stop_slave.inc
33+
SET @@GLOBAL.DEBUG = 'd,simulate_master_has_unknown_gtid_mode';
34+
START SLAVE;
35+
--let $slave_io_errno= convert_error(ER_SLAVE_FATAL_ERROR)
36+
--source include/wait_for_slave_io_error.inc
37+
38+
SET @@GLOBAL.DEBUG= @save_debug;
39+
--source include/stop_slave_sql.inc
40+
RESET SLAVE;
41+
--source include/start_slave.inc
42+
43+
--source include/rpl_end.inc

0 commit comments

Comments
 (0)