Commit c69357d8 authored by Jan Lindström's avatar Jan Lindström

MDEV-15611 Due to the failure of foreign key detection, Galera slave node killed himself.

Merge following change from 10.2

revision-id: d52cff9f10aeea208a1058f7b5527e602125584c (mariadb-10.2.14-25-gd52cff9)
parent(s): bc250145
author: Sachin Setiya
committer: Sachin Setiya
timestamp: 2018-04-04 12:26:06 +0530
message:

MDEV-15611 Due to the failure of foreign key detection, Galera...
slave node killed himself.

Problem:- If we try to delete table with foreign key and table whom it is
referring with wsrep_slave_threads>1 then galera tries to execute both
Delete_rows_log-event in parallel, which should not happen.

Solution:- This is happening because we do not have foreign key info in
write set. Upto version 10.2.7 it used to work fine. Actually it happening
because of issue in commit 2f342c45. wsrep_must_process_fk should be used
with negation.
parent f4387288
CREATE TABLE t1 (
id int primary key
);
CREATE TABLE t2 (
id int primary key ,
f_id int DEFAULT NULL, FOREIGN KEY(f_id) REFERENCES t1 (id)
);
insert into t1 select 1;
#Running 200 insert in t2 table
select count(*) from t2;
count(*)
200
delete from t2;
delete from t1;
drop table t2,t1;
!include ../galera_2nodes.cnf
[mysqld.1]
[mysqld.2]
wsrep_slave_threads=6
--source include/galera_cluster.inc
--source include/have_innodb.inc
--connection node_1
CREATE TABLE t1 (
id int primary key
);
CREATE TABLE t2 (
id int primary key ,
f_id int DEFAULT NULL, FOREIGN KEY(f_id) REFERENCES t1 (id)
);
insert into t1 select 1;
--disable_query_log
--let $count=200
--echo #Running 200 insert in t2 table
while($count)
{
#Repeatedly execute the following SQL until you generate thousands of data
--eval insert into t2 values ($count, 1);
--dec $count
}
--enable_query_log
select count(*) from t2;
delete from t2;
delete from t1;
drop table t2,t1;
......@@ -1803,6 +1803,23 @@ row_upd_store_row(
}
}
#ifdef WITH_WSREP
/** Determine if a FOREIGN KEY constraint needs to be processed.
@param[in] node query node
@param[in] trx transaction
@return whether the node cannot be ignored */
inline bool wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx)
{
if (!wsrep_on_trx(trx)) {
return false;
}
return que_node_get_type(node->common.parent) != QUE_NODE_UPDATE
|| static_cast<upd_node_t*>(node->common.parent)->cascade_node
!= node;
}
#endif /* WITH_WSREP */
/***********************************************************//**
Updates a secondary index entry of a row.
@return DB_SUCCESS if operation successfully completed, else error
......@@ -1833,7 +1850,7 @@ row_upd_sec_index_entry(
referenced = row_upd_index_is_referenced(index, trx);
#ifdef WITH_WSREP
ibool foreign = wsrep_row_upd_index_is_foreign(index, trx);
bool foreign = wsrep_row_upd_index_is_foreign(index, trx);
#endif /* WITH_WSREP */
heap = mem_heap_create(1024);
......@@ -1962,61 +1979,61 @@ row_upd_sec_index_entry(
row_ins_sec_index_entry() below */
if (!rec_get_deleted_flag(
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(
0, btr_cur, TRUE, thr, &mtr);
if (err == DB_SUCCESS && referenced) {
ulint* offsets;
offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
if (err != DB_SUCCESS) {
break;
}
#ifdef WITH_WSREP
if (err == DB_SUCCESS && !referenced &&
wsrep_on_trx(trx) &&
!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
!(parent && que_node_get_type(parent) ==
QUE_NODE_UPDATE &&
((upd_node_t*)parent)->cascade_node == node) &&
foreign
) {
ulint* offsets =
rec_get_offsets(
if (!referenced && foreign
&& wsrep_must_process_fk(node, trx)
&& !wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
ulint* offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
err = wsrep_row_upd_check_foreign_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
if (wsrep_debug) fprintf (stderr,
"WSREP: sec index FK check fail for deadlock");
if (wsrep_debug) {
ib_logf(IB_LOG_LEVEL_WARN,
"WSREP: sec index FK check fail for deadlock: "
" index %s table %s", index->name, index->table->name);
}
break;
default:
fprintf (stderr,
"WSREP: referenced FK check fail: %d",
(int)err);
ib_logf(IB_LOG_LEVEL_ERROR,
"WSREP: referenced FK check fail: %s index %s table %s",
ut_strerr(err), index->name, index->table->name);
break;
}
}
#endif /* WITH_WSREP */
}
break;
if (referenced) {
ulint* offsets;
offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
}
btr_pcur_close(&pcur);
......@@ -2185,9 +2202,6 @@ row_upd_clust_rec_by_insert(
rec_t* rec;
ulint* offsets = NULL;
#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
#endif /* WITH_WSREP */
ut_ad(node);
ut_ad(dict_index_is_clust(index));
......@@ -2269,35 +2283,31 @@ row_upd_clust_rec_by_insert(
if (err != DB_SUCCESS) {
goto err_exit;
}
}
#ifdef WITH_WSREP
if (!referenced && wsrep_on_trx(trx) &&
!(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
((upd_node_t*)parent)->cascade_node == node) &&
foreign
) {
} else if ((foreign && wsrep_must_process_fk(node, trx))) {
err = wsrep_row_upd_check_foreign_constraints(
node, pcur, table, index, offsets, thr, mtr);
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
if (wsrep_debug) fprintf (stderr,
"WSREP: insert FK check fail for deadlock");
if (wsrep_debug) {
ib_logf(IB_LOG_LEVEL_WARN,
"WSREP: sec index FK check fail for deadlock: "
" index %s table %s", index->name, index->table->name);
}
break;
default:
fprintf (stderr,
"WSREP: referenced FK check fail: %d",
(int)err);
ib_logf(IB_LOG_LEVEL_ERROR,
"WSREP: referenced FK check fail: %s index %s table %s",
ut_strerr(err), index->name, index->table->name);
break;
}
if (err != DB_SUCCESS) {
goto err_exit;
}
}
#endif /* WITH_WSREP */
}
}
mtr_commit(mtr);
......@@ -2500,7 +2510,7 @@ row_upd_del_mark_clust_rec(
dberr_t err;
#ifdef WITH_WSREP
rec_t* rec;
que_node_t *parent = que_node_get_parent(node);
trx_t* trx = thr_get_trx(thr) ;
#endif /* WITH_WSREP */
ut_ad(node);
......@@ -2529,38 +2539,37 @@ row_upd_del_mark_clust_rec(
btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur),
#endif /* WITH_WSREP */
index, offsets, thr, mtr);
if (err == DB_SUCCESS && referenced) {
if (err != DB_SUCCESS) {
} else if (referenced) {
/* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
#ifdef WITH_WSREP
trx_t* trx = thr_get_trx(thr) ;
if (err == DB_SUCCESS && !referenced && wsrep_on_trx(trx) &&
!(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
((upd_node_t*)parent)->cascade_node == node) &&
foreign
) {
} else if (foreign && wsrep_must_process_fk(node, trx)) {
err = wsrep_row_upd_check_foreign_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
if (wsrep_debug) fprintf (stderr,
"WSREP: clust rec FK check fail for deadlock");
if (wsrep_debug) {
ib_logf(IB_LOG_LEVEL_WARN,
"WSREP: sec index FK check fail for deadlock: "
" index %s table %s", index->name, index->table->name);
}
break;
default:
fprintf (stderr,
"WSREP: clust rec referenced FK check fail: %d",
(int)err);
ib_logf(IB_LOG_LEVEL_ERROR,
"WSREP: referenced FK check fail: %s index %s table %s",
ut_strerr(err), index->name, index->table->name);
break;
}
}
#endif /* WITH_WSREP */
}
mtr_commit(mtr);
......
......@@ -1806,6 +1806,23 @@ row_upd_store_row(
}
}
#ifdef WITH_WSREP
/** Determine if a FOREIGN KEY constraint needs to be processed.
@param[in] node query node
@param[in] trx transaction
@return whether the node cannot be ignored */
inline bool wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx)
{
if (!wsrep_on_trx(trx)) {
return false;
}
return que_node_get_type(node->common.parent) != QUE_NODE_UPDATE
|| static_cast<upd_node_t*>(node->common.parent)->cascade_node
!= node;
}
#endif /* WITH_WSREP */
/***********************************************************//**
Updates a secondary index entry of a row.
@return DB_SUCCESS if operation successfully completed, else error
......@@ -1836,7 +1853,7 @@ row_upd_sec_index_entry(
referenced = row_upd_index_is_referenced(index, trx);
#ifdef WITH_WSREP
ibool foreign = wsrep_row_upd_index_is_foreign(index, trx);
bool foreign = wsrep_row_upd_index_is_foreign(index, trx);
#endif /* WITH_WSREP */
heap = mem_heap_create(1024);
......@@ -1968,61 +1985,61 @@ row_upd_sec_index_entry(
row_ins_sec_index_entry() below */
if (!rec_get_deleted_flag(
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(
0, btr_cur, TRUE, thr, &mtr);
if (err == DB_SUCCESS && referenced) {
ulint* offsets;
offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
if (err != DB_SUCCESS) {
break;
}
#ifdef WITH_WSREP
if (err == DB_SUCCESS && !referenced &&
wsrep_on_trx(trx) &&
!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
!(parent && que_node_get_type(parent) ==
QUE_NODE_UPDATE &&
((upd_node_t*)parent)->cascade_node == node) &&
foreign
) {
ulint* offsets =
rec_get_offsets(
if (!referenced && foreign
&& wsrep_must_process_fk(node, trx)
&& !wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
ulint* offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
err = wsrep_row_upd_check_foreign_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
if (wsrep_debug) fprintf (stderr,
"WSREP: sec index FK check fail for deadlock");
if (wsrep_debug) {
ib_logf(IB_LOG_LEVEL_WARN,
"WSREP: sec index FK check fail for deadlock: "
" index %s table %s", index->name, index->table->name);
}
break;
default:
fprintf (stderr,
"WSREP: referenced FK check fail: %d",
(int)err);
ib_logf(IB_LOG_LEVEL_ERROR,
"WSREP: referenced FK check fail: %s index %s table %s",
ut_strerr(err), index->name, index->table->name);
break;
}
}
#endif /* WITH_WSREP */
}
break;
if (referenced) {
ulint* offsets;
offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
}
btr_pcur_close(&pcur);
......@@ -2191,9 +2208,6 @@ row_upd_clust_rec_by_insert(
rec_t* rec;
ulint* offsets = NULL;
#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
#endif /* WITH_WSREP */
ut_ad(node);
ut_ad(dict_index_is_clust(index));
......@@ -2278,35 +2292,31 @@ row_upd_clust_rec_by_insert(
if (err != DB_SUCCESS) {
goto err_exit;
}
}
#ifdef WITH_WSREP
if (!referenced && wsrep_on_trx(trx) &&
!(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
((upd_node_t*)parent)->cascade_node == node) &&
foreign
) {
} else if ((foreign && wsrep_must_process_fk(node, trx))) {
err = wsrep_row_upd_check_foreign_constraints(
node, pcur, table, index, offsets, thr, mtr);
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
if (wsrep_debug) fprintf (stderr,
"WSREP: insert FK check fail for deadlock");
if (wsrep_debug) {
ib_logf(IB_LOG_LEVEL_WARN,
"WSREP: sec index FK check fail for deadlock: "
" index %s table %s", index->name, index->table->name);
}
break;
default:
fprintf (stderr,
"WSREP: referenced FK check fail: %d",
(int)err);
ib_logf(IB_LOG_LEVEL_ERROR,
"WSREP: referenced FK check fail: %s index %s table %s",
ut_strerr(err), index->name, index->table->name);
break;
}
if (err != DB_SUCCESS) {
goto err_exit;
}
}
#endif /* WITH_WSREP */
}
}
mtr_commit(mtr);
......@@ -2512,7 +2522,7 @@ row_upd_del_mark_clust_rec(
dberr_t err;
#ifdef WITH_WSREP
rec_t* rec;
que_node_t *parent = que_node_get_parent(node);
trx_t* trx = thr_get_trx(thr) ;
#endif /* WITH_WSREP */
ut_ad(node);
......@@ -2541,38 +2551,37 @@ row_upd_del_mark_clust_rec(
btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur),
#endif /* WITH_WSREP */
index, offsets, thr, mtr);
if (err == DB_SUCCESS && referenced) {
if (err != DB_SUCCESS) {
} else if (referenced) {
/* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
#ifdef WITH_WSREP
trx_t* trx = thr_get_trx(thr) ;
if (err == DB_SUCCESS && !referenced && wsrep_on_trx(trx) &&
!(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
((upd_node_t*)parent)->cascade_node == node) &&
foreign
) {
} else if (foreign && wsrep_must_process_fk(node, trx)) {
err = wsrep_row_upd_check_foreign_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
if (wsrep_debug) fprintf (stderr,
"WSREP: clust rec FK check fail for deadlock");
if (wsrep_debug) {
ib_logf(IB_LOG_LEVEL_WARN,
"WSREP: sec index FK check fail for deadlock: "
" index %s table %s", index->name, index->table->name);
}
break;
default:
fprintf (stderr,
"WSREP: clust rec referenced FK check fail: %d",
(int)err);
ib_logf(IB_LOG_LEVEL_ERROR,
"WSREP: referenced FK check fail: %s index %s table %s",
ut_strerr(err), index->name, index->table->name);
break;
}
}
#endif /* WITH_WSREP */
}
mtr_commit(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