-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDEV-12398 All cluster nodes stop due to a foreign key constraint fai…
…lure Comment from Codership:- To fix the problem, we changed the certification logic in galera to treat insert on child table row as exclusive to prevent any operation on referenced parent table row. At the same time, update and delete on child table row were demoted to "shared", which makes it possible to update/delete referenced parent table row, but only in a later transaction. This change allows somewhat more concurrency for foreign key constrained transactions, but is still safe for correct certification end result.
- Loading branch information
1 parent
472c2d9
commit e333d82
Showing
5 changed files
with
502 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; | ||
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, | ||
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ; | ||
INSERT INTO p VALUES (1, 0); | ||
INSERT INTO p VALUES (2, 0); | ||
SET AUTOCOMMIT=ON; | ||
START TRANSACTION; | ||
DELETE FROM p WHERE f1 = 1; | ||
SET SESSION wsrep_sync_wait = 0; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; | ||
INSERT INTO c VALUES (1, 1); | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; | ||
COMMIT; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction | ||
SELECT * FROM p; | ||
f1 f2 | ||
1 0 | ||
2 0 | ||
SELECT * FROM c; | ||
f1 p_id | ||
1 1 | ||
DROP TABLE c; | ||
DROP TABLE p; | ||
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; | ||
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, | ||
f2 INTEGER, | ||
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ; | ||
INSERT INTO p VALUES (1, 0); | ||
INSERT INTO p VALUES (2, 0); | ||
INSERT INTO c VALUES (1, 1, 0); | ||
SET AUTOCOMMIT=ON; | ||
START TRANSACTION; | ||
UPDATE p SET f2 = 1 WHERE f1 = 1; | ||
SET SESSION wsrep_sync_wait = 0; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; | ||
UPDATE c SET f2 = 1 WHERE f1 = 1; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; | ||
COMMIT; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SELECT * FROM p; | ||
f1 f2 | ||
1 1 | ||
2 0 | ||
SELECT * FROM c; | ||
f1 p_id f2 | ||
1 1 1 | ||
DROP TABLE c; | ||
DROP TABLE p; | ||
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; | ||
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, | ||
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ; | ||
INSERT INTO p VALUES (1, 0); | ||
INSERT INTO p VALUES (2, 0); | ||
INSERT INTO c VALUES (1, 1); | ||
SET AUTOCOMMIT=ON; | ||
START TRANSACTION; | ||
UPDATE p SET f2 = 1 WHERE f1 = 1; | ||
SET SESSION wsrep_sync_wait = 0; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; | ||
DELETE FROM c WHERE f1 = 1; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; | ||
COMMIT; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SELECT * FROM p; | ||
f1 f2 | ||
1 1 | ||
2 0 | ||
SELECT * FROM c; | ||
f1 p_id | ||
DROP TABLE c; | ||
DROP TABLE p; | ||
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER UNIQUE KEY) ENGINE=INNODB; | ||
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, | ||
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f2)) ; | ||
INSERT INTO p VALUES (1, 0); | ||
SET AUTOCOMMIT=ON; | ||
START TRANSACTION; | ||
UPDATE p SET f2 = 1 WHERE f1 = 1; | ||
SET SESSION wsrep_sync_wait = 0; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; | ||
INSERT INTO c VALUES (1, 0);; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; | ||
COMMIT; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction | ||
SELECT * FROM p; | ||
f1 f2 | ||
1 0 | ||
SELECT * FROM c; | ||
f1 p_id | ||
1 0 | ||
DROP TABLE c; | ||
DROP TABLE p; | ||
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; | ||
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, | ||
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) | ||
ON DELETE CASCADE) ; | ||
INSERT INTO p VALUES (1, 0); | ||
INSERT INTO p VALUES (2, 0); | ||
INSERT INTO c VALUES (1, 1, 0); | ||
SET AUTOCOMMIT=ON; | ||
START TRANSACTION; | ||
DELETE FROM p WHERE f1 = 1; | ||
SET SESSION wsrep_sync_wait = 0; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; | ||
UPDATE c SET f2 = 1 WHERE f1 = 1; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; | ||
COMMIT; | ||
SET SESSION wsrep_on = 0; | ||
SET SESSION wsrep_on = 1; | ||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; | ||
SET GLOBAL wsrep_provider_options = 'dbug='; | ||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction | ||
SELECT * FROM p; | ||
f1 f2 | ||
1 0 | ||
2 0 | ||
SELECT * FROM c; | ||
f1 p_id f2 | ||
1 1 1 | ||
DROP TABLE c; | ||
DROP TABLE p; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# | ||
# This file should be included from tests for MW-369 to run concurrent | ||
# transaction from node_1 with autocommit query from node_2. | ||
# | ||
# The parameters: | ||
# * $mw_369_parent_query - the parent query to be run inside transaction | ||
# * $mw_369_child_query - the child query | ||
# | ||
# The operations are the following: | ||
# | ||
# node_1: | ||
# START TRANSACTION; | ||
# $mw_369_parent_query | ||
# node_2 | ||
# $mw_369_child_query - will be blocked on node_1 in apply monitor | ||
# node_1: | ||
# COMMIT; - will be blocked on node_1 in local monitor | ||
# | ||
# The $mw_369_child_query is always expected to succeed. The caller is | ||
# responsible for checking if the final COMMIT on connection node_1 | ||
# succeeds. | ||
# | ||
|
||
--connection node_1 | ||
SET AUTOCOMMIT=ON; | ||
START TRANSACTION; | ||
|
||
--eval $mw_369_parent_query | ||
|
||
# | ||
# Block the $mw_369_child_query from node_2 | ||
# | ||
# --connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 | ||
--connection node_1a | ||
SET SESSION wsrep_sync_wait = 0; | ||
--let $galera_sync_point = apply_monitor_slave_enter_sync | ||
--source include/galera_set_sync_point.inc | ||
|
||
# | ||
# insert client row, which will make it impossible to replay the | ||
# delete on parent | ||
# | ||
--connection node_2 | ||
--eval $mw_369_child_query | ||
|
||
# | ||
# Wait until $mw_369_child_query from node_2 reaches the sync point and | ||
# block the 'COMMIT' from node_1 before it certifies. | ||
# | ||
--connection node_1a | ||
--source include/galera_wait_sync_point.inc | ||
--source include/galera_clear_sync_point.inc | ||
|
||
--let $galera_sync_point = local_monitor_enter_sync | ||
--source include/galera_set_sync_point.inc | ||
|
||
--connection node_1 | ||
--send COMMIT | ||
|
||
# | ||
# Wait until both sync points have been reached | ||
# | ||
--connection node_1a | ||
--let $galera_sync_point = apply_monitor_slave_enter_sync local_monitor_enter_sync | ||
--source include/galera_wait_sync_point.inc | ||
|
||
# | ||
# both threads are now parked in sync points, signal them to continue | ||
# | ||
--let $galera_sync_point = apply_monitor_slave_enter_sync | ||
--source include/galera_signal_sync_point.inc | ||
|
||
--let $galera_sync_point = local_monitor_enter_sync | ||
--source include/galera_signal_sync_point.inc | ||
--source include/galera_clear_sync_point.inc |
Oops, something went wrong.