diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-17 15:17:37 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-17 15:26:33 +0300 |
commit | 198ed24cac6609e68687841c022efacdc9719d5f (patch) | |
tree | fb43f454e6b7e3b6b22c34051c7d9ce44e067b30 | |
parent | b390447e71cc3cbd4dc677efeabef771a0a77d64 (diff) | |
download | mariadb-git-198ed24cac6609e68687841c022efacdc9719d5f.tar.gz |
MDEV-19513: Rename dict_operation_lock to dict_sys.latch
dict_sys.lock(), dict_sys_lock(): Acquire both mutex and latch.
dict_sys.unlock(), dict_sys_unlock(): Release both mutex and latch.
dict_sys.assert_locked(): Assert that both mutex and latch are held.
26 files changed, 169 insertions, 252 deletions
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 59572fd11dd..71a4fd87c86 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -2327,8 +2327,7 @@ dict_delete_tablespace_and_datafiles( { dberr_t err = DB_SUCCESS; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); ut_ad(srv_sys_tablespaces_open); trx->op_info = "delete tablespace and datafiles from dictionary"; diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc index bec6ce0b49a..6782ac69bef 100644 --- a/storage/innobase/dict/dict0defrag_bg.cc +++ b/storage/innobase/dict/dict0defrag_bg.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2016, 2018, MariaDB Corporation. +Copyright (c) 2016, 2019, 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 the Free Software @@ -244,8 +244,7 @@ dict_stats_save_defrag_summary( return DB_SUCCESS; } - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); ret = dict_stats_save_index_stat(index, now, "n_pages_freed", index->stat_defrag_n_pages_freed, @@ -254,8 +253,7 @@ dict_stats_save_defrag_summary( " last defragmentation run.", NULL); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return (ret); } @@ -295,9 +293,7 @@ dict_stats_save_defrag_stats( return DB_SUCCESS; } - rw_lock_x_lock(dict_operation_lock); - - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); ret = dict_stats_save_index_stat(index, now, "n_page_split", index->stat_defrag_n_page_split, NULL, @@ -327,8 +323,6 @@ dict_stats_save_defrag_stats( NULL); end: - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); - - return (ret); + dict_sys_unlock(); + return ret; } diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index c8c694ea9e8..cd829f43891 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -87,16 +87,6 @@ ib_warn_row_too_big(const dict_table_t* table); /** the dictionary system */ dict_sys_t dict_sys; -/** @brief the data dictionary rw-latch protecting dict_sys - -table create, drop, etc. reserve this in X-mode; implicit or -backround operations purge, rollback, foreign key checks reserve this -in S-mode; we cannot trust that MySQL protects implicit or background -operations a table drop since MySQL does not know of them; therefore -we need this; NOTE: a transaction which reserves this must keep book -on the mode in trx_t::dict_operation_lock_mode */ -rw_lock_t* dict_operation_lock; - /** Percentage of compression failures that are allowed in a single round */ ulong zip_failure_threshold_pct = 5; @@ -530,8 +520,7 @@ dict_table_close_and_drop( { dberr_t err = DB_SUCCESS; - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); ut_ad(trx->dict_operation != TRX_DICT_OP_NONE); ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); @@ -1034,9 +1023,6 @@ dict_table_col_in_clustered_key( void dict_sys_t::create() { ut_ad(!is_initialised()); - dict_operation_lock = static_cast<rw_lock_t*>( - ut_zalloc_nokey(sizeof(*dict_operation_lock))); - ut_d(m_initialised= true); UT_LIST_INIT(table_LRU, &dict_table_t::table_LRU); UT_LIST_INIT(table_non_LRU, &dict_table_t::table_LRU); @@ -1050,8 +1036,7 @@ void dict_sys_t::create() table_id_hash= hash_create(hash_size); temp_id_hash= hash_create(hash_size); - rw_lock_create(dict_operation_lock_key, - dict_operation_lock, SYNC_DICT_OPERATION); + rw_lock_create(dict_operation_lock_key, &latch, SYNC_DICT_OPERATION); if (!srv_read_only_mode) { @@ -1260,9 +1245,7 @@ dict_table_can_be_evicted( /*======================*/ dict_table_t* table) /*!< in: table to test */ { - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - + ut_d(dict_sys.assert_locked()); ut_a(table->can_be_evicted); ut_a(table->foreign_set.empty()); ut_a(table->referenced_set.empty()); @@ -1328,8 +1311,7 @@ dict_make_room_in_cache( ut_a(pct_check > 0); ut_a(pct_check <= 100); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); ut_ad(dict_lru_validate()); i = len = UT_LIST_GET_LEN(dict_sys.table_LRU); @@ -1939,9 +1921,7 @@ void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep) and free the index pages. */ trx_t* trx = trx_create(); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - + ut_d(dict_sys.assert_locked()); /* Mimic row_mysql_lock_data_dictionary(). */ trx->dict_operation_lock_mode = RW_X_LATCH; @@ -5817,8 +5797,7 @@ dict_index_set_merge_threshold( ut_ad(!dict_table_is_comp(dict_sys.sys_tables)); ut_ad(!dict_table_is_comp(dict_sys.sys_indexes)); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t) + sizeof(que_fork_t) + sizeof(upd_node_t) @@ -5866,8 +5845,7 @@ dict_index_set_merge_threshold( mtr_commit(&mtr); mem_heap_free(heap); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); } #ifdef UNIV_DEBUG @@ -6449,11 +6427,7 @@ void dict_sys_t::close() mutex_exit(&mutex); mutex_free(&mutex); - - rw_lock_free(dict_operation_lock); - - ut_free(dict_operation_lock); - dict_operation_lock = NULL; + rw_lock_free(&latch); mutex_free(&dict_foreign_err_mutex); @@ -6806,8 +6780,7 @@ dict_space_is_empty( mtr_t mtr; bool found = false; - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); mtr_start(&mtr); for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); @@ -6828,8 +6801,7 @@ dict_space_is_empty( } mtr_commit(&mtr); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return(!found); } @@ -6847,8 +6819,7 @@ dict_space_get_id( ulint name_len = strlen(name); ulint id = ULINT_UNDEFINED; - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); mtr_start(&mtr); for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES); @@ -6877,8 +6848,7 @@ dict_space_get_id( } mtr_commit(&mtr); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return(id); } diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 2c3e9c9e1f5..ef87a0e7422 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -884,8 +884,7 @@ dict_update_filepath( dberr_t err = DB_SUCCESS; trx_t* trx; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); trx = trx_create(); trx->op_info = "update filepath"; @@ -952,8 +951,7 @@ dict_replace_tablespace_and_filepath( DBUG_EXECUTE_IF("innodb_fail_to_update_tablespace_dict", return(DB_INTERRUPTED);); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); ut_ad(filepath); trx = trx_create(); @@ -1350,8 +1348,7 @@ static ulint dict_check_sys_tables() DBUG_ENTER("dict_check_sys_tables"); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); mtr_start(&mtr); @@ -1487,8 +1484,7 @@ void dict_check_tablespaces_and_store_max_id() DBUG_ENTER("dict_check_tablespaces_and_store_max_id"); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); /* Initialize the max space_id from sys header */ mtr_start(&mtr); @@ -1505,8 +1501,7 @@ void dict_check_tablespaces_and_store_max_id() max_space_id = dict_check_sys_tables(); fil_set_max_space_id_if_bigger(max_space_id); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); DBUG_VOID_RETURN; } @@ -2833,7 +2828,7 @@ dict_load_tablespace( } /* Try to open the tablespace. We set the 2nd param (fix_dict) to - false because we do not have an x-lock on dict_operation_lock */ + false because we do not have an x-lock on dict_sys.latch */ table->space = fil_ibd_open( true, false, FIL_TYPE_TABLESPACE, table->space_id, dict_tf_to_fsp_flags(table->flags), diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index d557078de49..0ebbcebb708 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2009, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2018, MariaDB Corporation. +Copyright (c) 2015, 2019, 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 the Free Software @@ -283,8 +283,7 @@ dict_stats_exec_sql( dberr_t err; bool trx_started = false; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); if (!dict_stats_persistent_storage_check(true)) { pars_info_free(pinfo); @@ -2313,8 +2312,7 @@ dict_stats_save_index_stat( char table_utf8[MAX_TABLE_UTF8_LEN]; ut_ad(!trx || trx->internal || trx->mysql_thd); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); dict_fs2utf8(index->table->name.m_name, db_utf8, sizeof(db_utf8), table_utf8, sizeof(table_utf8)); @@ -2449,8 +2447,7 @@ dict_stats_save( table_utf8, sizeof(table_utf8)); now = ut_time(); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); pinfo = pars_info_create(); @@ -2488,13 +2485,10 @@ dict_stats_save( if (ret != DB_SUCCESS) { ib::error() << "Cannot save table statistics for table " << table->name << ": " << ut_strerr(ret); - - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); - +func_exit: + dict_sys_unlock(); dict_stats_snapshot_free(table); - - return(ret); + return ret; } trx_t* trx = trx_create(); @@ -2595,13 +2589,7 @@ dict_stats_save( end: trx_free(trx); - - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); - - dict_stats_snapshot_free(table); - - return(ret); + goto func_exit; } /*********************************************************************//** @@ -3406,8 +3394,7 @@ dict_stats_drop_index( pars_info_add_str_literal(pinfo, "index_name", iname); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); ret = dict_stats_exec_sql( pinfo, @@ -3419,8 +3406,7 @@ dict_stats_drop_index( "index_name = :index_name;\n" "END;\n", NULL); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); if (ret == DB_STATS_DO_NOT_EXIST) { ret = DB_SUCCESS; @@ -3468,8 +3454,7 @@ dict_stats_delete_from_table_stats( pars_info_t* pinfo; dberr_t ret; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); pinfo = pars_info_create(); @@ -3504,8 +3489,7 @@ dict_stats_delete_from_index_stats( pars_info_t* pinfo; dberr_t ret; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); pinfo = pars_info_create(); @@ -3541,8 +3525,7 @@ dict_stats_drop_table( char table_utf8[MAX_TABLE_UTF8_LEN]; dberr_t ret; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); /* skip tables that do not contain a database name e.g. if we are dropping SYS_TABLES */ @@ -3617,8 +3600,7 @@ dict_stats_rename_table_in_table_stats( pars_info_t* pinfo; dberr_t ret; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); pinfo = pars_info_create(); @@ -3661,8 +3643,7 @@ dict_stats_rename_table_in_index_stats( pars_info_t* pinfo; dberr_t ret; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); pinfo = pars_info_create(); @@ -3705,9 +3686,6 @@ dict_stats_rename_table( char new_table_utf8[MAX_TABLE_UTF8_LEN]; dberr_t ret; - ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(!mutex_own(&dict_sys.mutex)); - /* skip innodb_table_stats and innodb_index_stats themselves */ if (strcmp(old_name, TABLE_STATS_NAME) == 0 || strcmp(old_name, INDEX_STATS_NAME) == 0 @@ -3723,8 +3701,7 @@ dict_stats_rename_table( dict_fs2utf8(new_name, new_db_utf8, sizeof(new_db_utf8), new_table_utf8, sizeof(new_table_utf8)); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); ulint n_attempts = 0; do { @@ -3744,11 +3721,9 @@ dict_stats_rename_table( } if (ret != DB_SUCCESS) { - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); os_thread_sleep(200000 /* 0.2 sec */); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); } } while ((ret == DB_DEADLOCK || ret == DB_DUPLICATE_KEY @@ -3776,8 +3751,7 @@ dict_stats_rename_table( TABLE_STATS_NAME_PRINT, new_db_utf8, new_table_utf8, old_db_utf8, old_table_utf8); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return(ret); } /* else */ @@ -3800,19 +3774,16 @@ dict_stats_rename_table( } if (ret != DB_SUCCESS) { - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); os_thread_sleep(200000 /* 0.2 sec */); - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); } } while ((ret == DB_DEADLOCK || ret == DB_DUPLICATE_KEY || ret == DB_LOCK_WAIT_TIMEOUT) && n_attempts < 5); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); if (ret != DB_SUCCESS) { snprintf(errstr, errstr_sz, @@ -3853,12 +3824,10 @@ dict_stats_rename_index( const char* old_index_name, /*!< in: old index name */ const char* new_index_name) /*!< in: new index name */ { - rw_lock_x_lock(dict_operation_lock); - mutex_enter(&dict_sys.mutex); + dict_sys_lock(); if (!dict_stats_persistent_storage_check(true)) { - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return(DB_STATS_DO_NOT_EXIST); } @@ -3891,8 +3860,7 @@ dict_stats_rename_index( "index_name = :old_index_name;\n" "END;\n", NULL); - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return(ret); } diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc index 9bd4b6c8ce4..1d58ca196d9 100644 --- a/storage/innobase/dict/dict0stats_bg.cc +++ b/storage/innobase/dict/dict0stats_bg.cc @@ -313,7 +313,7 @@ dict_stats_thread_init() dict_stats_update_if_needed() is called and it may be acquired inside that function (thus a level <=SYNC_DICT would do). 3) from row_drop_table_for_mysql() after dict_sys.mutex (SYNC_DICT) - and dict_operation_lock (SYNC_DICT_OPERATION) have been locked + and dict_sys.latch (SYNC_DICT_OPERATION) have been locked (thus a level <SYNC_DICT && <SYNC_DICT_OPERATION would do) So we choose SYNC_STATS_AUTO_RECALC to be about below SYNC_DICT. */ diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index e4fb839a7cc..1dbf64e3fb9 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3178,11 +3178,12 @@ fil_ibd_open( ulint tablespaces_found = 0; ulint valid_tablespaces_found = 0; - ut_ad(!fix_dict || rw_lock_own(dict_operation_lock, RW_LOCK_X)); + if (fix_dict) { + ut_d(dict_sys.assert_locked()); + ut_ad(!srv_read_only_mode); + ut_ad(srv_log_file_size != 0); + } - ut_ad(!fix_dict || mutex_own(&dict_sys.mutex)); - ut_ad(!fix_dict || !srv_read_only_mode); - ut_ad(!fix_dict || srv_log_file_size != 0); ut_ad(fil_type_is_data(purpose)); /* Table flags can be ULINT_UNDEFINED if @@ -4766,7 +4767,7 @@ fil_space_validate_for_mtr_commit( /* We are serving mtr_commit(). While there is an active mini-transaction, we should have !space->stop_new_ops. This is guaranteed by meta-data locks or transactional locks, or - dict_operation_lock (X-lock in DROP, S-lock in purge). + dict_sys.latch (X-lock in DROP, S-lock in purge). However, a file I/O thread can invoke change buffer merge while fil_check_pending_operations() is waiting for operations diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 167c6589e22..83bddd439dd 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -20452,10 +20452,10 @@ for purge thread */ static TABLE* innodb_find_table_for_vc(THD* thd, dict_table_t* table) { if (THDVAR(thd, background_thread)) { - /* Purge thread acquires dict_operation_lock while - processing undo log record. Release the dict_operation_lock + /* Purge thread acquires dict_sys.latch while + processing undo log record. Release it before acquiring MDL on the table. */ - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); return innodb_acquire_mdl(thd, table); } else { if (table->vc_templ->mysql_table_query_id diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 85561c08d77..a8cf53b5033 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -746,8 +746,7 @@ inline void dict_table_t::rollback_instant( const char* old_v_col_names, const ulint* col_map) { - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); dict_index_t* index = indexes.start; mtr_t mtr; mtr.start(); @@ -4741,8 +4740,7 @@ innobase_update_gis_column_type( DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); info = pars_info_create(); @@ -6733,7 +6731,7 @@ new_clustered_failed: ut_a(ctx->new_table == temp_table); /* n_ref_count must be 1, because purge cannot be executing on this very table as we are - holding dict_operation_lock X-latch. */ + holding dict_sys.latch X-latch. */ DBUG_ASSERT(ctx->new_table->get_ref_count() == 1); DBUG_ASSERT(ctx->new_table->id != 0); DBUG_ASSERT(ctx->new_table->id == ctx->trx->table_id); @@ -6946,8 +6944,7 @@ error_handling_drop_uncached: op_ok: #endif /* UNIV_DEBUG */ ut_ad(ctx->trx->dict_operation_lock_mode == RW_X_LATCH); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS); if (ctx->need_rebuild()) { @@ -7091,7 +7088,7 @@ error_handled: trx_commit_for_mysql(ctx->trx); /* n_ref_count must be 1, because purge cannot be executing on this very table as we are - holding dict_operation_lock X-latch. */ + holding dict_sys.latch X-latch. */ DBUG_ASSERT(user_table->get_ref_count() == 1 || ctx->online); online_retry_drop_indexes_with_trx(user_table, ctx->trx); @@ -7233,9 +7230,7 @@ rename_index_try( trx_t* trx) { DBUG_ENTER("rename_index_try"); - - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); pars_info_t* pinfo; @@ -7293,9 +7288,7 @@ void innobase_rename_index_cache(dict_index_t* index, const char* new_name) { DBUG_ENTER("innobase_rename_index_cache"); - - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); size_t old_name_len = strlen(index->name); size_t new_name_len = strlen(new_name); @@ -8261,10 +8254,7 @@ ha_innobase::inplace_alter_table( bool rebuild_templ = false; DBUG_ENTER("inplace_alter_table"); DBUG_ASSERT(!srv_read_only_mode); - ut_ad(!sync_check_iterate(sync_check())); - ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_S)); DEBUG_SYNC(m_user_thd, "innodb_inplace_alter_table_enter"); @@ -8476,10 +8466,7 @@ innobase_online_rebuild_log_free( dict_table_t* table) { dict_index_t* clust_index = dict_table_get_first_index(table); - - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - + ut_d(dict_sys.assert_locked()); rw_lock_x_lock(&clust_index->lock); if (clust_index->online_log) { @@ -8752,8 +8739,7 @@ innobase_drop_foreign_try( DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); /* Drop the constraint from the data dictionary. */ static const char sql[] = @@ -8811,8 +8797,7 @@ innobase_rename_column_try( DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); if (new_clustered) { goto rename_foreign; @@ -9088,8 +9073,7 @@ innobase_rename_or_enlarge_column_try( DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); ulint n_base; @@ -10512,7 +10496,7 @@ alter_stats_norebuild( in a separate transaction from trx, because lock waits are not allowed in a data dictionary transaction. (Lock waits are possible on the statistics table, because it is directly accessible by users, - not covered by the dict_operation_lock.) + not covered by the dict_sys.latch.) Because the data dictionary changes were already committed, orphaned rows may be left in the statistics table if the system crashes. diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 6369b024a58..110bf8bb119 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -2869,19 +2869,19 @@ i_s_fts_deleted_generic_fill( } /* Prevent DDL to drop fts aux tables. */ - rw_lock_s_lock(dict_operation_lock); + rw_lock_s_lock(&dict_sys.latch); user_table = dict_table_open_on_name( fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE); if (!user_table) { - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(0); } else if (!dict_table_has_fts_index(user_table)) { dict_table_close(user_table, FALSE, FALSE); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(0); } @@ -2917,7 +2917,7 @@ i_s_fts_deleted_generic_fill( dict_table_close(user_table, FALSE, FALSE); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(ret); } @@ -3730,13 +3730,13 @@ i_s_fts_index_table_fill( } /* Prevent DDL to drop fts aux tables. */ - rw_lock_s_lock(dict_operation_lock); + rw_lock_s_lock(&dict_sys.latch); user_table = dict_table_open_on_name( fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE); if (!user_table) { - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(0); } @@ -3757,7 +3757,7 @@ i_s_fts_index_table_fill( dict_table_close(user_table, FALSE, FALSE); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); ut_free(conv_str.f_str); @@ -3899,19 +3899,19 @@ i_s_fts_config_fill( fields = table->field; /* Prevent DDL to drop fts aux tables. */ - rw_lock_s_lock(dict_operation_lock); + rw_lock_s_lock(&dict_sys.latch); user_table = dict_table_open_on_name( fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE); if (!user_table) { - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(0); } else if (!dict_table_has_fts_index(user_table)) { dict_table_close(user_table, FALSE, FALSE); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(0); } @@ -3971,7 +3971,7 @@ i_s_fts_config_fill( dict_table_close(user_table, FALSE, FALSE); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); DBUG_RETURN(ret); } @@ -6338,7 +6338,7 @@ i_s_sys_tables_fill_table_stats( } heap = mem_heap_create(1000); - rw_lock_s_lock(dict_operation_lock); + rw_lock_s_lock(&dict_sys.latch); mutex_enter(&dict_sys.mutex); mtr_start(&mtr); @@ -6372,11 +6372,11 @@ i_s_sys_tables_fill_table_stats( err_msg); } - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); mem_heap_empty(heap); /* Get the next record */ - rw_lock_s_lock(dict_operation_lock); + rw_lock_s_lock(&dict_sys.latch); mutex_enter(&dict_sys.mutex); mtr_start(&mtr); @@ -6385,7 +6385,7 @@ i_s_sys_tables_fill_table_stats( mtr_commit(&mtr); mutex_exit(&dict_sys.mutex); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); mem_heap_free(heap); DBUG_RETURN(0); diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 9146627b496..ae223acd07f 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1471,6 +1471,15 @@ public: and DROP TABLE, as well as reading the dictionary data for a table from system tables */ + /** @brief the data dictionary rw-latch protecting dict_sys + + Table create, drop, etc. reserve this in X-mode; implicit or + backround operations purge, rollback, foreign key checks reserve this + in S-mode; not all internal InnoDB operations are covered by MDL. + + This latch also prevents lock waits when accessing the InnoDB + data dictionary tables. @see trx_t::dict_operation_lock_mode */ + rw_lock_t latch; row_id_t row_id; /*!< the next row id to assign; NOTE that at a checkpoint this must be written to the dict system @@ -1501,7 +1510,6 @@ private: /** hash table of temporary table IDs */ hash_table_t* temp_id_hash; public: - /** @return a new temporary table ID */ table_id_t get_temporary_table_id() { return temp_table_id.fetch_add(1, std::memory_order_relaxed); @@ -1603,14 +1611,36 @@ public: } /** Acquire a reference to a cached table. */ inline void acquire(dict_table_t* table); + +#ifdef UNIV_DEBUG + /** Assert that the data dictionary is locked */ + void assert_locked() + { + ut_ad(mutex_own(&mutex)); + ut_ad(rw_lock_own(&latch, RW_LOCK_X)); + } +#endif + /** Lock the data dictionary cache. */ + void lock(const char* file, unsigned line) + { + rw_lock_x_lock_func(&latch, 0, file, line); + mutex_enter_loc(&mutex, file, line); + } + + /** Unlock the data dictionary cache. */ + void unlock() + { + mutex_exit(&mutex); + rw_lock_x_unlock(&latch); + } }; /** the data dictionary cache */ extern dict_sys_t dict_sys; -/** the data dictionary rw-latch protecting dict_sys */ -extern rw_lock_t* dict_operation_lock; #define dict_table_prevent_eviction(table) dict_sys.prevent_eviction(table) +#define dict_sys_lock() dict_sys.lock(__FILE__, __LINE__) +#define dict_sys_unlock() dict_sys.unlock() /** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */ extern dict_index_t* dict_ind_redundant; diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index cee16102b2e..b646537b4c3 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -948,12 +948,12 @@ struct dict_index_t { dictionary cache */ unsigned to_be_dropped:1; /*!< TRUE if the index is to be dropped; - protected by dict_operation_lock */ + protected by dict_sys.latch */ unsigned online_status:2; /*!< enum online_index_status. Transitions from ONLINE_INDEX_COMPLETE (to ONLINE_INDEX_CREATION) are protected - by dict_operation_lock and + by dict_sys.latch and dict_sys.mutex. Other changes are protected by index->lock. */ unsigned uncommitted:1; @@ -1835,8 +1835,7 @@ public: /** TRUE if the table is to be dropped, but not yet actually dropped (could in the background drop list). It is turned on at the beginning of row_drop_table_for_mysql() and turned off just before we start to - update system tables for the drop. It is protected by - dict_operation_lock. */ + update system tables for the drop. It is protected by dict_sys.latch. */ unsigned to_be_dropped:1; /** Number of non-virtual columns defined so far. */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index bfbe3a3578f..68b8a45d993 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -134,7 +134,7 @@ struct fil_space_t { the tablespace to disk; dropping of the tablespace is forbidden if this is positive */ /** Number of pending buffer pool operations accessing the tablespace - without holding a table lock or dict_operation_lock S-latch + without holding a table lock or dict_sys.latch S-latch that would prevent the table (and tablespace) from being dropped. An example is change buffer merge. The tablespace cannot be dropped while this is nonzero, diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index a3de6356ad8..39214b621e1 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 the Free Software @@ -485,7 +485,7 @@ log_free_check(void) static const latch_level_t latches[] = { SYNC_DICT, /* dict_sys.mutex during commit_try_rebuild() */ - SYNC_DICT_OPERATION, /* dict_operation_lock X-latch during + SYNC_DICT_OPERATION, /* dict_sys.latch X-latch during commit_try_rebuild() */ SYNC_FTS_CACHE, /* fts_cache_t::lock */ SYNC_INDEX_TREE /* index->lock */ diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 94307146e9e..167df0d3ec7 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -418,7 +418,7 @@ will remain locked. @param[in] create_failed true=create table failed because e.g. foreign key column @param[in] nonatomic Whether it is permitted to release - and reacquire dict_operation_lock + and reacquire dict_sys.latch @return error code */ dberr_t row_drop_table_for_mysql( diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index ee5f1c4aefb..a6eba0b1a92 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -690,7 +690,7 @@ with exactly one user transaction. There are some exceptions to this: * For DDL operations, a subtransaction is allocated that modifies the data dictionary tables. Lock waits and deadlocks are prevented by -acquiring the dict_operation_lock before starting the subtransaction +acquiring the dict_sys.latch before starting the subtransaction and releasing it after committing the subtransaction. * The purge system uses a special transaction that is not associated @@ -924,8 +924,8 @@ public: ib_uint32_t dict_operation_lock_mode; /*!< 0, RW_S_LATCH, or RW_X_LATCH: the latch mode trx currently holds - on dict_operation_lock. Protected - by dict_operation_lock. */ + on dict_sys.latch. Protected + by dict_sys.latch. */ time_t start_time; /*!< time the state last time became TRX_STATE_ACTIVE */ diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 5455c969c7a..cf8008d55c4 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3856,7 +3856,7 @@ row_import_for_mysql( /* Prevent DDL operations while we are checking. */ - rw_lock_s_lock_func(dict_operation_lock, 0, __FILE__, __LINE__); + rw_lock_s_lock(&dict_sys.latch); row_import cfg; @@ -3881,14 +3881,14 @@ row_import_for_mysql( autoinc = cfg.m_autoinc; } - rw_lock_s_unlock_gen(dict_operation_lock, 0); + rw_lock_s_unlock(&dict_sys.latch); DBUG_EXECUTE_IF("ib_import_set_index_root_failure", err = DB_TOO_MANY_CONCURRENT_TRXS;); } else if (cfg.m_missing) { - rw_lock_s_unlock_gen(dict_operation_lock, 0); + rw_lock_s_unlock(&dict_sys.latch); /* We don't have a schema file, we will have to discover the index root pages from the .ibd file and skip the schema @@ -3920,7 +3920,7 @@ row_import_for_mysql( space_flags = fetchIndexRootPages.get_space_flags(); } else { - rw_lock_s_unlock_gen(dict_operation_lock, 0); + rw_lock_s_unlock(&dict_sys.latch); } if (err != DB_SUCCESS) { @@ -4011,7 +4011,7 @@ row_import_for_mysql( /* Open the tablespace so that we can access via the buffer pool. We set the 2nd param (fix_dict = true) here because we already - have an x-lock on dict_operation_lock and dict_sys.mutex. + have an x-lock on dict_sys.latch and dict_sys.mutex. The tablespace is initially opened as a temporary one, because we will not be writing any redo log for it before we have invoked fil_space_t::set_imported() to declare it a persistent tablespace. */ diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index c4b6883156c..0cd49bce994 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1543,7 +1543,7 @@ row_ins_set_exclusive_rec_lock( /***************************************************************//** Checks if foreign key constraint fails for an index entry. Sets shared locks which lock either the success or the failure of the constraint. NOTE that -the caller must have a shared latch on dict_operation_lock. +the caller must have a shared latch on dict_sys.latch. @return DB_SUCCESS, DB_NO_REFERENCED_ROW, or DB_ROW_IS_REFERENCED */ dberr_t row_ins_check_foreign_constraint( @@ -1584,7 +1584,7 @@ row_ins_check_foreign_constraint( upd_node= NULL; #endif /* WITH_WSREP */ - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)); + ut_ad(rw_lock_own(&dict_sys.latch, RW_LOCK_S)); err = DB_SUCCESS; @@ -1990,7 +1990,7 @@ row_ins_check_foreign_constraints( } /* NOTE that if the thread ends up waiting for a lock - we will release dict_operation_lock temporarily! + 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. */ diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 834a31684b2..c0e98a5368b 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -3111,7 +3111,7 @@ row_log_table_apply( stage->begin_phase_log_table(); - ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_S)); + ut_ad(!rw_lock_own(&dict_sys.latch, RW_LOCK_S)); clust_index = dict_table_get_first_index(old_table); if (clust_index->online_log->n_rows == 0) { diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 83c8316b523..aebdd09e5d6 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -3755,10 +3755,9 @@ row_merge_drop_index_dict( pars_info_t* info; ut_ad(!srv_read_only_mode); - ut_ad(mutex_own(&dict_sys.mutex)); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); ut_ad(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); info = pars_info_create(); pars_info_add_ull_literal(info, "indexid", index_id); @@ -3818,17 +3817,16 @@ row_merge_drop_indexes_dict( pars_info_t* info; ut_ad(!srv_read_only_mode); - ut_ad(mutex_own(&dict_sys.mutex)); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); ut_ad(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); /* It is possible that table->n_ref_count > 1 when locked=TRUE. In this case, all code that should have an open handle to the table be waiting for the next statement to execute, or waiting for a meta-data lock. - A concurrent purge will be prevented by dict_operation_lock. */ + A concurrent purge will be prevented by dict_sys.latch. */ info = pars_info_create(); pars_info_add_ull_literal(info, "tableid", table_id); @@ -3868,10 +3866,9 @@ row_merge_drop_indexes( dict_index_t* next_index; ut_ad(!srv_read_only_mode); - ut_ad(mutex_own(&dict_sys.mutex)); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); ut_ad(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); index = dict_table_get_first_index(table); ut_ad(dict_index_is_clust(index)); @@ -3885,7 +3882,7 @@ row_merge_drop_indexes( handle to the table be waiting for the next statement to execute, or waiting for a meta-data lock. - A concurrent purge will be prevented by dict_operation_lock. */ + A concurrent purge will be prevented by dict_sys.latch. */ if (!locked && (table->get_ref_count() > 1 || UT_LIST_GET_FIRST(table->locks))) { @@ -4320,7 +4317,7 @@ row_merge_rename_tables_dict( ut_ad(!srv_read_only_mode); ut_ad(old_table != new_table); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); ut_a(trx->dict_operation_lock_mode == RW_X_LATCH); ut_ad(trx_get_dict_operation(trx) == TRX_DICT_OP_TABLE || trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 1ddae8d4fc3..02b936b167c 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2121,7 +2121,7 @@ row_mysql_freeze_data_dictionary_func( { ut_a(trx->dict_operation_lock_mode == 0); - rw_lock_s_lock_inline(dict_operation_lock, 0, file, line); + rw_lock_s_lock_inline(&dict_sys.latch, 0, file, line); trx->dict_operation_lock_mode = RW_S_LATCH; } @@ -2137,7 +2137,7 @@ row_mysql_unfreeze_data_dictionary( ut_a(trx->dict_operation_lock_mode == RW_S_LATCH); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); trx->dict_operation_lock_mode = 0; } @@ -2321,14 +2321,8 @@ row_mysql_lock_data_dictionary_func( { ut_a(trx->dict_operation_lock_mode == 0 || trx->dict_operation_lock_mode == RW_X_LATCH); - - /* Serialize data dictionary operations with dictionary mutex: - no deadlocks or lock waits can occur then in these operations */ - - rw_lock_x_lock_inline(dict_operation_lock, 0, file, line); + dict_sys.lock(file, line); trx->dict_operation_lock_mode = RW_X_LATCH; - - mutex_enter(&dict_sys.mutex); } /*********************************************************************//** @@ -2339,16 +2333,9 @@ row_mysql_unlock_data_dictionary( trx_t* trx) /*!< in/out: transaction */ { ut_ad(lock_trx_has_sys_table_locks(trx) == NULL); - ut_a(trx->dict_operation_lock_mode == RW_X_LATCH); - - /* Serialize data dictionary operations with dictionary mutex: - no deadlocks can occur then in these operations */ - - mutex_exit(&dict_sys.mutex); - rw_lock_x_unlock(dict_operation_lock); - trx->dict_operation_lock_mode = 0; + dict_sys.unlock(); } /*********************************************************************//** @@ -2370,8 +2357,7 @@ row_create_table_for_mysql( que_thr_t* thr; dberr_t err; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); DBUG_EXECUTE_IF( @@ -2511,8 +2497,7 @@ row_create_index_for_mysql( ulint len; dict_table_t* table = index->table; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - ut_ad(mutex_own(&dict_sys.mutex)); + ut_d(dict_sys.assert_locked()); for (i = 0; i < index->n_def; i++) { /* Check that prefix_len and actual length @@ -3303,7 +3288,7 @@ will remain locked. @param[in] create_failed true=create table failed because e.g. foreign key column @param[in] nonatomic Whether it is permitted to release - and reacquire dict_operation_lock + and reacquire dict_sys.latch @return error code or DB_SUCCESS */ dberr_t row_drop_table_for_mysql( @@ -3342,8 +3327,7 @@ row_drop_table_for_mysql( nonatomic = true; } - ut_ad(mutex_own(&dict_sys.mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); + ut_d(dict_sys.assert_locked()); table = dict_table_open_on_name( name, TRUE, FALSE, diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index bafcb35fad8..c6a415a8d29 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -102,7 +102,7 @@ row_purge_remove_clust_if_poss_low( purge_node_t* node, /*!< in/out: row purge node */ ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S) + ut_ad(rw_lock_own(&dict_sys.latch, RW_LOCK_S) || node->vcol_info.is_used()); dict_index_t* index = dict_table_get_first_index(node->table); @@ -790,7 +790,7 @@ whose old history can no longer be observed. @param[in,out] mtr mini-transaction (will be started and committed) */ static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr) { - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S) + ut_ad(rw_lock_own(&dict_sys.latch, RW_LOCK_S) || node->vcol_info.is_used()); /* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */ mtr->start(); @@ -867,7 +867,7 @@ row_purge_upd_exist_or_extern_func( { mem_heap_t* heap; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S) + ut_ad(rw_lock_own(&dict_sys.latch, RW_LOCK_S) || node->vcol_info.is_used()); ut_ad(!node->table->skip_alter_undo); @@ -1058,7 +1058,7 @@ row_purge_parse_undo_rec( for this row */ try_again: - rw_lock_s_lock_inline(dict_operation_lock, 0, __FILE__, __LINE__); + rw_lock_s_lock_inline(&dict_sys.latch, 0, __FILE__, __LINE__); node->table = dict_table_open_on_id( table_id, FALSE, DICT_TABLE_OP_NORMAL); @@ -1089,7 +1089,7 @@ try_again: if (!mysqld_server_started) { dict_table_close(node->table, FALSE, FALSE); - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { return(false); } @@ -1119,7 +1119,7 @@ inaccessible: dict_table_close(node->table, FALSE, FALSE); node->table = NULL; err_exit: - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); node->skip(table_id, trx_id); return(false); } @@ -1255,10 +1255,10 @@ row_purge( node, undo_rec, thr, updated_extern); if (!node->vcol_info.is_used()) { - rw_lock_s_unlock(dict_operation_lock); + rw_lock_s_unlock(&dict_sys.latch); } - ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_S)); + ut_ad(!rw_lock_own(&dict_sys.latch, RW_LOCK_S)); if (purged || srv_shutdown_state != SRV_SHUTDOWN_NONE diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 9c8d3d3d313..64d0e812838 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -270,7 +270,7 @@ row_undo_mod_clust( ut_ad(thr_get_trx(thr) == node->trx); ut_ad(node->trx->dict_operation_lock_mode); ut_ad(node->trx->in_rollback); - ut_ad(rw_lock_own_flagged(dict_operation_lock, + ut_ad(rw_lock_own_flagged(&dict_sys.latch, RW_LOCK_FLAG_X | RW_LOCK_FLAG_S)); log_free_check(); @@ -327,7 +327,7 @@ row_undo_mod_clust( } /* Online rebuild cannot be initiated while we are holding - dict_operation_lock and index->lock. (It can be aborted.) */ + dict_sys.latch and index->lock. (It can be aborted.) */ ut_ad(online || !dict_index_is_online_ddl(index)); if (err == DB_SUCCESS && online) { diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index b560ec2a0da..42df2318566 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -420,7 +420,7 @@ row_undo( /* Prevent DROP TABLE etc. while we are rolling back this row. If we are doing a TABLE CREATE or some other dictionary operation, - then we already have dict_operation_lock locked in x-mode. Do not + then we already have dict_sys.latch locked in x-mode. Do not try to lock again, because that would cause a hang. */ trx_t* trx = node->trx; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index e1403eea93b..fe82cdf7e08 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -122,7 +122,7 @@ row_upd_changes_first_fields_binary( Checks if index currently is mentioned as a referenced index in a foreign key constraint. -NOTE that since we do not hold dict_operation_lock when leaving the +NOTE that since we do not hold dict_sys.latch when leaving the function, it may be that the referencing table has been dropped when we leave this function: this function is only for heuristic use! @@ -289,7 +289,7 @@ row_upd_check_references_constraints( } /* NOTE that if the thread ends up waiting for a lock - we will release dict_operation_lock temporarily! + we will release dict_sys.latch temporarily! But the inc_fk_checks() protects foreign_table from being dropped while the check is running. */ @@ -397,7 +397,7 @@ wsrep_row_upd_check_foreign_constraints( } /* NOTE that if the thread ends up waiting for a lock - we will release dict_operation_lock temporarily! + we will release dict_sys.latch temporarily! But the counter on the table protects 'foreign' from being dropped while the check is running. */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 8501ffbf672..260271bdc8d 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1996,16 +1996,12 @@ srv_master_evict_from_table_cache( { ulint n_tables_evicted = 0; - rw_lock_x_lock(dict_operation_lock); - - dict_mutex_enter_for_mysql(); + dict_sys_lock(); n_tables_evicted = dict_make_room_in_cache( innobase_get_table_cache_size(), pct_check); - dict_mutex_exit_for_mysql(); - - rw_lock_x_unlock(dict_operation_lock); + dict_sys_unlock(); return(n_tables_evicted); } |