diff options
author | sjaakola <seppo.jaakola@iki.fi> | 2020-11-04 13:42:18 +0200 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2020-11-11 17:46:50 +0200 |
commit | ad432ef4c0b81cf796f9b1f66848a3cde6becf77 (patch) | |
tree | 0bf96ebee710d3de2dfe105de7fad6a92c313e95 | |
parent | 99a9774754ea8c4e309589a2dbc7847e16e1fbde (diff) | |
download | mariadb-git-ad432ef4c0b81cf796f9b1f66848a3cde6becf77.tar.gz |
MDEV-24119 MDL BF-BF Conflict caused by TRUNCATE TABLE
This PR fixes same issue as MDEV-21577 for TRUNCATE TABLE.
MDEV-21577 fixed TOI replication for OPTIMIZE, REPAIR and ALTER TABLE
operating on FK child table. It was later found out that also TRUNCATE
has similar problem and needs a fix.
The actual fix is to do FK parent table lookup before TRUNCATE TOI
isolation and append found FK parent table names in certification key
list for the write set.
PR contains also new test scenario in galera_ddl_fk_conflict test where
FK child has two FK parent tables and there are two DML transactions operating
on both parent tables.
For development convenience, new TO isolation macro was added:
WSREP_TO_ISOLATION_BEGIN_IF and WSREP_TO_ISOLATION_BEGIN_ALTER macro was changed
to skip the goto statement.
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
-rw-r--r-- | include/wsrep.h | 10 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/galera_ddl_fk_conflict.result | 437 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc | 100 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_ddl_fk_conflict.test | 10 | ||||
-rw-r--r-- | sql/sql_admin.cc | 4 | ||||
-rw-r--r-- | sql/sql_alter.cc | 11 | ||||
-rw-r--r-- | sql/sql_truncate.cc | 20 |
7 files changed, 512 insertions, 80 deletions
diff --git a/include/wsrep.h b/include/wsrep.h index 65cceba1065..5272b687732 100644 --- a/include/wsrep.h +++ b/include/wsrep.h @@ -23,15 +23,17 @@ #define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A) #define WSREP_MYSQL_DB (char *)"mysql" -#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ +#define WSREP_TO_ISOLATION_BEGIN_IF(db_, table_, table_list_) \ + if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) + +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ goto wsrep_error_label; #define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_) \ if (WSREP(thd) && wsrep_thd_is_local(thd) && \ wsrep_to_isolation_begin(thd, db_, table_, \ - table_list_, alter_info_, fk_tables_)) \ - goto wsrep_error_label; + table_list_, alter_info_, fk_tables_)) #define WSREP_TO_ISOLATION_END \ if ((WSREP(thd) && wsrep_thd_is_local_toi(thd)) || \ @@ -48,7 +50,7 @@ #define WSREP_TO_ISOLATION_BEGIN_FK_TABLES(db_, table_, table_list_, fk_tables) \ if (WSREP(thd) && !thd->lex->no_write_to_binlog \ - && wsrep_to_isolation_begin(thd, db_, table_, table_list_, NULL, fk_tables)) goto wsrep_error_label; + && wsrep_to_isolation_begin(thd, db_, table_, table_list_, NULL, fk_tables)) #define WSREP_DEBUG(...) \ if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__) diff --git a/mysql-test/suite/galera/r/galera_ddl_fk_conflict.result b/mysql-test/suite/galera/r/galera_ddl_fk_conflict.result index a39fa6a6219..f0d0d61e58f 100644 --- a/mysql-test/suite/galera/r/galera_ddl_fk_conflict.result +++ b/mysql-test/suite/galera/r/galera_ddl_fk_conflict.result @@ -3,6 +3,9 @@ connection node_1; connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; connection node_1a; SET SESSION wsrep_sync_wait=0; +connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1b; +SET SESSION wsrep_sync_wait=0; ###################################################################### # Test for OPTIMIZE ###################################################################### @@ -14,29 +17,39 @@ SET SESSION wsrep_sync_wait=0; ###################################################################### connection node_1; SET SESSION wsrep_sync_wait=0; -CREATE TABLE p (pk INTEGER PRIMARY KEY, f2 CHAR(30)); -INSERT INTO p VALUES (1, 'INITIAL VALUE'); -INSERT INTO p VALUES (2, 'INITIAL VALUE'); -CREATE TABLE c (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p(pk)); -INSERT INTO c VALUES (1,1), (2,2); +CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p1 VALUES (1, 'INITIAL VALUE'); +CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p2 VALUES (1, 'INITIAL VALUE'); +INSERT INTO p2 VALUES (2, 'INITIAL VALUE'); +CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk)); +INSERT INTO c1 VALUES (1,1); +CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk)); +INSERT INTO c2 VALUES (1,1,1), (2,1,2); connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; connection node_2; SET SESSION wsrep_sync_wait=0; -OPTIMIZE TABLE c ; +OPTIMIZE TABLE c1 ; Table Op Msg_type Msg_text -test.c optimize note Table does not support optimize, doing recreate + analyze instead -test.c optimize status OK +test.c1 optimize note Table does not support optimize, doing recreate + analyze instead +test.c1 optimize status OK connection node_1; COMMIT; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 ###################################################################### @@ -49,16 +62,63 @@ connection node_1; BEGIN; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; connection node_2; -OPTIMIZE TABLE c ; +OPTIMIZE TABLE c1 ; +Table Op Msg_type Msg_text +test.c1 optimize note Table does not support optimize, doing recreate + analyze instead +test.c1 optimize status OK +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +COMMIT; +connection node_1a; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +connection node_2; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +###################################################################### +# +# Scenario #3: 2 DMLs working on two FK parent tables try to replicate, +# but fails in certification for earlier DDL on child table +# which is child to both FK parents +# +###################################################################### +connection node_1; +BEGIN; +connection node_1b; +BEGIN; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +OPTIMIZE TABLE c2 ; Table Op Msg_type Msg_text -test.c optimize note Table does not support optimize, doing recreate + analyze instead -test.c optimize status OK +test.c2 optimize note Table does not support optimize, doing recreate + analyze instead +test.c2 optimize status OK connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +COMMIT; +connection node_1b; +UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2; COMMIT; connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; @@ -67,15 +127,26 @@ ERROR 40001: Deadlock found when trying to get lock; try restarting transaction SELECT 'I deadlocked'; I deadlocked I deadlocked -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +connection node_1b; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 -DROP TABLE c; -DROP TABLE p; +DROP TABLE c1, c2; +DROP TABLE p1, p2; ###################################################################### # Test for REPAIR ###################################################################### @@ -87,28 +158,38 @@ DROP TABLE p; ###################################################################### connection node_1; SET SESSION wsrep_sync_wait=0; -CREATE TABLE p (pk INTEGER PRIMARY KEY, f2 CHAR(30)); -INSERT INTO p VALUES (1, 'INITIAL VALUE'); -INSERT INTO p VALUES (2, 'INITIAL VALUE'); -CREATE TABLE c (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p(pk)); -INSERT INTO c VALUES (1,1), (2,2); +CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p1 VALUES (1, 'INITIAL VALUE'); +CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p2 VALUES (1, 'INITIAL VALUE'); +INSERT INTO p2 VALUES (2, 'INITIAL VALUE'); +CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk)); +INSERT INTO c1 VALUES (1,1); +CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk)); +INSERT INTO c2 VALUES (1,1,1), (2,1,2); connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; connection node_2; SET SESSION wsrep_sync_wait=0; -REPAIR TABLE c ; +REPAIR TABLE c1 ; Table Op Msg_type Msg_text -test.c repair note The storage engine for the table doesn't support repair +test.c1 repair note The storage engine for the table doesn't support repair connection node_1; COMMIT; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 ###################################################################### @@ -121,15 +202,15 @@ connection node_1; BEGIN; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; connection node_2; -REPAIR TABLE c ; +REPAIR TABLE c1 ; Table Op Msg_type Msg_text -test.c repair note The storage engine for the table doesn't support repair +test.c1 repair note The storage engine for the table doesn't support repair connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; COMMIT; connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; @@ -138,15 +219,72 @@ ERROR 40001: Deadlock found when trying to get lock; try restarting transaction SELECT 'I deadlocked'; I deadlocked I deadlocked -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 -DROP TABLE c; -DROP TABLE p; +###################################################################### +# +# Scenario #3: 2 DMLs working on two FK parent tables try to replicate, +# but fails in certification for earlier DDL on child table +# which is child to both FK parents +# +###################################################################### +connection node_1; +BEGIN; +connection node_1b; +BEGIN; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +REPAIR TABLE c2 ; +Table Op Msg_type Msg_text +test.c2 repair note The storage engine for the table doesn't support repair +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +COMMIT; +connection node_1b; +UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2; +COMMIT; +connection node_1a; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +connection node_1b; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +connection node_2; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +DROP TABLE c1, c2; +DROP TABLE p1, p2; ###################################################################### # Test for ALTER ENGINE=INNODB ###################################################################### @@ -158,26 +296,168 @@ DROP TABLE p; ###################################################################### connection node_1; SET SESSION wsrep_sync_wait=0; -CREATE TABLE p (pk INTEGER PRIMARY KEY, f2 CHAR(30)); -INSERT INTO p VALUES (1, 'INITIAL VALUE'); -INSERT INTO p VALUES (2, 'INITIAL VALUE'); -CREATE TABLE c (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p(pk)); -INSERT INTO c VALUES (1,1), (2,2); +CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p1 VALUES (1, 'INITIAL VALUE'); +CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p2 VALUES (1, 'INITIAL VALUE'); +INSERT INTO p2 VALUES (2, 'INITIAL VALUE'); +CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk)); +INSERT INTO c1 VALUES (1,1); +CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk)); +INSERT INTO c2 VALUES (1,1,1), (2,1,2); +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +connection node_2; +SET SESSION wsrep_sync_wait=0; +ALTER TABLE c1 ENGINE=INNODB; +connection node_1; +COMMIT; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +connection node_2; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +###################################################################### +# +# Scenario #2: DML working on FK parent table tries to replicate, but +# fails in certification for earlier DDL on child table +# +###################################################################### +connection node_1; +BEGIN; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +ALTER TABLE c1 ENGINE=INNODB; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +COMMIT; +connection node_1a; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +connection node_2; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +###################################################################### +# +# Scenario #3: 2 DMLs working on two FK parent tables try to replicate, +# but fails in certification for earlier DDL on child table +# which is child to both FK parents +# +###################################################################### +connection node_1; +BEGIN; +connection node_1b; +BEGIN; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +ALTER TABLE c2 ENGINE=INNODB; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +COMMIT; +connection node_1b; +UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2; +COMMIT; +connection node_1a; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +connection node_1b; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +connection node_2; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +DROP TABLE c1, c2; +DROP TABLE p1, p2; +###################################################################### +# Test for TRUNCATE +###################################################################### +###################################################################### +# +# Scenario #1: DML working on FK parent table BF aborted by DDL +# over child table +# +###################################################################### +connection node_1; +SET SESSION wsrep_sync_wait=0; +CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p1 VALUES (1, 'INITIAL VALUE'); +CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p2 VALUES (1, 'INITIAL VALUE'); +INSERT INTO p2 VALUES (2, 'INITIAL VALUE'); +CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk)); +INSERT INTO c1 VALUES (1,1); +CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk)); +INSERT INTO c2 VALUES (1,1,1), (2,1,2); connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; connection node_2; SET SESSION wsrep_sync_wait=0; -ALTER TABLE c ENGINE=INNODB; +TRUNCATE TABLE c1 ; connection node_1; COMMIT; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 ###################################################################### @@ -190,13 +470,13 @@ connection node_1; BEGIN; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; connection node_2; -ALTER TABLE c ENGINE=INNODB; +TRUNCATE TABLE c1 ; connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; COMMIT; connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; @@ -205,12 +485,67 @@ ERROR 40001: Deadlock found when trying to get lock; try restarting transaction SELECT 'I deadlocked'; I deadlocked I deadlocked -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +connection node_2; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; +EXPECT_2 +2 +###################################################################### +# +# Scenario #3: 2 DMLs working on two FK parent tables try to replicate, +# but fails in certification for earlier DDL on child table +# which is child to both FK parents +# +###################################################################### +connection node_1; +BEGIN; +connection node_1b; +BEGIN; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +TRUNCATE TABLE c2 ; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +COMMIT; +connection node_1b; +UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2; +COMMIT; +connection node_1a; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +connection node_1b; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SELECT 'I deadlocked'; +I deadlocked +I deadlocked +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +EXPECT_1 +1 +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; EXPECT_2 2 -DROP TABLE c; -DROP TABLE p; +DROP TABLE c1, c2; +DROP TABLE p1, p2; diff --git a/mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc b/mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc index 18271d0b641..4a473d3776c 100644 --- a/mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc +++ b/mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc @@ -40,31 +40,40 @@ --connection node_1 SET SESSION wsrep_sync_wait=0; -CREATE TABLE p (pk INTEGER PRIMARY KEY, f2 CHAR(30)); -INSERT INTO p VALUES (1, 'INITIAL VALUE'); -INSERT INTO p VALUES (2, 'INITIAL VALUE'); +CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p1 VALUES (1, 'INITIAL VALUE'); -CREATE TABLE c (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p(pk)); -INSERT INTO c VALUES (1,1), (2,2); + +CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30)); +INSERT INTO p2 VALUES (1, 'INITIAL VALUE'); +INSERT INTO p2 VALUES (2, 'INITIAL VALUE'); + +CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk)); +INSERT INTO c1 VALUES (1,1); + +CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk)); +INSERT INTO c2 VALUES (1,1,1), (2,1,2); --connection node_1 SET AUTOCOMMIT=ON; START TRANSACTION; -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; --connection node_2 SET SESSION wsrep_sync_wait=0; ---eval $table_admin_command TABLE c $table_admin_command_end +--eval $table_admin_command TABLE c1 $table_admin_command_end --connection node_1 --error ER_LOCK_DEADLOCK COMMIT; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; --connection node_2 -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; --echo ###################################################################### --echo # @@ -81,7 +90,7 @@ BEGIN; --source include/galera_set_sync_point.inc --connection node_2 ---eval $table_admin_command TABLE c $table_admin_command_end +--eval $table_admin_command TABLE c1 $table_admin_command_end --connection node_1a --source include/galera_wait_sync_point.inc @@ -89,7 +98,62 @@ BEGIN; --let $expected_cert_failures = `SELECT VARIABLE_VALUE+1 FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'` --connection node_1 -UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +--send COMMIT + +--connection node_1a +--let $galera_sync_point = apply_monitor_slave_enter_sync +--source include/galera_signal_sync_point.inc + +--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures' +--source include/wait_condition.inc + +--connection node_1 +--error ER_LOCK_DEADLOCK +--reap + +SELECT 'I deadlocked'; + +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; + +--connection node_2 +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; + + +--echo ###################################################################### +--echo # +--echo # Scenario #3: 2 DMLs working on two FK parent tables try to replicate, +--echo # but fails in certification for earlier DDL on child table +--echo # which is child to both FK parents +--echo # +--echo ###################################################################### + +--connection node_1 +BEGIN; + +--connection node_1b +BEGIN; + +# Block the applier on node #1 and issue DDL on node 2 +--let $galera_sync_point = apply_monitor_slave_enter_sync +--source include/galera_set_sync_point.inc + +--connection node_2 +--eval $table_admin_command TABLE c2 $table_admin_command_end + +--connection node_1a +--source include/galera_wait_sync_point.inc +--source include/galera_clear_sync_point.inc +--let $expected_cert_failures = `SELECT VARIABLE_VALUE+2 FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'` + +--connection node_1 +UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1; +--send COMMIT + +--connection node_1b +UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2; --send COMMIT --connection node_1a @@ -102,13 +166,19 @@ UPDATE p SET f2 = 'TO DEADLOCK' WHERE pk = 1; --connection node_1 --error ER_LOCK_DEADLOCK --reap +SELECT 'I deadlocked'; +--connection node_1b +--error ER_LOCK_DEADLOCK +--reap SELECT 'I deadlocked'; -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; --connection node_2 -SELECT COUNT(*) AS EXPECT_2 FROM p WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE'; +SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE'; -DROP TABLE c; -DROP TABLE p; +DROP TABLE c1, c2; +DROP TABLE p1, p2; diff --git a/mysql-test/suite/galera/t/galera_ddl_fk_conflict.test b/mysql-test/suite/galera/t/galera_ddl_fk_conflict.test index a07006a8e49..c6d20e3bffd 100644 --- a/mysql-test/suite/galera/t/galera_ddl_fk_conflict.test +++ b/mysql-test/suite/galera/t/galera_ddl_fk_conflict.test @@ -7,10 +7,16 @@ --source include/have_debug_sync.inc --source include/galera_have_debug_sync.inc +# sync point controlling session --connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 --connection node_1a SET SESSION wsrep_sync_wait=0; +# secondary conflicting DML victim session +--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1b +SET SESSION wsrep_sync_wait=0; + --let $table_admin_command = OPTIMIZE --source galera_ddl_fk_conflict.inc @@ -21,5 +27,9 @@ SET SESSION wsrep_sync_wait=0; --let $table_admin_command_end = ENGINE=INNODB --source galera_ddl_fk_conflict.inc +--let $table_admin_command = TRUNCATE +--let $table_admin_command_end = +--source galera_ddl_fk_conflict.inc + # CHECK and ANALYZE are not affected diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index ebd0e9b39aa..c13d61d9f7a 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -453,7 +453,9 @@ static bool wsrep_toi_replication(THD *thd, TABLE_LIST *tables) { WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, tables); } else { - WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, tables, &keys); + WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, tables, &keys) { + return true; + } } return false; diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index cefd37811a2..2bbc8169df2 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -480,7 +480,11 @@ bool Sql_cmd_alter_table::execute(THD *thd) WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : NULL), (lex->name.str ? lex->name.str : NULL), - first_table, &alter_info, &keys); + first_table, &alter_info, &keys) + { + WSREP_WARN("ALTER TABLE isolation failure"); + DBUG_RETURN(TRUE); + } thd->variables.auto_increment_offset = 1; thd->variables.auto_increment_increment = 1; @@ -522,11 +526,6 @@ bool Sql_cmd_alter_table::execute(THD *thd) lex->ignore); DBUG_RETURN(result); -#ifdef WITH_WSREP -wsrep_error_label: - WSREP_WARN("ALTER TABLE isolation failure"); - DBUG_RETURN(TRUE); -#endif } bool Sql_cmd_discard_import_tablespace::execute(THD *thd) diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index bfcdda6e0e9..c3d347307a2 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -416,9 +416,23 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) bool hton_can_recreate; #ifdef WITH_WSREP - if (WSREP(thd) && - wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, 0)) - DBUG_RETURN(TRUE); + if (WSREP(thd)) + { + wsrep::key_array keys; + wsrep_append_fk_parent_table(thd, table_ref, &keys); + if (keys.empty()) + { + WSREP_TO_ISOLATION_BEGIN_IF(table_ref->db.str, table_ref->table_name.str, NULL) + { + DBUG_RETURN(TRUE); + } + } else { + WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, table_ref, &keys) + { + DBUG_RETURN(TRUE); + } + } + } #endif /* WITH_WSREP */ if (lock_table(thd, table_ref, &hton_can_recreate)) DBUG_RETURN(TRUE); |