diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-07-24 16:07:00 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-07-24 16:07:00 +0300 |
commit | 7dc405f0523313546eeb7b30d6b534081dd9e3d8 (patch) | |
tree | fd5521885ad207d11d59a354c1c0307def3979e5 | |
parent | a18639f1a913b446f32d7fbe531aa0d5782cf720 (diff) | |
download | mariadb-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.h | 1 | ||||
-rw-r--r-- | include/my_base.h | 4 | ||||
-rw-r--r-- | mysql-test/suite/binlog/disabled.def | 2 | ||||
-rw-r--r-- | mysql-test/suite/innodb/disabled.def | 2 | ||||
-rw-r--r-- | mysql-test/suite/rpl/disabled.def | 6 | ||||
-rw-r--r-- | sql/handler.cc | 4 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 4 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 3 | ||||
-rw-r--r-- | storage/innobase/include/db0err.h | 2 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 22 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 30 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.cc | 53 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 12 | ||||
-rw-r--r-- | storage/innobase/ut/ut0ut.cc | 2 |
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: |