Skip to content

Commit e5ae7aa

Browse files
author
Libing Song
committed
BUG#21045848 XA+MEMORY TABLE: POST SERVER RESTART 'XA COMMIT'
IS OVERRIDDEN BY 'DELETE' CMD ANALYSIS ======== Memory table's data will be lost after server restarts. To keep the data consistency between master and slave, it just binlogs 'DELETE FROM `db`.`table_name`' when the memory table is locked first time. So DELETE statement could be binlogged in many statements. Because it was put into binlog statement cache of current session, so it could cause below troubles: - COM_FIELD_LIST it doesn't flush binlog cache to binlog file. So the DELETEs were not binlogged in COM_FIELD_LIST, it was binlogged with next statement together. - CREATE TABLE ... LIKE memory_table - CREATE TABLE ... SELECT memory_table They were binlogged like: GTID_log_event | Anonymous_gtid_log_event DELETE FROM memory_table CREATE TABLE ... LIKE memory_table | CREATE TABLE ... SELECT memory_table Both statements shared the same gtid event. That was not correct. - DELETE was binlogged without BEGIN and COMMIT It caused some DML binlogged without BEGIN and COMMIT e.g. INSERT INTO myisam_t1 SELECT * FROM memory_table it was binlogged as: GTID_log_event | Anonymous_gtid_log_event DELETE FROM memory_table INSERT INTO myisam_t1 SELECT * FROM memory_table FIX === To fix it, each DELETE will be binlogged separately and wrapped by BEGIN/COMMIT pair. It is flush to binlog immediately after it is written into binlog statement cache. E.g. INSERT INTO myisam_t1 SELECT * FROM memory_table will be binlogged as: GTID_log_event | Anonymous_gtid_log_event Query_log_event BEGIN Query_log_event DELETE FROM memory_table Query_log_event COMMIT GTID_log_event | Anonymous_gtid_log_event Query_log_event BEGIN Query_log_event INSERT INTO myisam_t1 SELECT * FROM memory_table Xid_log_event It also added a debug option build_completion_hash to mysql for test purpose.
1 parent c4ce65c commit e5ae7aa

9 files changed

+550
-7
lines changed

client/mysql.cc

+34-2
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,25 @@ static const CHARSET_INFO *charset_info= &my_charset_latin1;
201201

202202
const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
203203

204+
/*
205+
completion_hash is an auxiliary feature for mysql client to complete
206+
an object name(db name, table name and field name) automatically.
207+
e.g.
208+
mysql> use my_d
209+
then press <TAB>, it will check the hash and complete the db name
210+
for users.
211+
the result will be:
212+
mysql> use my_dbname
213+
214+
In general, this feature is only on when it is an interactive mysql client.
215+
It is not possible to use it in test case.
216+
217+
For using this feature in test case, we add the option in debug code.
218+
*/
219+
#ifndef DBUG_OFF
220+
static my_bool opt_build_completion_hash = FALSE;
221+
#endif
222+
204223
#ifdef _WIN32
205224
/*
206225
A flag that indicates if --execute buffer has already been converted,
@@ -1862,6 +1881,13 @@ static struct my_option my_long_options[] =
18621881
"password sandbox mode.",
18631882
&opt_connect_expired_password, &opt_connect_expired_password, 0, GET_BOOL,
18641883
NO_ARG, 0, 0, 0, 0, 0, 0},
1884+
#ifndef DBUG_OFF
1885+
{"build-completion-hash", 0,
1886+
"Build completion hash even when it is in batch mode. It is used for "
1887+
"test purpose, so it is just built when DEBUG is on.",
1888+
&opt_build_completion_hash, &opt_build_completion_hash, 0, GET_BOOL,
1889+
NO_ARG, 0, 0, 0, 0, 0, 0},
1890+
#endif
18651891
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
18661892
};
18671893

@@ -2955,8 +2981,14 @@ static void build_completion_hash(bool rehash, bool write_info)
29552981
int i,j,num_fields;
29562982
DBUG_ENTER("build_completion_hash");
29572983

2958-
if (status.batch || quick || !current_db)
2959-
DBUG_VOID_RETURN; // We don't need completion in batches
2984+
#ifndef DBUG_OFF
2985+
if (!opt_build_completion_hash)
2986+
#endif
2987+
{
2988+
if (status.batch || quick || !current_db)
2989+
DBUG_VOID_RETURN; // We don't need completion in batches
2990+
}
2991+
29602992
if (!rehash)
29612993
DBUG_VOID_RETURN;
29622994

mysql-test/include/assert_binlog_events.inc

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ if ($binlog_position)
162162
{
163163
--let $statement= $statement FROM $binlog_position
164164
}
165-
if ($limit)
165+
if ($limit != "")
166166
{
167167
--let $statement= $statement LIMIT $limit
168168
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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("Found 1 prepared XA transactions");
7+
CREATE DATABASE db1;
8+
CREATE DATABASE db2;
9+
CREATE TABLE t1(c1 INT);
10+
CREATE TABLE t2(c1 INT);
11+
CREATE TABLE mem_t1(c1 INT PRIMARY KEY) ENGINE = MEMORY;
12+
CREATE TABLE mem_t2(c1 INT PRIMARY KEY) ENGINE = MEMORY;
13+
CREATE TABLE db1.mem_t1(c1 INT PRIMARY KEY) ENGINE = MEMORY;
14+
CREATE TABLE db1.mem_t2(c1 INT PRIMARY KEY) ENGINE = MEMORY;
15+
CREATE TABLE db2.mem_t1(c1 INT PRIMARY KEY) ENGINE = MEMORY;
16+
CREATE TABLE db2.mem_t2(c1 INT PRIMARY KEY) ENGINE = MEMORY;
17+
CREATE TABLE db2.mem_t3(c1 INT PRIMARY KEY) ENGINE = MEMORY;
18+
CREATE TABLE db2.mem_t4(c1 INT PRIMARY KEY) ENGINE = MEMORY;
19+
CREATE TABLE db2.mem_t5(c1 INT PRIMARY KEY) ENGINE = MEMORY;
20+
CREATE TRIGGER tr1 AFTER INSERT ON t2 FOR EACH ROW
21+
BEGIN
22+
INSERT INTO t1 SELECT * FROM db2.mem_t3;
23+
END |
24+
INSERT INTO mem_t1 VALUES(1),(2),(3);
25+
INSERT INTO mem_t2 VALUES(1),(2),(3);
26+
INSERT INTO db1.mem_t1 VALUES(1),(2),(3);
27+
INSERT INTO db1.mem_t2 VALUES(1),(2),(3);
28+
INSERT INTO db2.mem_t1 VALUES(1),(2),(3);
29+
INSERT INTO db2.mem_t2 VALUES(1),(2),(3);
30+
INSERT INTO db2.mem_t3 VALUES(1),(2),(3);
31+
INSERT INTO db2.mem_t4 VALUES(1),(2),(3);
32+
INSERT INTO db2.mem_t5 VALUES(1),(2),(3);
33+
include/sync_slave_sql_with_master.inc
34+
include/stop_slave_io.inc
35+
[connection master]
36+
XA START 'xa1';
37+
INSERT INTO t1 VALUES(1);
38+
XA END 'xa1';
39+
XA PREPARE 'xa1';
40+
include/save_master_pos.inc
41+
include/rpl_restart_server.inc [server_number=1]
42+
[connection slave]
43+
include/start_slave_io.inc
44+
include/sync_slave_sql.inc
45+
#
46+
# Test case 1: verify XA COMMIT can be binlogged correctly.
47+
#
48+
[connection master]
49+
include/gtid_step_reset.inc
50+
include/save_binlog_position.inc
51+
include/gtid_step_assert.inc [count=3, only_count=0]
52+
include/assert_binlog_events.inc [Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT # Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
53+
include/sync_slave_sql_with_master.inc
54+
include/rpl_diff.inc
55+
#
56+
# Test case 2: verify COM_FIELD_LIST can binlog DELETE FROM mem_xx
57+
# correctly
58+
#
59+
[connection master]
60+
include/gtid_step_reset.inc
61+
include/gtid_step_assert.inc [count=2, only_count=0]
62+
include/sync_slave_sql_with_master.inc
63+
SELECT * FROM mem_t1;
64+
c1
65+
SELECT * FROM mem_t2;
66+
c1
67+
#
68+
# Test case 3: verify DELETE FROM mem_xx can be binlogged correctly
69+
# in CREATE TABLE ... LIKE
70+
[connection master]
71+
include/gtid_step_reset.inc
72+
include/save_binlog_position.inc
73+
CREATE TABLE t3 LIKE db2.mem_t1;
74+
include/gtid_step_assert.inc [count=2, only_count=0]
75+
include/assert_binlog_events.inc [Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
76+
include/sync_slave_sql_with_master.inc
77+
SELECT * FROM db2.mem_t1;
78+
c1
79+
#
80+
# Test case 4: verify DELETE FROM mem_xx can be binlogged correctly
81+
# in DML
82+
[connection master]
83+
include/gtid_step_reset.inc
84+
include/save_binlog_position.inc
85+
INSERT INTO t3 SELECT * FROM db2.mem_t2 UNION SELECT 10;
86+
include/gtid_step_assert.inc [count=2, only_count=0]
87+
include/assert_binlog_events.inc [Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
88+
include/sync_slave_sql_with_master.inc
89+
SELECT * FROM db2.mem_t2;
90+
c1
91+
#
92+
# Test case 5: verify DELETE FROM mem_xx can be binlogged correctly
93+
# in a trigger
94+
[connection master]
95+
include/gtid_step_reset.inc
96+
include/save_binlog_position.inc
97+
INSERT INTO t2 VALUES(11);
98+
include/gtid_step_assert.inc [count=2, only_count=0]
99+
include/assert_binlog_events.inc [Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
100+
include/sync_slave_sql_with_master.inc
101+
SELECT * FROM db2.mem_t3;
102+
c1
103+
#
104+
# Test case 6: Verify DELETE FROM mem_xx can be binlog correctly
105+
# when ALTER the memory table.
106+
[connection master]
107+
include/gtid_step_reset.inc
108+
include/save_binlog_position.inc
109+
ALTER TABLE db2.mem_t4 ADD COLUMN c2 INT;
110+
include/gtid_step_assert.inc [count=2, only_count=0]
111+
include/assert_binlog_events.inc [Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
112+
include/sync_slave_sql_with_master.inc
113+
SELECT * FROM db2.mem_t4;
114+
c1 c2
115+
#
116+
# Test case 7: Verify DELETE FROM mem_xx can be binlog correctly
117+
# when DROP the memory table.
118+
[connection master]
119+
include/gtid_step_reset.inc
120+
DROP TABLE db2.mem_t5;
121+
include/gtid_step_assert.inc [count=1, only_count=0]
122+
include/sync_slave_sql_with_master.inc
123+
[connection master]
124+
DROP TABLE t1, t2, t3, mem_t1, mem_t2;
125+
DROP DATABASE db1;
126+
DROP DATABASE db2;
127+
include/rpl_end.inc
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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("Found 1 prepared XA transactions");
7+
CREATE TABLE t1(c1 INT);
8+
CREATE TABLE t2(c1 INT) ENGINE = MyISAM;
9+
CREATE TABLE mem_t1(c1 INT PRIMARY KEY) ENGINE = MEMORY;
10+
CREATE TABLE mem_t2(c1 INT PRIMARY KEY) ENGINE = MEMORY;
11+
INSERT INTO mem_t1 VALUES(1),(2),(3);
12+
INSERT INTO mem_t2 VALUES(1),(2),(3);
13+
include/sync_slave_sql_with_master.inc
14+
include/rpl_restart_server.inc [server_number=1]
15+
# Test case 1: verify DELETE FROM mem_xx can be binlogged correctly
16+
# in CREATE TABLE ... SELECT
17+
[connection master]
18+
include/save_binlog_position.inc
19+
CREATE TABLE t3 SELECT * FROM mem_t1 UNION SELECT 10;
20+
include/assert_binlog_events.inc [Anonymous_Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
21+
include/sync_slave_sql_with_master.inc
22+
SELECT * FROM mem_t1;
23+
c1
24+
#
25+
# Test case 2: verify DELETE FROM mem_xx can be binlogged correctly
26+
# in a DML on a MyISAM table
27+
[connection master]
28+
include/save_binlog_position.inc
29+
INSERT INTO t2 SELECT * FROM mem_t2 UNION SELECT 10;
30+
include/assert_binlog_events.inc [Anonymous_Gtid # Query/.*BEGIN # Query/.*DELETE.* # Query/.*COMMIT]
31+
include/sync_slave_sql_with_master.inc
32+
SELECT * FROM mem_t2;
33+
c1
34+
[connection master]
35+
DROP TABLE t1, t2, t3, mem_t1, mem_t2;
36+
include/rpl_end.inc

0 commit comments

Comments
 (0)