Skip to content
/ server Public

Commit d5db6c1

Browse files
hemantdangi-gcvuvova
authored andcommitted
MDL BF-BF conflict on ALTER and INSERT with multi-level foreign key parents
Issue: On galera write node INSERT statements does not acquire MDL locks on it's all child tables and thereby wsrep certification keys are also added for limited tables, but on applier nodes it does acquire MDL locks for all child tables. This can result into MDL BF-BF conflict on applier node when transactions referring to parent and child tables are executed concurrently. For example: Tables with foreign keys: t1<-t2<-t3<-t4 Conflicting transactions: INSERT t1 and DROP TABLE t4 Wsrep certification keys taken on write node: - for INSERT t1: t1 and t2 - for DROP TABLE t4: t4 On applier node MDL BF-BF conflict happened between two transaction because MDL locks on t1, t2, t3 and t4 were taken for INSERT t1, which conflicted with MDL lock on t4 taken by DROP TABLE t4. The Wsrep certification keys helps in resolving this MDL BF-BF conflict by prioritizing and scheduling concurrent transactions. But to generate Wsrep certification keys it needs to open and take MDL locks on all the child tables. On applier nodes Write_rows event is implicitly a REPLACE, deleting all conflicting rows which can cause cascading FK actions and locks on foreign key children tables. Solution: For Galera applier nodes the Write_rows event is considered pure INSERT which will never cause cascading FK actions and locks on foreign key children tables.
1 parent 4802bfe commit d5db6c1

15 files changed

+720
-202
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
connection node_2;
2+
connection node_1;
3+
#
4+
# 1. LOCK TABLE and INSERT
5+
#
6+
connection node_1;
7+
CREATE TABLE t1 (
8+
id varchar(100),
9+
PRIMARY KEY (id)) engine=innodb;
10+
CREATE TABLE t2 (
11+
id varchar(100) , a varchar(100),
12+
PRIMARY KEY (id,a),
13+
KEY a (a),
14+
CONSTRAINT FOREIGN KEY (a) REFERENCES t1 (id)
15+
) ENGINE=InnoDB;
16+
CREATE TABLE t3 (
17+
a varchar(100),
18+
b varchar(100) ,
19+
PRIMARY KEY (a, b),
20+
CONSTRAINT FOREIGN KEY (a) REFERENCES t2 (a)
21+
) ENGINE=InnoDB;
22+
LOCK TABLES t1 WRITE;
23+
INSERT INTO t1 VALUES ('a');
24+
UNLOCK TABLES;
25+
connection node_2;
26+
select * from t1;
27+
id
28+
a
29+
connection node_1;
30+
select * from t1;
31+
id
32+
a
33+
DROP TABLE t3, t2, t1;
34+
#
35+
# 2. FLUSH TABLES WITH READ LOCK and INSERT
36+
#
37+
connection node_1;
38+
CREATE TABLE t1 (
39+
id varchar(100),
40+
PRIMARY KEY (id)) engine=innodb;
41+
CREATE TABLE t2 (
42+
id varchar(100) , a varchar(100),
43+
PRIMARY KEY (id,a),
44+
KEY a (a),
45+
CONSTRAINT FOREIGN KEY (a) REFERENCES t1 (id)
46+
) ENGINE=InnoDB;
47+
CREATE TABLE t3 (
48+
a varchar(100),
49+
b varchar(100) ,
50+
PRIMARY KEY (a, b),
51+
CONSTRAINT FOREIGN KEY (a) REFERENCES t2 (a)
52+
) ENGINE=InnoDB;
53+
FLUSH TABLES WITH READ LOCK;
54+
INSERT INTO t1 VALUES ('a');
55+
ERROR HY000: Can't execute the query because you have a conflicting read lock
56+
UNLOCK TABLES;
57+
connection node_2;
58+
select * from t1;
59+
id
60+
connection node_1;
61+
select * from t1;
62+
id
63+
DROP TABLE t3, t2, t1;

mysql-test/suite/galera/r/galera_multi_level_fk_ddl_insert.result

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ connection node_2;
4848
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
4949
SET SESSION wsrep_sync_wait = 0;
5050
connection node_1;
51-
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
5251
START TRANSACTION;
5352
INSERT INTO t1 VALUES (3,0);
5453
COMMIT;
@@ -62,10 +61,6 @@ connection node_1;
6261
SET DEBUG_SYNC = 'RESET';
6362
SET GLOBAL DEBUG_DBUG = "";
6463
SET GLOBAL wsrep_slave_threads=DEFAULT;
65-
connection node_1;
66-
include/assert_grep.inc [Foreign key referenced table found: 2 tables]
67-
include/assert_grep.inc [Foreign key referenced table found: test.t2]
68-
include/assert_grep.inc [Foreign key referenced table found: test.t3]
6964
connection node_2;
7065
select * from t1;
7166
id f2
@@ -146,7 +141,6 @@ connection node_2;
146141
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
147142
SET SESSION wsrep_sync_wait = 0;
148143
connection node_1;
149-
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
150144
START TRANSACTION;
151145
INSERT INTO t1 VALUES (3,0);
152146
COMMIT;
@@ -160,11 +154,6 @@ connection node_1;
160154
SET DEBUG_SYNC = 'RESET';
161155
SET GLOBAL DEBUG_DBUG = "";
162156
SET GLOBAL wsrep_slave_threads=DEFAULT;
163-
connection node_1;
164-
include/assert_grep.inc [Foreign key referenced table found: 3 tables]
165-
include/assert_grep.inc [Foreign key referenced table found: test.t2]
166-
include/assert_grep.inc [Foreign key referenced table found: test.t3]
167-
include/assert_grep.inc [Foreign key referenced table found: test.t4]
168157
connection node_2;
169158
select * from t1;
170159
id f2
@@ -233,7 +222,6 @@ connection node_2;
233222
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
234223
SET SESSION wsrep_sync_wait = 0;
235224
connection node_1;
236-
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
237225
START TRANSACTION;
238226
INSERT INTO t1 VALUES (3,0);
239227
COMMIT;
@@ -247,11 +235,6 @@ connection node_1;
247235
SET DEBUG_SYNC = 'RESET';
248236
SET GLOBAL DEBUG_DBUG = "";
249237
SET GLOBAL wsrep_slave_threads=DEFAULT;
250-
connection node_1;
251-
include/assert_grep.inc [Foreign key referenced table found: 2 tables]
252-
include/assert_grep.inc [Foreign key referenced table found: test.t2]
253-
include/assert_grep.inc [Foreign key referenced table found: test.t3]
254-
include/assert_grep.inc [Foreign key referenced table found: test.t4]
255238
connection node_2;
256239
select * from t1;
257240
id f2
@@ -323,7 +306,6 @@ connection node_2;
323306
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
324307
SET SESSION wsrep_sync_wait = 0;
325308
connection node_1;
326-
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
327309
START TRANSACTION;
328310
INSERT INTO t1 VALUES (3,0);
329311
COMMIT;
@@ -337,10 +319,6 @@ connection node_1;
337319
SET DEBUG_SYNC = 'RESET';
338320
SET GLOBAL DEBUG_DBUG = "";
339321
SET GLOBAL wsrep_slave_threads=DEFAULT;
340-
connection node_1;
341-
include/assert_grep.inc [Foreign key referenced table found: 1 tables]
342-
include/assert_grep.inc [Foreign key referenced table found: test.t2]
343-
include/assert_grep.inc [Foreign key referenced table found: test.t3]
344322
connection node_2;
345323
select * from t1;
346324
id f2
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#
2+
# MDEV-38216 was failing after MDEV-25039 changes.
3+
#
4+
5+
--source include/galera_cluster.inc
6+
--source include/have_innodb.inc
7+
--source include/have_debug.inc
8+
--source include/have_debug_sync.inc
9+
--source include/have_perfschema.inc
10+
11+
--echo #
12+
--echo # 1. LOCK TABLE and INSERT
13+
--echo #
14+
15+
#
16+
# Setup
17+
#
18+
--connection node_1
19+
CREATE TABLE t1 (
20+
id varchar(100),
21+
PRIMARY KEY (id)) engine=innodb;
22+
23+
CREATE TABLE t2 (
24+
id varchar(100) , a varchar(100),
25+
PRIMARY KEY (id,a),
26+
KEY a (a),
27+
CONSTRAINT FOREIGN KEY (a) REFERENCES t1 (id)
28+
) ENGINE=InnoDB;
29+
30+
CREATE TABLE t3 (
31+
a varchar(100),
32+
b varchar(100) ,
33+
PRIMARY KEY (a, b),
34+
CONSTRAINT FOREIGN KEY (a) REFERENCES t2 (a)
35+
) ENGINE=InnoDB;
36+
37+
LOCK TABLES t1 WRITE;
38+
INSERT INTO t1 VALUES ('a');
39+
UNLOCK TABLES;
40+
41+
42+
#
43+
# Verify insert has succeded.
44+
#
45+
--connection node_2
46+
--let $wait_condition = SELECT COUNT(*) = 1 FROM test.t1
47+
--source include/wait_condition.inc
48+
49+
select * from t1;
50+
51+
--connection node_1
52+
select * from t1;
53+
54+
55+
#
56+
# Cleanup
57+
#
58+
DROP TABLE t3, t2, t1;
59+
60+
61+
--echo #
62+
--echo # 2. FLUSH TABLES WITH READ LOCK and INSERT
63+
--echo #
64+
65+
#
66+
# Setup
67+
#
68+
--connection node_1
69+
CREATE TABLE t1 (
70+
id varchar(100),
71+
PRIMARY KEY (id)) engine=innodb;
72+
73+
CREATE TABLE t2 (
74+
id varchar(100) , a varchar(100),
75+
PRIMARY KEY (id,a),
76+
KEY a (a),
77+
CONSTRAINT FOREIGN KEY (a) REFERENCES t1 (id)
78+
) ENGINE=InnoDB;
79+
80+
CREATE TABLE t3 (
81+
a varchar(100),
82+
b varchar(100) ,
83+
PRIMARY KEY (a, b),
84+
CONSTRAINT FOREIGN KEY (a) REFERENCES t2 (a)
85+
) ENGINE=InnoDB;
86+
87+
FLUSH TABLES WITH READ LOCK;
88+
--error ER_CANT_UPDATE_WITH_READLOCK
89+
INSERT INTO t1 VALUES ('a');
90+
UNLOCK TABLES;
91+
92+
93+
#
94+
# Verify insert has succeded.
95+
#
96+
--connection node_2
97+
--let $wait_condition = SELECT COUNT(*) = 0 FROM test.t1
98+
--source include/wait_condition.inc
99+
100+
select * from t1;
101+
102+
--connection node_1
103+
select * from t1;
104+
105+
106+
#
107+
# Cleanup
108+
#
109+
DROP TABLE t3, t2, t1;

0 commit comments

Comments
 (0)