summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-07-24 16:07:00 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-07-24 16:07:00 +0300
commit7dc405f0523313546eeb7b30d6b534081dd9e3d8 (patch)
treefd5521885ad207d11d59a354c1c0307def3979e5
parenta18639f1a913b446f32d7fbe531aa0d5782cf720 (diff)
downloadmariadb-git-bb-10.5-MDEV-21175.tar.gz
WIP MDEV-21175 Remove dict_table_t::n_foreign_key_checks_runningbb-10.5-MDEV-21175
The counter dict_table_t::n_foreign_key_checks_running was a work-around for missing meta-data locking (MDL) on the SQL layer. ER_TABLE_IN_FK_CHECK: Replaced with ER_UNUSED_26. HA_ERR_TABLE_IN_FK_CHECK: Remove. dict_table_t: Remove inc_fk_checks(), dec_fk_checks(), n_foreign_key_checks_running. row_ins_check_foreign_constraints(), row_upd_check_references_constraints(): Do not acquire a shared dict_sys latch nor touch the reference counters. row_drop_table_for_mysql(): Make the checks stricter. We will still employ row_mysql_drop_list for TRUNCATE TABLE and for dropping internal tables related to FULLTEXT INDEX. So, this will not fix MDEV-21283 yet. MDEV-21602 CREATE TABLE…PRIMARY KEY…SELECT workaround causes DROP TABLE to ignore locks The error handling of CREATE…SELECT would invoke handler::delete_table() while still holding locks on the table, due to not having invoked handlerton::rollback first. InnoDB used to work around this as well. In MDEV-742 this was worked around further by breaking MDL, causing MDEV-22733.
-rw-r--r--include/handler_ername.h1
-rw-r--r--include/my_base.h4
-rw-r--r--mysql-test/suite/binlog/disabled.def2
-rw-r--r--mysql-test/suite/innodb/disabled.def2
-rw-r--r--mysql-test/suite/rpl/disabled.def6
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--storage/innobase/handler/ha_innodb.cc3
-rw-r--r--storage/innobase/include/db0err.h2
-rw-r--r--storage/innobase/include/dict0mem.h22
-rw-r--r--storage/innobase/row/row0ins.cc30
-rw-r--r--storage/innobase/row/row0mysql.cc53
-rw-r--r--storage/innobase/row/row0upd.cc12
-rw-r--r--storage/innobase/ut/ut0ut.cc2
14 files changed, 22 insertions, 125 deletions
diff --git a/include/handler_ername.h b/include/handler_ername.h
index fe55062e6fb..4b76ecb8d36 100644
--- a/include/handler_ername.h
+++ b/include/handler_ername.h
@@ -74,7 +74,6 @@
{ "HA_ERR_INDEX_COL_TOO_LONG", HA_ERR_INDEX_COL_TOO_LONG, "" },
{ "HA_ERR_INDEX_CORRUPT", HA_ERR_INDEX_CORRUPT, "" },
{ "HA_ERR_UNDO_REC_TOO_BIG", HA_ERR_UNDO_REC_TOO_BIG, "" },
-{ "HA_ERR_TABLE_IN_FK_CHECK", HA_ERR_TABLE_IN_FK_CHECK, "" },
{ "HA_ERR_ROW_NOT_VISIBLE", HA_ERR_ROW_NOT_VISIBLE, "" },
{ "HA_ERR_ABORTED_BY_USER", HA_ERR_ABORTED_BY_USER, "" },
{ "HA_ERR_DISK_FULL", HA_ERR_DISK_FULL, "" },
diff --git a/include/my_base.h b/include/my_base.h
index dc5b135628f..7706d8c4a17 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 1995, 2018, MariaDB Corporation.
+ Copyright (c) 1995, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -513,7 +513,7 @@ enum ha_base_keytype {
#define HA_ERR_INDEX_CORRUPT 180 /* Index corrupted */
#define HA_ERR_UNDO_REC_TOO_BIG 181 /* Undo log record too big */
#define HA_FTS_INVALID_DOCID 182 /* Invalid InnoDB Doc ID */
-#define HA_ERR_TABLE_IN_FK_CHECK 183 /* Table being used in foreign key check */
+/* #define HA_ERR_TABLE_IN_FK_CHECK 183 */ /* Table being used in foreign key check */
#define HA_ERR_TABLESPACE_EXISTS 184 /* The tablespace existed in storage engine */
#define HA_ERR_TOO_MANY_FIELDS 185 /* Table has too many columns */
#define HA_ERR_ROW_IN_WRONG_PARTITION 186 /* Row in wrong partition */
diff --git a/mysql-test/suite/binlog/disabled.def b/mysql-test/suite/binlog/disabled.def
index 424e5549541..1576e21af52 100644
--- a/mysql-test/suite/binlog/disabled.def
+++ b/mysql-test/suite/binlog/disabled.def
@@ -11,3 +11,5 @@
##############################################################################
binlog_truncate_innodb : BUG#11764459 2010-10-20 anitha Originally disabled due to BUG#42643. Product bug fixed, but test changes needed
binlog_spurious_ddl_errors : BUG#11761680 2013-01-18 astha Fixed on mysql-5.6 and trunk
+binlog_stm_mix_innodb_myisam : WIP: MDEV-21175/MDEV-21602
+binlog_row_mix_innodb_myisam : WIP: MDEV-21175/MDEV-21602
diff --git a/mysql-test/suite/innodb/disabled.def b/mysql-test/suite/innodb/disabled.def
index 4484417afce..6944c1bf034 100644
--- a/mysql-test/suite/innodb/disabled.def
+++ b/mysql-test/suite/innodb/disabled.def
@@ -12,3 +12,5 @@
create-index-debug : MDEV-13680 InnoDB may crash when btr_page_alloc() fails
innodb_force_recovery_rollback : MDEV-22889 InnoDB occasionally breaks ACID
+innodb_mysql : WIP: MDEV-21175/MDEV-21602
+xa_recovery : WIP: MDEV-21175/MDEV-21602/MDEV-22769 (MDEV-742 regression)
diff --git a/mysql-test/suite/rpl/disabled.def b/mysql-test/suite/rpl/disabled.def
index 640c4b56cd0..78a3e962e97 100644
--- a/mysql-test/suite/rpl/disabled.def
+++ b/mysql-test/suite/rpl/disabled.def
@@ -20,3 +20,9 @@ rpl_slave_grp_exec: MDEV-10514
rpl_auto_increment_update_failure : disabled for now
rpl_current_user : waits for MDEV-22374 fix
rpl_parallel2 : waits for MDEV-23089
+rpl_mixed_mixing_engines : WIP: MDEV-21175/MDEV-21602
+rpl_non_direct_mixed_mixing_engines : WIP: MDEV-21175/MDEV-21602
+rpl_non_direct_row_mixing_engines : WIP: MDEV-21175/MDEV-21602
+rpl_non_direct_stm_mixing_engines : WIP: MDEV-21175/MDEV-21602
+rpl_row_mixing_engines : WIP: MDEV-21175/MDEV-21602
+rpl_stm_mixing_engines : WIP: MDEV-21175/MDEV-21602
diff --git a/sql/handler.cc b/sql/handler.cc
index 58f1c60edf9..d96a800d284 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -486,7 +486,6 @@ int ha_init_errors(void)
SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID");
- SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE, "Too many words in a FTS phrase or proximity search");
SETMSG(HA_ERR_FK_DEPTH_EXCEEDED, "Foreign key cascade delete/update exceeds");
@@ -4186,9 +4185,6 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_UNDO_REC_TOO_BIG:
textno= ER_UNDO_RECORD_TOO_BIG;
break;
- case HA_ERR_TABLE_IN_FK_CHECK:
- textno= ER_TABLE_IN_FK_CHECK;
- break;
default:
{
/* The error was "unknown" to this function.
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 275dc1605d8..4f6ed2a8bfe 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6624,8 +6624,8 @@ ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC
ER_BINLOG_UNSAFE_INSERT_TWO_KEYS
eng "INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe"
-ER_TABLE_IN_FK_CHECK
- eng "Table is being used in foreign key check"
+ER_UNUSED_26
+ eng "You should never see it"
ER_UNUSED_1
eng "You should never see it"
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 67822d0b752..289eaf49ea6 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1854,9 +1854,6 @@ convert_error_code_to_mysql(
"InnoDB");
return(HA_ERR_INTERNAL_ERROR);
- case DB_TABLE_IN_FK_CHECK:
- return(HA_ERR_TABLE_IN_FK_CHECK);
-
case DB_TABLE_IS_BEING_USED:
return(HA_ERR_WRONG_COMMAND);
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index 6cfc63f4a9e..05d56734bd8 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -121,8 +121,6 @@ enum dberr_t {
DB_READ_ONLY, /*!< Update operation attempted in
a read-only transaction */
DB_FTS_INVALID_DOCID, /* FTS Doc ID cannot be zero */
- DB_TABLE_IN_FK_CHECK, /* table is being used in foreign
- key check */
DB_ONLINE_LOG_TOO_BIG, /*!< Modification log grew too big
during online index creation */
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 81a76ac8bab..50e9203a3e6 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1916,23 +1916,6 @@ struct dict_table_t {
return versioned() && cols[vers_start].mtype == DATA_INT;
}
- void inc_fk_checks()
- {
-#ifdef UNIV_DEBUG
- int32_t fk_checks=
-#endif
- n_foreign_key_checks_running++;
- ut_ad(fk_checks >= 0);
- }
- void dec_fk_checks()
- {
-#ifdef UNIV_DEBUG
- int32_t fk_checks=
-#endif
- n_foreign_key_checks_running--;
- ut_ad(fk_checks > 0);
- }
-
/** For overflow fields returns potential max length stored inline */
inline size_t get_overflow_field_local_len() const;
@@ -2110,11 +2093,6 @@ public:
loading child table into memory along with its parent table. */
unsigned fk_max_recusive_level:8;
- /** Count of how many foreign key check operations are currently being
- performed on the table. We cannot drop the table while there are
- foreign key checks running on it. */
- Atomic_counter<int32_t> n_foreign_key_checks_running;
-
/** Transactions whose view low limit is greater than this number are
not allowed to store to the MySQL query cache or retrieve from it.
When a trx with undo logs commits, it sets this to the value of the
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 0f1e8007d36..a3b176cf8d9 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -1539,8 +1539,6 @@ row_ins_check_foreign_constraint(
upd_node= NULL;
#endif /* WITH_WSREP */
- ut_ad(rw_lock_own(&dict_sys.latch, RW_LOCK_S));
-
err = DB_SUCCESS;
if (trx->check_foreigns == FALSE) {
@@ -1886,8 +1884,6 @@ do_possible_lock_wait:
thr->lock_state = QUE_THR_LOCK_ROW;
- check_table->inc_fk_checks();
-
lock_wait_suspend_thread(thr);
thr->lock_state = QUE_THR_LOCK_NOLOCK;
@@ -1899,8 +1895,6 @@ do_possible_lock_wait:
} else {
err = DB_LOCK_WAIT;
}
-
- check_table->dec_fk_checks();
}
exit_func:
@@ -1931,7 +1925,6 @@ row_ins_check_foreign_constraints(
dict_foreign_t* foreign;
dberr_t err;
trx_t* trx;
- ibool got_s_lock = FALSE;
DBUG_ASSERT(index->is_primary() == pk);
@@ -1959,32 +1952,9 @@ row_ins_check_foreign_constraints(
FALSE, FALSE, DICT_ERR_IGNORE_NONE);
}
- if (0 == trx->dict_operation_lock_mode) {
- got_s_lock = TRUE;
-
- row_mysql_freeze_data_dictionary(trx);
- }
-
- if (referenced_table) {
- foreign->foreign_table->inc_fk_checks();
- }
-
- /* NOTE that if the thread ends up waiting for a lock
- we will release dict_sys.latch temporarily!
- But the counter on the table protects the referenced
- table from being dropped while the check is running. */
-
err = row_ins_check_foreign_constraint(
TRUE, foreign, table, entry, thr);
- if (referenced_table) {
- foreign->foreign_table->dec_fk_checks();
- }
-
- if (got_s_lock) {
- row_mysql_unfreeze_data_dictionary(trx);
- }
-
if (ref_table != NULL) {
dict_table_close(ref_table, FALSE, FALSE);
}
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 296c273a779..9c62cbf28ac 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -2867,7 +2867,6 @@ row_discard_tablespace_begin(
if (table) {
dict_stats_wait_bg_to_stop_using_table(table, trx);
ut_a(!is_system_tablespace(table->space_id));
- ut_ad(!table->n_foreign_key_checks_running);
}
return(table);
@@ -3102,8 +3101,6 @@ row_discard_tablespace_for_mysql(
err = DB_ERROR;
} else {
- ut_ad(!table->n_foreign_key_checks_running);
-
bool fts_exist = (dict_table_has_fts_index(table)
|| DICT_TF2_FLAG_IS_SET(
table, DICT_TF2_FTS_HAS_DOC_ID));
@@ -3462,16 +3459,14 @@ row_drop_table_for_mysql(
}
}
- DBUG_EXECUTE_IF("row_drop_table_add_to_background", goto defer;);
-
- /* TODO: could we replace the counter n_foreign_key_checks_running
- with lock checks on the table? Acquire here an exclusive lock on the
- table, and rewrite lock0lock.cc and the lock wait in srv0srv.cc so that
- they can cope with the table having been dropped here? Foreign key
- checks take an IS or IX lock on the table. */
+ DBUG_EXECUTE_IF("row_drop_table_add_to_background", goto dbug_defer;);
- if (table->n_foreign_key_checks_running > 0) {
+ if (table->get_ref_count()) {
defer:
+ ut_ad(is_temp_name || strstr(table->name.m_name, "/FTS_"));
+#ifndef DBUG_OFF
+dbug_defer:
+#endif
/* Rename #sql-backup to #sql-ib if table has open ref count
while dropping the table. This scenario can happen
when purge thread is waiting for dict_sys.mutex so
@@ -3499,22 +3494,8 @@ defer:
goto funct_exit;
}
- /* Remove all locks that are on the table or its records, if there
- are no references to the table but it has record locks, we release
- the record locks unconditionally. One use case is:
-
- CREATE TABLE t2 (PRIMARY KEY (a)) SELECT * FROM t1;
-
- If after the user transaction has done the SELECT and there is a
- problem in completing the CREATE TABLE operation, MySQL will drop
- the table. InnoDB will create a new background transaction to do the
- actual drop, the trx instance that is passed to this function. To
- preserve existing behaviour we remove the locks but ideally we
- shouldn't have to. There should never be record locks on a table
- that is going to be dropped. */
-
- if (table->get_ref_count() > 0 || table->n_rec_locks > 0
- || lock_table_has_locks(table)) {
+ if (UNIV_UNLIKELY(table->n_rec_locks
+ || lock_table_has_locks(table))) {
goto defer;
}
@@ -4123,7 +4104,6 @@ row_rename_table_for_mysql(
ulint n_constraints_to_drop = 0;
ibool old_is_tmp, new_is_tmp;
pars_info_t* info = NULL;
- int retry;
bool aux_fts_rename = false;
char* is_part = NULL;
@@ -4235,23 +4215,6 @@ row_rename_table_for_mysql(
}
}
- /* Is a foreign key check running on this table? */
- for (retry = 0; retry < 100
- && table->n_foreign_key_checks_running > 0; ++retry) {
- row_mysql_unlock_data_dictionary(trx);
- os_thread_yield();
- row_mysql_lock_data_dictionary(trx);
- }
-
- if (table->n_foreign_key_checks_running > 0) {
- ib::error() << "In ALTER TABLE "
- << ut_get_name(trx, old_name)
- << " a FOREIGN KEY check is running. Cannot rename"
- " table.";
- err = DB_TABLE_IN_FK_CHECK;
- goto funct_exit;
- }
-
if (!table->is_temporary()) {
err = trx_undo_report_rename(trx, table);
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 2639f3ec7ea..2eca746bfb7 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -283,21 +283,9 @@ row_upd_check_references_constraints(
FALSE, FALSE, DICT_ERR_IGNORE_NONE);
}
- if (foreign_table) {
- foreign_table->inc_fk_checks();
- }
-
- /* NOTE that if the thread ends up waiting for a lock
- we will release dict_sys.latch temporarily!
- But the inc_fk_checks() protects foreign_table from
- being dropped while the check is running. */
-
err = row_ins_check_foreign_constraint(
FALSE, foreign, table, entry, thr);
- if (foreign_table) {
- foreign_table->dec_fk_checks();
- }
if (ref_table != NULL) {
dict_table_close(ref_table, FALSE, FALSE);
}
diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc
index bf35e7857c5..0ae208010db 100644
--- a/storage/innobase/ut/ut0ut.cc
+++ b/storage/innobase/ut/ut0ut.cc
@@ -436,8 +436,6 @@ ut_strerr(
return("End of index");
case DB_IO_ERROR:
return("I/O error");
- case DB_TABLE_IN_FK_CHECK:
- return("Table is being used in foreign key check");
case DB_NOT_FOUND:
return("not found");
case DB_ONLINE_LOG_TOO_BIG: