Skip to content

Commit fd8ed77

Browse files
author
Venkatesh Duggirala
committed
Merge branch 'mysql-5.6' into mysql-5.7
2 parents abb670c + 44a901a commit fd8ed77

File tree

5 files changed

+183
-2
lines changed

5 files changed

+183
-2
lines changed

client/mysqlbinlog.cc

+72-1
Original file line numberDiff line numberDiff line change
@@ -1092,9 +1092,66 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
10921092
case binary_log::FORMAT_DESCRIPTION_EVENT:
10931093
delete glob_description_event;
10941094
glob_description_event= (Format_description_log_event*) ev;
1095+
/*
1096+
The first FD event in log is always generated
1097+
from the local server. So if it is first FD event to be
1098+
processed (i.e., if server_id_from_fd_event is 0),
1099+
get server_id from the FD event and keep it in
1100+
server_id_from_fd_event to differentiate between FDs
1101+
(originated from local server vs another server).
1102+
*/
1103+
if (print_event_info->server_id_from_fd_event == 0)
1104+
print_event_info->server_id_from_fd_event= ev->server_id;
1105+
10951106
print_event_info->common_header_len=
10961107
glob_description_event->common_header_len;
10971108
ev->print(result_file, print_event_info);
1109+
/*
1110+
At this point, if we are in transaction that means
1111+
we are reading a relay log file (transaction cannot
1112+
spawn across two binary log files, they are writen
1113+
at once in binlog). When AUTO_POSITION is enabled
1114+
and if IO thread stopped in between the GTID transaction,
1115+
upon IO thread restart, Master will send the GTID events
1116+
again from the begin of the transaction. Hence, we should
1117+
rollback the old transaction.
1118+
1119+
If you are reading FD event that came from Master
1120+
(first FD event is from the server that owns the relaylog
1121+
and second one is from Master) and if it's log_pos is > 0
1122+
then it represents the begin of a master's binary log
1123+
(any unfinished transaction will not be finished) or that
1124+
auto_position is enabled (any partial transaction left will
1125+
not be finished but will be fully retrieved again). On both
1126+
cases, the next transaction in the relay log will start from the
1127+
beginning and we must rollback any unfinished transaction
1128+
*/
1129+
if (ev->server_id !=0 &&
1130+
ev->server_id != print_event_info->server_id_from_fd_event &&
1131+
ev->common_header->log_pos > 0)
1132+
{
1133+
if (in_transaction)
1134+
{
1135+
my_b_printf(&print_event_info->head_cache,
1136+
"ROLLBACK /* added by mysqlbinlog */ %s\n",
1137+
print_event_info->delimiter);
1138+
}
1139+
else if (print_event_info->is_gtid_next_set &&
1140+
print_event_info->is_gtid_next_valid)
1141+
{
1142+
/*
1143+
If we are here, then we have seen only GTID_LOG_EVENT
1144+
of a transaction and did not see even a BEGIN event
1145+
(in_transaction flag is false). So generate BEGIN event
1146+
also along with ROLLBACK event.
1147+
*/
1148+
my_b_printf(&print_event_info->head_cache,
1149+
"BEGIN /*added by mysqlbinlog */ %s\n"
1150+
"ROLLBACK /* added by mysqlbinlog */ %s\n",
1151+
print_event_info->delimiter,
1152+
print_event_info->delimiter);
1153+
}
1154+
}
10981155
if (head->error == -1)
10991156
goto err;
11001157
if (opt_remote_proto == BINLOG_LOCAL)
@@ -1342,7 +1399,21 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
13421399
Fake rotate events have 'when' set to zero. @c fake_rotate_event(...).
13431400
*/
13441401
bool is_fake= (rev->common_header->when.tv_sec == 0);
1345-
if (!in_transaction && !is_fake)
1402+
/*
1403+
'in_transaction' flag is not set to true even after GTID_LOG_EVENT
1404+
of a transaction is seen. ('mysqlbinlog' tool assumes that there
1405+
is only one event per DDL transaction other than BEGIN and COMMIT
1406+
events. Using 'in_transaction' flag and 'starts_group', 'ends_group'
1407+
flags, DDL transaction generation is handled. Hence 'in_transaction'
1408+
cannot be set to true after seeing GTID_LOG_EVENT). So in order to
1409+
see if we are out of a transaction or not, we should check that
1410+
'in_transaction' is false and we have not seen GTID_LOG_EVENT.
1411+
To see if a GTID_LOG_EVENT of a transaction is seen or not,
1412+
we should check is_gtid_next_valid flag is false.
1413+
*/
1414+
if (!is_fake && !in_transaction &&
1415+
print_event_info->is_gtid_next_set &&
1416+
!print_event_info->is_gtid_next_valid)
13461417
{
13471418
/*
13481419
If processing multiple files, we must reset this flag,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
CREATE TABLE t1(i INT) ENGINE=InnoDB;
7+
INSERT INTO t1 VALUES (1);
8+
include/sync_slave_sql_with_master.inc
9+
SET @save_debug=@@global.debug;
10+
SET GLOBAL DEBUG='d,stop_io_after_reading_gtid_log_event';
11+
[connection master]
12+
INSERT INTO t1 VALUES (2);
13+
[connection slave]
14+
include/wait_for_slave_io_to_stop.inc
15+
include/assert.inc [Slave MASTER_AUTO_POSITION should be enabled for this test]
16+
SET GLOBAL DEBUG= @save_debug;
17+
include/start_slave.inc
18+
[connection master]
19+
include/sync_slave_sql_with_master.inc
20+
DROP TABLE t1;
21+
RESET MASTER;
22+
include/assert.inc [Check that there is one tuple in the table]
23+
DROP TABLE t1;
24+
RESET MASTER;
25+
include/assert.inc [Check that there are two tuples in the table]
26+
[connection master]
27+
DROP TABLE t1;
28+
include/rpl_end.inc
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
############################################################################
2+
# Bug #17650326 MYSQLBINLOG PRINTS INVALID SQL FROM RELAY LOGS WHEN GTID IS
3+
# ENABLED
4+
# Problem: Replaying a relaylog which ends with GTID_LOG_EVENT causes error
5+
# "ERROR 1790 (HY000) @@SESSION.GTID_NEXT cannot be changed by a client that
6+
# owns a GTID. The client owns <UUID:GNO>. Ownership is released on COMMIT
7+
# or ROLLBACK."
8+
#
9+
# Steps to reproduce:
10+
# 1) Stop IO thread after reading gtid_log_event (relaylog 1 contains
11+
# GTID_LOG_EVENT at the end)
12+
# 2) Restart IO thread which rotates relaylog file (relaylog 2)
13+
# 3) Replay relaylog1's 'mysqlbinlog' output against 'mysql' client tool,
14+
# it should not cause any problems.
15+
# 4) Replay (relaylog1 + relaylog2)'s 'mysqlbinlog' output against
16+
# 'mysql' client tool, it should not cause any problems.
17+
#
18+
############################################################################
19+
--source include/have_debug.inc
20+
# This test is not need against MTS setup
21+
--source include/not_mts_slave_parallel_workers.inc
22+
--source include/have_gtid.inc
23+
--source include/have_binlog_format_statement.inc
24+
--source include/master-slave.inc
25+
26+
# Initial setup
27+
CREATE TABLE t1(i INT) ENGINE=InnoDB;
28+
INSERT INTO t1 VALUES (1);
29+
--source include/sync_slave_sql_with_master.inc
30+
--let MYSQLD_DATADIR=`select @@datadir`
31+
SET @save_debug=@@global.debug;
32+
33+
# Step 1: Stop I/O thread after reading GTID_LOG_EVENT
34+
# This will leave the relaylog in incomplete state(i.e., it ends
35+
# with GTID_LOG_EVENT)
36+
SET GLOBAL DEBUG='d,stop_io_after_reading_gtid_log_event';
37+
38+
--source include/rpl_connection_master.inc
39+
INSERT INTO t1 VALUES (2);
40+
41+
--source include/rpl_connection_slave.inc
42+
--source include/wait_for_slave_io_to_stop.inc
43+
--let $relay_file1 = query_get_value( SHOW SLAVE STATUS, Relay_Log_File, 1 )
44+
45+
--let $auto_pos = query_get_value( SHOW SLAVE STATUS, Auto_Position, 1 )
46+
--let $assert_text= Slave MASTER_AUTO_POSITION should be enabled for this test
47+
--let $assert_cond= $auto_pos= 1
48+
--source include/assert.inc
49+
50+
# Step 2: Restart I/O thread and execute the pending INSERT(2)
51+
SET GLOBAL DEBUG= @save_debug;
52+
--source include/start_slave.inc
53+
54+
--source include/rpl_connection_master.inc
55+
--source include/sync_slave_sql_with_master.inc
56+
--let $relay_file2 = query_get_value( SHOW SLAVE STATUS, Relay_Log_File, 1 )
57+
58+
# Step 3: Replay the incomplete Relaylog's mysqlbinlog output against mysql and see that
59+
# there are no issues.
60+
DROP TABLE t1;
61+
RESET MASTER;
62+
--exec $MYSQL_BINLOG --force-if-open $MYSQLD_DATADIR/$relay_file1 | $MYSQL -uroot -S$SLAVE_MYSOCK
63+
64+
--let $assert_text= Check that there is one tuple in the table
65+
--let $assert_cond= [SELECT COUNT(*) AS Val FROM t1 where i=1, Val, 1] = 1
66+
--source include/assert.inc
67+
68+
# Step 4: Concat two relay logs and then replay mysqlbinlog ouput against mysql and see
69+
# that there are no issues.
70+
DROP TABLE t1;
71+
RESET MASTER;
72+
--exec $MYSQL_BINLOG --force-if-open $MYSQLD_DATADIR/$relay_file1 $MYSQLD_DATADIR/$relay_file2 | $MYSQL -uroot -S$SLAVE_MYSOCK
73+
74+
--let $assert_text= Check that there are two tuples in the table
75+
--let $assert_cond= [SELECT COUNT(*) AS Val FROM t1 where i=1 or i=2, Val, 1] = 2
76+
--source include/assert.inc
77+
78+
# Cleanup
79+
--source include/rpl_connection_master.inc
80+
DROP TABLE t1;
81+
--source include/rpl_end.inc

sql/log_event.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -13831,7 +13831,7 @@ st_print_event_info::st_print_event_info()
1383113831
auto_increment_increment(0),auto_increment_offset(0), charset_inited(0),
1383213832
lc_time_names_number(~0),
1383313833
charset_database_number(ILLEGAL_CHARSET_INFO_NUMBER),
13834-
thread_id(0), thread_id_printed(false),
13834+
thread_id(0), thread_id_printed(false),server_id_from_fd_event(0),
1383513835
base64_output_mode(BASE64_OUTPUT_UNSPEC), printed_fd_event(FALSE),
1383613836
have_unflushed_events(false), skipped_event_in_transaction(false),
1383713837
is_gtid_next_set(false), is_gtid_next_valid(true)

sql/log_event.h

+1
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ typedef struct st_print_event_info
379379
uint charset_database_number;
380380
my_thread_id thread_id;
381381
bool thread_id_printed;
382+
uint32 server_id_from_fd_event;
382383

383384
st_print_event_info();
384385

0 commit comments

Comments
 (0)