Commit 3894fdd4 authored by Jan Lindström's avatar Jan Lindström

MDEV-13678: DELETE with CASCADE takes a long time when Galera is enabled

Ported fix from mysql-wsrep-bugs with some refactoring.

Test case is MW-402 where MariaDB needs record as there is
extra connection <con_name> lines.
parent d186b992
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, 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); CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON DELETE CASCADE);
INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0); INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1, 0); INSERT INTO c VALUES (1, 1, 0);
connection node_1a;
connection node_1;
SET AUTOCOMMIT=ON; SET AUTOCOMMIT=ON;
START TRANSACTION; START TRANSACTION;
UPDATE c SET f2=1 where f1=1; UPDATE c SET f2=1 where f1=1;
connection node_1a;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
DELETE FROM p WHERE f1 = 1; DELETE FROM p WHERE f1 = 1;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
connection node_1;
COMMIT; COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; 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 = 'signal=local_monitor_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_2;
SELECT * FROM p; SELECT * FROM p;
f1 f2 f1 f2
2 0 2 0
...@@ -28,29 +39,39 @@ SELECT * FROM c; ...@@ -28,29 +39,39 @@ SELECT * FROM c;
f1 p_id f2 f1 p_id f2
DROP TABLE c; DROP TABLE c;
DROP TABLE p; DROP TABLE p;
connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE); CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE);
INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0); INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1, 0); INSERT INTO c VALUES (1, 1, 0);
connection node_1a;
connection node_1;
SET AUTOCOMMIT=ON; SET AUTOCOMMIT=ON;
START TRANSACTION; START TRANSACTION;
UPDATE c SET f2=2 where f1=1; UPDATE c SET f2=2 where f1=1;
connection node_1a;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
UPDATE p set f1=11 WHERE f1 = 1; UPDATE p set f1=11 WHERE f1 = 1;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
connection node_1;
COMMIT; COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; 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 = 'signal=local_monitor_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_2;
SELECT * FROM p; SELECT * FROM p;
f1 f2 f1 f2
2 0 2 0
...@@ -60,29 +81,39 @@ f1 p_id f2 ...@@ -60,29 +81,39 @@ f1 p_id f2
1 11 0 1 11 0
DROP TABLE c; DROP TABLE c;
DROP TABLE p; DROP TABLE p;
connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE); CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE);
INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0); INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1, 0); INSERT INTO c VALUES (1, 1, 0);
connection node_1a;
connection node_1;
SET AUTOCOMMIT=ON; SET AUTOCOMMIT=ON;
START TRANSACTION; START TRANSACTION;
UPDATE c SET p_id=2 where f1=1; UPDATE c SET p_id=2 where f1=1;
connection node_1a;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
UPDATE p set f1=11 WHERE f1 = 1; UPDATE p set f1=11 WHERE f1 = 1;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
connection node_1;
COMMIT; COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; 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 = 'signal=local_monitor_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_2;
SELECT * FROM p; SELECT * FROM p;
f1 f2 f1 f2
2 0 2 0
...@@ -90,23 +121,32 @@ f1 f2 ...@@ -90,23 +121,32 @@ f1 f2
SELECT * FROM c; SELECT * FROM c;
f1 p_id f2 f1 p_id f2
1 11 0 1 11 0
connection node_1a;
connection node_1;
SET AUTOCOMMIT=ON; SET AUTOCOMMIT=ON;
START TRANSACTION; START TRANSACTION;
UPDATE p set f1=21 WHERE f1 = 11; UPDATE p set f1=21 WHERE f1 = 11;
connection node_1a;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
UPDATE c SET p_id=2 where f1=1; UPDATE c SET p_id=2 where f1=1;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
connection node_1;
COMMIT; COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; 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 = 'signal=local_monitor_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_2;
SELECT * FROM p; SELECT * FROM p;
f1 f2 f1 f2
2 0 2 0
...@@ -116,6 +156,7 @@ f1 p_id f2 ...@@ -116,6 +156,7 @@ f1 p_id f2
1 2 0 1 2 0
DROP TABLE c; DROP TABLE c;
DROP TABLE p; DROP TABLE p;
connection node_1;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER, f2 INTEGER, CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER, f2 INTEGER,
...@@ -124,22 +165,31 @@ CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)); ...@@ -124,22 +165,31 @@ CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1));
INSERT INTO p1 VALUES (1, 0); INSERT INTO p1 VALUES (1, 0);
INSERT INTO p2 VALUES (1, 0); INSERT INTO p2 VALUES (1, 0);
INSERT INTO c VALUES (1, 1, 1, 0); INSERT INTO c VALUES (1, 1, 1, 0);
connection node_1a;
connection node_1;
SET AUTOCOMMIT=ON; SET AUTOCOMMIT=ON;
START TRANSACTION; START TRANSACTION;
UPDATE p2 SET f2=2 where f1=1; UPDATE p2 SET f2=2 where f1=1;
connection node_1a;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
DELETE FROM p1 WHERE f1 = 1; DELETE FROM p1 WHERE f1 = 1;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
connection node_1;
COMMIT; COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1; SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; 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 = 'signal=local_monitor_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
connection node_2;
SELECT * FROM p1; SELECT * FROM p1;
f1 f2 f1 f2
SELECT * FROM p2; SELECT * FROM p2;
......
...@@ -460,14 +460,18 @@ wsrep_row_upd_check_foreign_constraints( ...@@ -460,14 +460,18 @@ wsrep_row_upd_check_foreign_constraints(
@param[in] node query node @param[in] node query node
@param[in] trx transaction @param[in] trx transaction
@return whether the node cannot be ignored */ @return whether the node cannot be ignored */
static inline
bool bool
wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx) wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx)
{ {
if (que_node_get_type(node->common.parent) != QUE_NODE_UPDATE ||
!wsrep_on(trx->mysql_thd)) {
return false;
}
const upd_node_t* parent = static_cast<const upd_node_t*>(node->common.parent); const upd_node_t* parent = static_cast<const upd_node_t*>(node->common.parent);
return (!parent || (que_node_get_type(parent) != QUE_NODE_UPDATE) || return parent->cascade_upd_nodes->empty();
parent->cascade_upd_nodes->empty());
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
...@@ -2430,10 +2434,6 @@ row_upd_sec_index_entry( ...@@ -2430,10 +2434,6 @@ row_upd_sec_index_entry(
if (!rec_get_deleted_flag( if (!rec_get_deleted_flag(
rec, dict_table_is_comp(index->table))) { rec, dict_table_is_comp(index->table))) {
#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
#endif /* WITH_WSREP */
err = btr_cur_del_mark_set_sec_rec( err = btr_cur_del_mark_set_sec_rec(
flags, btr_cur, TRUE, thr, &mtr); flags, btr_cur, TRUE, thr, &mtr);
...@@ -2442,8 +2442,9 @@ row_upd_sec_index_entry( ...@@ -2442,8 +2442,9 @@ row_upd_sec_index_entry(
} }
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (!referenced && foreign if (!referenced && foreign
&& wsrep_must_process_fk(node, trx) wsrep_must_process_fk(node, trx) &&
&& !wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { !wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
ulint* offsets = rec_get_offsets( ulint* offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED, rec, index, NULL, ULINT_UNDEFINED,
&heap); &heap);
...@@ -2662,9 +2663,6 @@ row_upd_clust_rec_by_insert( ...@@ -2662,9 +2663,6 @@ row_upd_clust_rec_by_insert(
rec_t* rec; rec_t* rec;
ulint* offsets = NULL; ulint* offsets = NULL;
#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
#endif /* WITH_WSREP */
ut_ad(node); ut_ad(node);
ut_ad(dict_index_is_clust(index)); ut_ad(dict_index_is_clust(index));
...@@ -2752,7 +2750,7 @@ row_upd_clust_rec_by_insert( ...@@ -2752,7 +2750,7 @@ row_upd_clust_rec_by_insert(
goto err_exit; goto err_exit;
} }
#ifdef WITH_WSREP #ifdef WITH_WSREP
} else if (foreign && wsrep_on(trx->mysql_thd) && } else if (foreign &&
wsrep_must_process_fk(node, trx)) { wsrep_must_process_fk(node, trx)) {
err = wsrep_row_upd_check_foreign_constraints( err = wsrep_row_upd_check_foreign_constraints(
...@@ -2971,10 +2969,6 @@ row_upd_del_mark_clust_rec( ...@@ -2971,10 +2969,6 @@ row_upd_del_mark_clust_rec(
ut_ad(dict_index_is_clust(index)); ut_ad(dict_index_is_clust(index));
ut_ad(node->is_delete); ut_ad(node->is_delete);
#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
#endif /* WITH_WSREP */
pcur = node->pcur; pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur); btr_cur = btr_pcur_get_btr_cur(pcur);
...@@ -3000,10 +2994,9 @@ row_upd_del_mark_clust_rec( ...@@ -3000,10 +2994,9 @@ row_upd_del_mark_clust_rec(
err = row_upd_check_references_constraints( err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr); node, pcur, index->table, index, offsets, thr, mtr);
#ifdef WITH_WSREP #ifdef WITH_WSREP
} else if (trx && wsrep_on(trx->mysql_thd) && } else if (trx &&
wsrep_must_process_fk(node, trx)) { wsrep_must_process_fk(node, trx)) {
err = wsrep_row_upd_check_foreign_constraints( err = wsrep_row_upd_check_foreign_constraints(
node, pcur, index->table, index, offsets, thr, mtr); node, pcur, index->table, index, offsets, thr, mtr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment