summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-07-30 13:29:35 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-07-30 13:29:35 +0300
commita8642ba0072bc018c966dfa376de7c0190b23cd5 (patch)
tree7e051221bba66955fb12548aa8e6925fc0faeb3c
parentc69286b73e4dec4d488fb2ad7a248a4905a5ec4b (diff)
downloadmariadb-git-bb-10.6-MDEV-24258.tar.gz
MDEV-24258 Merge dict_sys.mutex into dict_sys.latchbb-10.6-MDEV-24258
Thanks to the preparation, dict_sys.latch was only being acquired in exclusive mode. Thus, it could theoretically have been replaced with a mutex. But, we can do better and merge dict_sys.mutex into dict_sys.latch. Generally, every occurrence of dict_sys.mutex_lock() will be replaced with dict_sys.lock(). Much of the current use of dict_sys.lock() will be replaced with dict_sys.freeze(), which we will reintroduce for the new shared mode. The PERFORMANCE_SCHEMA instrumentation for dict_sys_mutex will be removed along with dict_sys.mutex. The dict_sys.latch will remain instrumented as dict_operation_lock. As demonstrated by the test perfschema.sxlock_func, there will be less contention on dict_sys.latch, because some previous use of exclusive latches will be replaced with shared latches. fts_parse_sql_no_dict_lock(): Replaced with pars_sql(). fts_get_table_name_prefix(): Merged to fts_optimize_create(). dict_stats_update_transient_for_index(): Deduplicated some code. ha_innobase::info_low(), dict_stats_stop_bg(): Use a combination of dict_sys.latch and table->stats_mutex_lock() to cover the changes of BG_STAT_SHOULD_QUIT, because the flag is being read in dict_stats_update_persistent() while not holding dict_sys.latch. row_discard_tablespace_for_mysql(): Protect stats_bg_flag by exclusive dict_sys.latch, like most other code does. row_quiesce_table_has_fts_index(): Remove unnecessary mutex acquisition. FLUSH TABLES...FOR EXPORT is protected by MDL. row_import::set_root_by_heuristic(): Remove unnecessary mutex acquisition. ALTER TABLE...IMPORT TABLESPACE is protected by MDL. row_ins_sec_index_entry_low(): Replace a call to dict_set_corrupted_index_cache_only(). Reads of index->type were not really protected by dict_sys.mutex, and writes (flagging an index corrupted) should be extremely rare.
-rw-r--r--mysql-test/suite/perfschema/r/sxlock_func.result1
-rw-r--r--storage/innobase/btr/btr0sea.cc12
-rw-r--r--storage/innobase/dict/dict0boot.cc6
-rw-r--r--storage/innobase/dict/dict0crea.cc32
-rw-r--r--storage/innobase/dict/dict0defrag_bg.cc16
-rw-r--r--storage/innobase/dict/dict0dict.cc192
-rw-r--r--storage/innobase/dict/dict0load.cc51
-rw-r--r--storage/innobase/dict/dict0stats.cc46
-rw-r--r--storage/innobase/dict/dict0stats_bg.cc22
-rw-r--r--storage/innobase/dict/drop.cc8
-rw-r--r--storage/innobase/fil/fil0fil.cc2
-rw-r--r--storage/innobase/fts/fts0fts.cc45
-rw-r--r--storage/innobase/fts/fts0opt.cc26
-rw-r--r--storage/innobase/fts/fts0sql.cc59
-rw-r--r--storage/innobase/handler/ha_innodb.cc58
-rw-r--r--storage/innobase/handler/handler0alter.cc63
-rw-r--r--storage/innobase/handler/i_s.cc126
-rw-r--r--storage/innobase/include/dict0dict.h110
-rw-r--r--storage/innobase/include/dict0dict.ic4
-rw-r--r--storage/innobase/include/dict0load.h9
-rw-r--r--storage/innobase/include/dict0mem.h9
-rw-r--r--storage/innobase/include/dict0stats.ic4
-rw-r--r--storage/innobase/include/dict0stats_bg.h14
-rw-r--r--storage/innobase/include/fil0fil.h2
-rw-r--r--storage/innobase/include/fts0fts.h4
-rw-r--r--storage/innobase/include/fts0priv.h20
-rw-r--r--storage/innobase/include/log0log.h2
-rw-r--r--storage/innobase/include/log0log.ic2
-rw-r--r--storage/innobase/include/que0que.h4
-rw-r--r--storage/innobase/include/univ.i1
-rw-r--r--storage/innobase/lock/lock0lock.cc4
-rw-r--r--storage/innobase/pars/pars0pars.cc2
-rw-r--r--storage/innobase/pars/pars0sym.cc2
-rw-r--r--storage/innobase/que/que0que.cc20
-rw-r--r--storage/innobase/row/row0import.cc6
-rw-r--r--storage/innobase/row/row0ins.cc4
-rw-r--r--storage/innobase/row/row0merge.cc10
-rw-r--r--storage/innobase/row/row0mysql.cc17
-rw-r--r--storage/innobase/row/row0purge.cc10
-rw-r--r--storage/innobase/row/row0quiesce.cc4
-rw-r--r--storage/innobase/row/row0uins.cc26
-rw-r--r--storage/innobase/row/row0umod.cc6
-rw-r--r--storage/innobase/row/row0upd.cc4
-rw-r--r--storage/innobase/srv/srv0srv.cc4
-rw-r--r--storage/innobase/trx/trx0trx.cc4
45 files changed, 499 insertions, 574 deletions
diff --git a/mysql-test/suite/perfschema/r/sxlock_func.result b/mysql-test/suite/perfschema/r/sxlock_func.result
index 943f2c9301b..fdc5c59dc16 100644
--- a/mysql-test/suite/perfschema/r/sxlock_func.result
+++ b/mysql-test/suite/perfschema/r/sxlock_func.result
@@ -38,7 +38,6 @@ AND event_name NOT IN
'wait/synch/rwlock/innodb/trx_purge_latch')
ORDER BY event_name;
event_name
-wait/synch/rwlock/innodb/dict_operation_lock
wait/synch/rwlock/innodb/fil_space_latch
wait/synch/rwlock/innodb/lock_latch
SELECT event_name FROM performance_schema.events_waits_history_long
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 7f110541fee..fda5aa82b0e 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -223,12 +223,12 @@ void btr_search_disable()
{
dict_table_t* table;
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
btr_search_x_lock_all();
if (!btr_search_enabled) {
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
btr_search_x_unlock_all();
return;
}
@@ -249,7 +249,7 @@ void btr_search_disable()
btr_search_disable_ref_count(table);
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
/* Set all block->index = NULL. */
buf_pool.clear_hash_index();
@@ -1256,7 +1256,7 @@ retry:
ut_ad(page_is_leaf(block->frame));
/* We must not dereference block->index here, because it could be freed
- if (index->table->n_ref_count == 0).
+ if (!index->table->get_ref_count() && !dict_sys.frozen()).
Determine the ahi_slot based on the block contents. */
const index_id_t index_id
@@ -1429,10 +1429,8 @@ void btr_search_drop_page_hash_when_freed(const page_id_t page_id)
/* In all our callers, the table handle should
be open, or we should be in the process of
dropping the table (preventing eviction). */
-#ifdef SAFE_MUTEX
DBUG_ASSERT(block->index->table->get_ref_count()
- || dict_sys.mutex_is_locked());
-#endif /* SAFE_MUTEX */
+ || dict_sys.locked());
btr_search_drop_page_hash_index(block);
}
}
diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc
index 2792f71376d..e6a46699f02 100644
--- a/storage/innobase/dict/dict0boot.cc
+++ b/storage/innobase/dict/dict0boot.cc
@@ -225,7 +225,7 @@ dict_boot(void)
heap = mem_heap_create(450);
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
/* Get the dictionary header */
const byte* dict_hdr = &dict_hdr_get(&mtr)->frame[DICT_HDR];
@@ -413,10 +413,10 @@ dict_boot(void)
dict_load_sys_table(dict_sys.sys_columns);
dict_load_sys_table(dict_sys.sys_indexes);
dict_load_sys_table(dict_sys.sys_fields);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
dict_sys.load_sys_tables();
} else {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
return(err);
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index 70d9e2bb022..c293ab302a3 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -343,7 +343,7 @@ dict_build_table_def_step(
que_thr_t* thr, /*!< in: query thread */
tab_node_t* node) /*!< in: table create node */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
dict_table_t* table = node->table;
ut_ad(!table->is_temporary());
ut_ad(!table->space);
@@ -403,7 +403,7 @@ dict_build_v_col_def_step(
Based on an index object, this function builds the entry to be inserted
in the SYS_INDEXES system table.
@return the tuple which should be inserted */
-static
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
dtuple_t*
dict_create_sys_indexes_tuple(
/*==========================*/
@@ -416,7 +416,7 @@ dict_create_sys_indexes_tuple(
dfield_t* dfield;
byte* ptr;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(index);
ut_ad(index->table->space || !UT_LIST_GET_LEN(index->table->indexes)
|| index->table->file_unreadable);
@@ -646,7 +646,7 @@ dict_build_index_def_step(
dtuple_t* row;
trx_t* trx;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
trx = thr_get_trx(thr);
@@ -691,7 +691,7 @@ dict_build_index_def(
dict_index_t* index, /*!< in/out: index */
trx_t* trx) /*!< in/out: InnoDB transaction handle */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
|| dict_index_is_clust(index));
@@ -734,7 +734,7 @@ dict_create_index_tree_step(
dict_index_t* index;
dtuple_t* search_tuple;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
index = node->index;
@@ -803,7 +803,7 @@ dict_create_index_tree_in_mem(
{
mtr_t mtr;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(!(index->type & DICT_FTS));
mtr_start(&mtr);
@@ -833,7 +833,7 @@ uint32_t dict_drop_index_tree(btr_pcur_t *pcur, trx_t *trx, mtr_t *mtr)
{
rec_t *rec= btr_pcur_get_rec(pcur);
- ut_d(if (trx) dict_sys.assert_locked());
+ ut_ad(!trx || dict_sys.locked());
ut_ad(!dict_table_is_comp(dict_sys.sys_indexes));
btr_pcur_store_position(pcur, mtr);
@@ -995,7 +995,7 @@ dict_create_table_step(
trx_t* trx;
ut_ad(thr);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
trx = thr_get_trx(thr);
@@ -1171,7 +1171,7 @@ dict_create_index_step(
trx_t* trx;
ut_ad(thr);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
trx = thr_get_trx(thr);
@@ -1319,7 +1319,7 @@ bool dict_sys_t::load_sys_tables()
{
ut_ad(!srv_any_background_activity());
bool mismatch= false;
- mutex_lock();
+ lock(SRW_LOCK_CALL);
if (!(sys_foreign= load_table(SYS_TABLE[SYS_FOREIGN],
DICT_ERR_IGNORE_FK_NOKEY)));
else if (UT_LIST_GET_LEN(sys_foreign->indexes) == 3 &&
@@ -1354,7 +1354,7 @@ bool dict_sys_t::load_sys_tables()
mismatch= true;
ib::error() << "Invalid definition of SYS_VIRTUAL";
}
- mutex_unlock();
+ unlock();
return mismatch;
}
@@ -1453,13 +1453,13 @@ err_exit:
trx->free();
srv_file_per_table= srv_file_per_table_backup;
- mutex_lock();
+ lock(SRW_LOCK_CALL);
if (sys_foreign);
else if (!(sys_foreign= load_table(SYS_TABLE[SYS_FOREIGN])))
{
tablename= SYS_TABLE[SYS_FOREIGN].data();
load_fail:
- mutex_unlock();
+ unlock();
ib::error() << "Failed to CREATE TABLE " << tablename;
return DB_TABLE_NOT_FOUND;
}
@@ -1484,7 +1484,7 @@ load_fail:
else
prevent_eviction(sys_virtual);
- mutex_unlock();
+ unlock();
return DB_SUCCESS;
}
@@ -1877,7 +1877,7 @@ dict_create_add_foreigns_to_dictionary(
const dict_table_t* table,
trx_t* trx)
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
if (!dict_sys.sys_foreign)
{
diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc
index 4be6a28882e..bcbe0513dd9 100644
--- a/storage/innobase/dict/dict0defrag_bg.cc
+++ b/storage/innobase/dict/dict0defrag_bg.cc
@@ -145,7 +145,7 @@ dict_stats_defrag_pool_del(
{
ut_a((table && !index) || (!table && index));
ut_ad(!srv_read_only_mode);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
mysql_mutex_lock(&defrag_pool_mutex);
@@ -187,7 +187,7 @@ dict_stats_process_entry_from_defrag_pool()
dict_table_t* table;
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
/* If the table is no longer cached, we've already lost the in
memory stats so there's nothing really to write to disk. */
@@ -202,11 +202,11 @@ dict_stats_process_entry_from_defrag_pool()
if (table) {
dict_table_close(table, TRUE, FALSE);
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
return;
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
dict_stats_save_defrag_stats(index);
dict_table_close(table, FALSE, FALSE);
}
@@ -237,7 +237,7 @@ dict_stats_save_defrag_summary(
return DB_SUCCESS;
}
- dict_sys_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
ret = dict_stats_save_index_stat(index, time(NULL), "n_pages_freed",
index->stat_defrag_n_pages_freed,
@@ -246,7 +246,7 @@ dict_stats_save_defrag_summary(
" last defragmentation run.",
NULL);
- dict_sys_unlock();
+ dict_sys.unlock();
return (ret);
}
@@ -331,7 +331,7 @@ dict_stats_save_defrag_stats(
return DB_SUCCESS;
}
- dict_sys_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
ret = dict_stats_save_index_stat(index, now, "n_page_split",
index->stat_defrag_n_page_split,
NULL,
@@ -361,6 +361,6 @@ dict_stats_save_defrag_stats(
NULL);
end:
- dict_sys_unlock();
+ dict_sys.unlock();
return ret;
}
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 9c4eb741bad..8f5a0495777 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -86,7 +86,7 @@ const span<const char> dict_sys_t::SYS_TABLE[]=
/** Diagnostic message for exceeding the mutex_lock_wait() timeout */
const char dict_sys_t::fatal_msg[]=
- "innodb_fatal_semaphore_wait_threshold was exceeded for dict_sys.mutex. "
+ "innodb_fatal_semaphore_wait_threshold was exceeded for dict_sys.latch. "
"Please refer to "
"https://mariadb.com/kb/en/how-to-produce-a-full-stack-trace-for-mysqld/";
@@ -272,11 +272,10 @@ dict_table_try_drop_aborted(
/**********************************************************************//**
When opening a table,
try to drop any indexes after an aborted index creation.
-Release the dict_sys.mutex. */
+Invoke dict_sys.unlock(). */
static
void
-dict_table_try_drop_aborted_and_mutex_exit(
-/*=======================================*/
+dict_table_try_drop_aborted_and_unlock(
dict_table_t* table, /*!< in: table (may be NULL) */
ibool try_drop) /*!< in: FALSE if should try to
drop indexes whose online creation
@@ -292,11 +291,11 @@ dict_table_try_drop_aborted_and_mutex_exit(
was aborted. */
table_id_t table_id = table->id;
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
dict_table_try_drop_aborted(table, table_id, 1);
} else {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
}
@@ -317,10 +316,10 @@ dict_table_close(
MDL_ticket* mdl)
{
if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_a(table->get_ref_count() > 0);
const bool last_handle = table->release();
@@ -330,8 +329,9 @@ dict_table_close(
if they have been manually modified. We reset table->stat_initialized
only if table reference count is 0 because we do not want too frequent
stats re-reads (e.g. in other cases than FLUSH TABLE). */
- if (last_handle && strchr(table->name.m_name, '/') != NULL
- && dict_stats_is_persistent_enabled(table)) {
+ if (last_handle
+ && dict_stats_is_persistent_enabled(table)
+ && strchr(table->name.m_name, '/')) {
table->stats_mutex_lock();
dict_stats_deinit(table);
@@ -347,7 +347,7 @@ dict_table_close(
&& table->drop_aborted
&& dict_table_get_first_index(table);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
/* dict_table_try_drop_aborted() can generate undo logs.
So it should be avoided after shutdown of background
@@ -691,7 +691,7 @@ dict_index_get_nth_field_pos(
}
/** Parse the table file name into table name and database name.
-@tparam dict_locked whether dict_sys.mutex is being held
+@tparam dict_locked whether dict_sys.lock() was called
@param[in,out] db_name database name buffer
@param[in,out] tbl_name table name buffer
@param[out] db_name_len database name length
@@ -706,8 +706,8 @@ bool dict_table_t::parse_name(char (&db_name)[NAME_LEN + 1],
char tbl_buf[MAX_TABLE_NAME_LEN + 1];
if (!dict_locked)
- dict_sys.mutex_lock(); /* protect against renaming */
- dict_sys.assert_locked();
+ dict_sys.freeze(SRW_LOCK_CALL); /* protect against renaming */
+ ut_ad(dict_sys.frozen());
const size_t db_len= name.dblen();
ut_ad(db_len <= MAX_DATABASE_NAME_LEN);
@@ -726,7 +726,7 @@ bool dict_table_t::parse_name(char (&db_name)[NAME_LEN + 1],
tbl_buf[tbl_len]= 0;
if (!dict_locked)
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
*db_name_len= filename_to_tablename(db_buf, db_name,
MAX_DATABASE_NAME_LEN + 1, true);
@@ -766,13 +766,13 @@ dict_acquire_mdl_shared(dict_table_t *table,
if (trylock)
{
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
db_len= dict_get_db_name_len(table->name.m_name);
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
}
else
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
db_len= dict_get_db_name_len(table->name.m_name);
}
@@ -811,7 +811,7 @@ is_unaccessible:
return nullptr;
if (!trylock)
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
{
MDL_request request;
MDL_REQUEST_INIT(&request,MDL_key::TABLE, db_buf, tbl_buf, MDL_SHARED, MDL_EXPLICIT);
@@ -832,7 +832,7 @@ is_unaccessible:
}
if (!trylock)
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
else if (!*mdl)
return nullptr;
@@ -903,10 +903,10 @@ dict_table_open_on_id(table_id_t table_id, bool dict_locked,
MDL_ticket **mdl)
{
if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
dict_table_t* table = dict_table_open_on_id_low(
table_id,
@@ -925,7 +925,7 @@ dict_table_open_on_id(table_id_t table_id, bool dict_locked,
table, thd, mdl, table_op);
}
- dict_table_try_drop_aborted_and_mutex_exit(
+ dict_table_try_drop_aborted_and_unlock(
table, table_op == DICT_TABLE_OP_DROP_ORPHAN);
}
@@ -991,8 +991,6 @@ void dict_sys_t::create()
UT_LIST_INIT(table_LRU, &dict_table_t::table_LRU);
UT_LIST_INIT(table_non_LRU, &dict_table_t::table_LRU);
- mysql_mutex_init(dict_sys_mutex_key, &mutex, nullptr);
-
const ulint hash_size = buf_pool_get_curr_size()
/ (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE);
@@ -1026,14 +1024,17 @@ inline void dict_sys_t::acquire(dict_table_t *table)
table->acquire();
}
-void dict_sys_t::mutex_lock_wait()
+void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line))
{
ulonglong now= my_hrtime_coarse().val, old= 0;
- if (mutex_wait_start.compare_exchange_strong
+ if (latch_ex_wait_start.compare_exchange_strong
(old, now, std::memory_order_relaxed, std::memory_order_relaxed))
{
- mysql_mutex_lock(&mutex);
- mutex_wait_start.store(0, std::memory_order_relaxed);
+ latch.wr_lock(SRW_LOCK_ARGS(file, line));
+ latch_ex_wait_start.store(0, std::memory_order_relaxed);
+ ut_ad(!latch_readers);
+ ut_ad(!latch_ex);
+ ut_d(latch_ex= true);
return;
}
@@ -1047,32 +1048,36 @@ void dict_sys_t::mutex_lock_wait()
if (waited > threshold / 4)
ib::warn() << "A long wait (" << waited
- << " seconds) was observed for dict_sys.mutex";
- mysql_mutex_lock(&mutex);
+ << " seconds) was observed for dict_sys.latch";
+ latch.wr_lock(SRW_LOCK_ARGS(file, line));
+ ut_ad(!latch_readers);
+ ut_ad(!latch_ex);
+ ut_d(latch_ex= true);
}
-#ifdef HAVE_PSI_MUTEX_INTERFACE
-/** Acquire the mutex */
-void dict_sys_t::mutex_lock()
+#ifdef UNIV_PFS_RWLOCK
+ATTRIBUTE_NOINLINE void dict_sys_t::unlock()
{
- if (mysql_mutex_trylock(&mutex))
- mutex_lock_wait();
+ ut_ad(latch_ex);
+ ut_ad(!latch_readers);
+ ut_d(latch_ex= false);
+ latch.wr_unlock();
}
-/** Release the mutex */
-void dict_sys_t::mutex_unlock() { mysql_mutex_unlock(&mutex); }
-#endif
+ATTRIBUTE_NOINLINE void dict_sys_t::freeze(const char *file, unsigned line)
+{
+ latch.rd_lock(file, line);
+ ut_ad(!latch_ex);
+ ut_d(latch_readers++);
+}
-/** Lock the data dictionary cache. */
-void dict_sys_t::lock(SRW_LOCK_ARGS(const char *file, unsigned line))
+ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze()
{
- ut_ad(this == &dict_sys);
- ut_ad(is_initialised());
- latch.wr_lock(SRW_LOCK_ARGS(file, line));
ut_ad(!latch_ex);
- ut_d(latch_ex= true);
- mutex_lock();
+ ut_ad(latch_readers--);
+ latch.rd_unlock();
}
+#endif /* UNIV_PFS_RWLOCK */
/**********************************************************************//**
Returns a table object and increment its open handle count.
@@ -1097,7 +1102,7 @@ dict_table_open_on_name(
DBUG_PRINT("dict_table_open_on_name", ("table: '%s'", table_name));
if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
ut_ad(table_name);
@@ -1118,17 +1123,13 @@ dict_table_open_on_name(
ib::error() << "Table " << table->name
<< " is corrupted. Please "
"drop the table and recreate.";
- if (!dict_locked) {
- dict_sys.mutex_unlock();
- }
-
- DBUG_RETURN(NULL);
+ table = nullptr;
+ } else {
+ dict_sys.acquire(table);
}
- dict_sys.acquire(table);
-
if (!dict_locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
DBUG_RETURN(table);
@@ -1140,7 +1141,7 @@ dict_table_open_on_name(
ut_ad(dict_lru_validate());
if (!dict_locked) {
- dict_table_try_drop_aborted_and_mutex_exit(table, try_drop);
+ dict_table_try_drop_aborted_and_unlock(table, try_drop);
}
DBUG_RETURN(table);
@@ -1252,7 +1253,7 @@ inline void dict_sys_t::add(dict_table_t* table)
@return whether the table can be evicted */
static bool dict_table_can_be_evicted(dict_table_t *table)
{
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ut_a(table->can_be_evicted);
ut_a(table->foreign_set.empty());
ut_a(table->referenced_set.empty());
@@ -1421,8 +1422,8 @@ dict_table_find_index_on_id(
}
/**********************************************************************//**
-Looks for an index with the given id. NOTE that we do not reserve
-the dictionary mutex: this function is for emergency purposes like
+Looks for an index with the given id. NOTE that we do not acquire
+dict_sys.latch: this function is for emergency purposes like
printing info of a corrupt database page!
@return index or NULL if not found in cache */
dict_index_t*
@@ -1538,7 +1539,7 @@ dict_table_rename_in_cache(
ulint fold;
char old_name[MAX_FULL_NAME_LEN + 1];
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* store the old/current name to an automatic variable */
const size_t old_name_len = strlen(table->name.m_name);
@@ -1862,7 +1863,7 @@ dict_table_change_id_in_cache(
dict_table_t* table, /*!< in/out: table object already in cache */
table_id_t new_id) /*!< in: new id to set */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(!table->is_temporary());
@@ -1941,7 +1942,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_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
/* Mimic row_mysql_lock_data_dictionary(). */
trx->dict_operation_lock_mode = RW_X_LATCH;
@@ -2024,7 +2025,7 @@ dict_index_add_to_cache(
ulint n_ord;
ulint i;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(index->n_def == index->n_fields);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(!dict_index_is_online_ddl(index));
@@ -2152,7 +2153,7 @@ dict_index_remove_from_cache_low(
ut_ad(table && index);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(table->id);
#ifdef BTR_CUR_HASH_ADAPT
ut_ad(!index->freed());
@@ -2232,7 +2233,7 @@ dict_index_find_cols(
const dict_table_t* table = index->table;
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
for (ulint i = 0; i < index->n_fields; i++) {
ulint j;
@@ -2501,7 +2502,7 @@ dict_index_build_internal_clust(
ut_ad(index->is_primary());
ut_ad(!index->has_virtual());
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* Create a new index object with certainly enough fields */
new_index = dict_mem_index_create(index->table, index->name,
@@ -2656,7 +2657,7 @@ dict_index_build_internal_non_clust(
ut_ad(table && index);
ut_ad(!dict_index_is_clust(index));
ut_ad(!dict_index_is_ibuf(index));
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* The clustered index should be the first in the list of indexes */
clust_index = UT_LIST_GET_FIRST(table->indexes);
@@ -2750,7 +2751,7 @@ dict_index_build_internal_fts(
dict_index_t* new_index;
ut_ad(index->type == DICT_FTS);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* Create a new index */
new_index = dict_mem_index_create(index->table, index->name,
@@ -2802,7 +2803,7 @@ dict_foreign_remove_from_cache(
/*===========================*/
dict_foreign_t* foreign) /*!< in, own: foreign constraint */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_a(foreign);
if (foreign->referenced_table != NULL) {
@@ -2827,7 +2828,7 @@ dict_foreign_find(
dict_table_t* table, /*!< in: table object */
dict_foreign_t* foreign) /*!< in: foreign constraint */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
ut_ad(dict_foreign_set_validate(table->foreign_set));
ut_ad(dict_foreign_set_validate(table->referenced_set));
@@ -2881,7 +2882,7 @@ dict_foreign_find_index(
/*!< out: index where error
happened */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
if (error) {
*error = FK_INDEX_NOT_FOUND;
@@ -2979,7 +2980,7 @@ dict_foreign_add_to_cache(
DBUG_ENTER("dict_foreign_add_to_cache");
DBUG_PRINT("dict_foreign_add_to_cache", ("id: %s", foreign->id));
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
for_table = dict_sys.find_table(
{foreign->foreign_table_name_lookup,
@@ -3626,7 +3627,7 @@ dict_foreign_parse_drop_constraints(
ptr = str;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
loop:
ptr = dict_scan_to(ptr, "DROP");
@@ -3728,14 +3729,14 @@ syntax_error:
/**********************************************************************//**
Returns an index object if it is found in the dictionary cache.
-Assumes that dict_sys.mutex is already being held.
+Assumes that dict_sys.latch is already being held.
@return index, NULL if not found */
dict_index_t*
dict_index_get_if_in_cache_low(
/*===========================*/
index_id_t index_id) /*!< in: index id */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
return(dict_index_find_on_id_low(index_id));
}
@@ -3755,11 +3756,11 @@ dict_index_get_if_in_cache(
return(NULL);
}
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
index = dict_index_get_if_in_cache_low(index_id);
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
return(index);
}
@@ -4045,7 +4046,7 @@ dict_print_info_on_foreign_keys(
dict_foreign_t* foreign;
std::string str;
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
@@ -4112,7 +4113,7 @@ dict_print_info_on_foreign_keys(
}
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
return str;
}
@@ -4210,7 +4211,7 @@ dict_set_corrupted(
row_mysql_lock_data_dictionary(trx);
}
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(!dict_table_is_comp(dict_sys.sys_tables));
ut_ad(!dict_table_is_comp(dict_sys.sys_indexes));
@@ -4298,7 +4299,7 @@ dict_set_corrupted_index_cache_only(
{
ut_ad(index != NULL);
ut_ad(index->table != NULL);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(!dict_table_is_comp(dict_sys.sys_tables));
ut_ad(!dict_table_is_comp(dict_sys.sys_indexes));
@@ -4332,13 +4333,13 @@ 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));
- dict_sys_lock();
-
heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
+ sizeof(que_fork_t) + sizeof(upd_node_t)
+ sizeof(upd_t) + 12));
- mtr_start(&mtr);
+ mtr.start();
+
+ dict_sys.lock(SRW_LOCK_CALL);
sys_index = UT_LIST_GET_FIRST(dict_sys.sys_indexes->indexes);
@@ -4376,7 +4377,7 @@ dict_index_set_merge_threshold(
mtr_commit(&mtr);
mem_heap_free(heap);
- dict_sys_unlock();
+ dict_sys.unlock();
}
#ifdef UNIV_DEBUG
@@ -4408,14 +4409,14 @@ void
dict_set_merge_threshold_all_debug(
uint merge_threshold_all)
{
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
dict_set_merge_threshold_list_debug(
&dict_sys.table_LRU, merge_threshold_all);
dict_set_merge_threshold_list_debug(
&dict_sys.table_non_LRU, merge_threshold_all);
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
}
#endif /* UNIV_DEBUG */
@@ -4533,7 +4534,7 @@ dict_table_check_for_dup_indexes(
const dict_index_t* index1;
const dict_index_t* index2;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
/* The primary index _must_ exist */
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
@@ -4645,7 +4646,7 @@ void dict_sys_t::resize()
{
ut_ad(this == &dict_sys);
ut_ad(is_initialised());
- mutex_lock();
+ lock(SRW_LOCK_CALL);
/* all table entries are in table_LRU and table_non_LRU lists */
table_hash.free();
@@ -4683,7 +4684,7 @@ void dict_sys_t::resize()
HASH_INSERT(dict_table_t, id_hash, id_hash, id_fold, table);
}
- mutex_unlock();
+ unlock();
}
/** Close the data dictionary cache on shutdown. */
@@ -4692,10 +4693,10 @@ void dict_sys_t::close()
ut_ad(this == &dict_sys);
if (!is_initialised()) return;
- mutex_lock();
+ lock(SRW_LOCK_CALL);
- /* Free the hash elements. We don't remove them from the table
- because we are going to destroy the table anyway. */
+ /* Free the hash elements. We don't remove them from table_hash
+ because we are invoking table_hash.free() below. */
for (ulint i= table_hash.n_cells; i--; )
while (dict_table_t *table= static_cast<dict_table_t*>
(HASH_GET_FIRST(&table_hash, i)))
@@ -4710,8 +4711,7 @@ void dict_sys_t::close()
/* No temporary tables should exist at this point. */
temp_id_hash.free();
- mutex_unlock();
- mysql_mutex_destroy(&mutex);
+ unlock();
latch.destroy();
mysql_mutex_destroy(&dict_foreign_err_mutex);
@@ -4736,7 +4736,7 @@ dict_lru_validate(void)
{
dict_table_t* table;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
for (table = UT_LIST_GET_FIRST(dict_sys.table_LRU);
table != NULL;
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index db11f4ff003..74275b77bb0 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -509,7 +509,7 @@ dict_sys_tables_rec_check(
const byte* field;
ulint len;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
if (rec_get_deleted_flag(rec, 0)) {
return("delete-marked record in SYS_TABLES");
@@ -828,7 +828,7 @@ static ulint dict_check_sys_tables()
DBUG_ENTER("dict_check_sys_tables");
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
mtr_start(&mtr);
@@ -934,7 +934,7 @@ void dict_check_tablespaces_and_store_max_id()
DBUG_ENTER("dict_check_tablespaces_and_store_max_id");
- dict_sys_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
/* Initialize the max space_id from sys header */
mtr.start();
@@ -949,7 +949,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);
- dict_sys_unlock();
+ dict_sys.unlock();
DBUG_VOID_RETURN;
}
@@ -1237,7 +1237,7 @@ dict_load_columns(
mtr_t mtr;
ulint n_skipped = 0;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
mtr_start(&mtr);
@@ -1351,7 +1351,7 @@ dict_load_virtual_one_col(
mtr_t mtr;
ulint skipped = 0;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
if (v_col->num_base == 0) {
return;
@@ -1581,7 +1581,7 @@ dict_load_fields(
mtr_t mtr;
dberr_t error;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
mtr_start(&mtr);
@@ -1811,7 +1811,7 @@ dict_load_indexes(
mtr_t mtr;
dberr_t error = DB_SUCCESS;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
mtr_start(&mtr);
@@ -2122,7 +2122,7 @@ dict_save_data_dir_path(
dict_table_t* table, /*!< in/out: table */
const char* filepath) /*!< in: filepath of tablespace */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
ut_a(DICT_TF_HAS_DATA_DIR(table->flags));
ut_a(!table->data_dir_path);
@@ -2145,20 +2145,17 @@ dict_save_data_dir_path(
}
}
-/** Make sure the data_dir_path is saved in dict_table_t if needed.
-@param[in] table Table object
-@param[in] dict_mutex_own true if dict_sys.mutex is owned already */
-void
-dict_get_and_save_data_dir_path(
- dict_table_t* table,
- bool dict_mutex_own)
+/** Make sure the data_file_name is saved in dict_table_t if needed.
+@param[in,out] table Table object
+@param[in] dict_locked dict_sys.frozen() */
+void dict_get_and_save_data_dir_path(dict_table_t* table, bool dict_locked)
{
ut_ad(!table->is_temporary());
ut_ad(!table->space || table->space->id == table->space_id);
if (!table->data_dir_path && table->space_id && table->space) {
- if (!dict_mutex_own) {
- dict_sys.mutex_lock();
+ if (!dict_locked) {
+ dict_sys.freeze(SRW_LOCK_CALL);
}
table->flags |= 1 << DICT_TF_POS_DATA_DIR
@@ -2176,8 +2173,8 @@ dict_get_and_save_data_dir_path(
& ((1U << DICT_TF_BITS) - 1);
}
- if (!dict_mutex_own) {
- dict_sys.mutex_unlock();
+ if (!dict_locked) {
+ dict_sys.unfreeze();
}
}
}
@@ -2288,7 +2285,7 @@ static dict_table_t *dict_load_table_one(const span<const char> &name,
DBUG_PRINT("dict_load_table_one",
("table: %.*s", name.size(), name.data()));
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
heap = mem_heap_create(32000);
@@ -2544,10 +2541,10 @@ dict_load_table_on_id(
ulint len;
mtr_t mtr;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* NOTE that the operation of this function is protected by
- the dictionary mutex, and therefore no deadlocks can occur
+ dict_sys.latch, and therefore no deadlocks can occur
with other dictionary operations. */
mtr.start();
@@ -2627,7 +2624,7 @@ dict_load_sys_table(
{
mem_heap_t* heap;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
heap = mem_heap_create(1000);
@@ -2662,7 +2659,7 @@ dict_load_foreign_cols(
mtr_t mtr;
size_t id_len;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
id_len = strlen(foreign->id);
@@ -2804,7 +2801,7 @@ dict_load_foreign(
DBUG_PRINT("dict_load_foreign",
("id: '%s', check_recursive: %d", id, check_recursive));
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
id_len = strlen(id);
@@ -2977,7 +2974,7 @@ dict_load_foreigns(
DBUG_ENTER("dict_load_foreigns");
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
if (!dict_sys.sys_foreign || !dict_sys.sys_foreign_cols) {
if (ignore_err & DICT_ERR_IGNORE_FK_NOKEY) {
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index eb2f06ab31e..ee72d7db3cd 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -326,7 +326,6 @@ static bool innodb_index_stats_not_found_reported;
Checks whether a table exists and whether it has the given structure.
The table must have the same number of columns with the same names and
types. The order of the columns does not matter.
-The caller must own the dictionary mutex.
dict_table_schema_check() @{
@return DB_SUCCESS if the table exists and contains the necessary columns */
static
@@ -478,21 +477,16 @@ dict_table_schema_check(
Checks whether the persistent statistics storage exists and that all
tables have the proper structure.
@return true if exists and all tables are ok */
-static
-bool
-dict_stats_persistent_storage_check(
-/*================================*/
- bool caller_has_dict_sys_mutex) /*!< in: true if the caller
- owns dict_sys.mutex */
+static bool dict_stats_persistent_storage_check(bool dict_already_locked)
{
char errstr[512];
dberr_t ret;
- if (!caller_has_dict_sys_mutex) {
- dict_sys.mutex_lock();
+ if (!dict_already_locked) {
+ dict_sys.lock(SRW_LOCK_CALL);
}
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* first check table_stats */
ret = dict_table_schema_check(&table_stats_schema, errstr,
@@ -503,8 +497,8 @@ dict_stats_persistent_storage_check(
sizeof(errstr));
}
- if (!caller_has_dict_sys_mutex) {
- dict_sys.mutex_unlock();
+ if (!dict_already_locked) {
+ dict_sys.unlock();
}
if (ret != DB_SUCCESS && ret != DB_STATS_DO_NOT_EXIST) {
@@ -530,7 +524,7 @@ only in the case of error, but not freed.
static
dberr_t dict_stats_exec_sql(pars_info_t *pinfo, const char* sql, trx_t *trx)
{
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
if (!dict_stats_persistent_storage_check(true))
{
@@ -1014,7 +1008,7 @@ dict_table_t*
dict_stats_snapshot_create(
dict_table_t* table)
{
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
dict_stats_assert_initialized(table);
@@ -1035,7 +1029,7 @@ dict_stats_snapshot_create(
t->stats_sample_pages = table->stats_sample_pages;
t->stats_bg_flag = table->stats_bg_flag;
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
return(t);
}
@@ -1074,14 +1068,13 @@ dict_stats_update_transient_for_index(
Initialize some bogus index cardinality
statistics, so that the data can be queried in
various means, also via secondary indexes. */
+dummy_empty:
index->table->stats_mutex_lock();
dict_stats_empty_index(index, false);
index->table->stats_mutex_unlock();
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
} else if (ibuf_debug && !dict_index_is_clust(index)) {
- index->table->stats_mutex_lock();
- dict_stats_empty_index(index, false);
- index->table->stats_mutex_unlock();
+ goto dummy_empty;
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
} else {
mtr_t mtr;
@@ -1102,10 +1095,7 @@ dict_stats_update_transient_for_index(
switch (size) {
case ULINT_UNDEFINED:
- index->table->stats_mutex_lock();
- dict_stats_empty_index(index, false);
- index->table->stats_mutex_unlock();
- return;
+ goto dummy_empty;
case 0:
/* The root node of the tree is a leaf */
size = 1;
@@ -2586,7 +2576,7 @@ dict_stats_save_index_stat(
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
dict_fs2utf8(index->table->name.m_name, db_utf8, sizeof(db_utf8),
table_utf8, sizeof(table_utf8));
@@ -2722,7 +2712,7 @@ dict_stats_save(
trx_t* trx = trx_create();
trx_start_internal(trx);
trx->dict_operation_lock_mode = RW_X_LATCH;
- dict_sys_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
pinfo = pars_info_create();
@@ -2764,7 +2754,7 @@ rollback_and_exit:
trx->rollback();
free_and_exit:
trx->dict_operation_lock_mode = 0;
- dict_sys_unlock();
+ dict_sys.unlock();
trx->free();
dict_stats_snapshot_free(table);
return ret;
@@ -3634,7 +3624,7 @@ dberr_t dict_stats_delete_from_table_stats(const char *database_name,
{
pars_info_t* pinfo;
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
pinfo = pars_info_create();
@@ -3661,7 +3651,7 @@ dberr_t dict_stats_delete_from_index_stats(const char *database_name,
{
pars_info_t* pinfo;
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
pinfo = pars_info_create();
@@ -3690,7 +3680,7 @@ dberr_t dict_stats_delete_from_index_stats(const char *database_name,
{
pars_info_t* pinfo;
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
pinfo = pars_info_create();
diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc
index dbaff373ac4..2ac5f76f3c1 100644
--- a/storage/innobase/dict/dict0stats_bg.cc
+++ b/storage/innobase/dict/dict0stats_bg.cc
@@ -146,8 +146,6 @@ schedule new estimates for table and index statistics to be calculated.
void dict_stats_update_if_needed_func(dict_table_t *table)
#endif
{
- dict_sys.assert_not_locked();
-
if (UNIV_UNLIKELY(!table->stat_initialized)) {
/* The table may have been evicted from dict_sys
and reloaded internally by InnoDB for FOREIGN KEY
@@ -258,7 +256,7 @@ dict_stats_recalc_pool_del(
const dict_table_t* table) /*!< in: table to remove */
{
ut_ad(!srv_read_only_mode);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
mysql_mutex_lock(&recalc_pool_mutex);
@@ -280,13 +278,9 @@ dict_stats_recalc_pool_del(
/*****************************************************************//**
Wait until background stats thread has stopped using the specified table.
-The caller must have locked the data dictionary using
-row_mysql_lock_data_dictionary() and this function may unlock it temporarily
-and restore the lock before it exits.
The background stats thread is guaranteed not to start using the specified
-table after this function returns and before the caller unlocks the data
-dictionary because it sets the BG_STAT_IN_PROGRESS bit in table->stats_bg_flag
-under dict_sys.mutex. */
+table after this function returns and before the caller releases
+dict_sys.latch. */
void
dict_stats_wait_bg_to_stop_using_table(
/*===================================*/
@@ -347,7 +341,7 @@ next_table_id:
dict_table_t* table;
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
table = dict_table_open_on_id(table_id, TRUE, DICT_TABLE_OP_NORMAL);
@@ -362,13 +356,13 @@ next_table_id:
if (!table->is_accessible()) {
dict_table_close(table, TRUE, FALSE);
no_table:
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
goto next_table_id;
}
table->stats_bg_flag |= BG_STAT_IN_PROGRESS;
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
/* time() could be expensive, the current function
is called once every time a table has been changed more than 10% and
@@ -393,13 +387,13 @@ no_table:
ret = true;
}
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
table->stats_bg_flag = BG_STAT_NONE;
dict_table_close(table, TRUE, FALSE);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
return ret;
}
diff --git a/storage/innobase/dict/drop.cc b/storage/innobase/dict/drop.cc
index b2aab6992bb..bb0af50c4c2 100644
--- a/storage/innobase/dict/drop.cc
+++ b/storage/innobase/dict/drop.cc
@@ -78,7 +78,7 @@ before transaction commit and must be rolled back explicitly are as follows:
@return error code */
dberr_t trx_t::drop_table_foreign(const table_name_t &name)
{
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ut_ad(state == TRX_STATE_ACTIVE);
ut_ad(dict_operation);
ut_ad(dict_operation_lock_mode == RW_X_LATCH);
@@ -116,7 +116,7 @@ dberr_t trx_t::drop_table_foreign(const table_name_t &name)
@return error code */
dberr_t trx_t::drop_table_statistics(const table_name_t &name)
{
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ut_ad(dict_operation_lock_mode == RW_X_LATCH);
if (strstr(name.m_name, "/" TEMP_FILE_PREFIX_INNODB) ||
@@ -143,7 +143,7 @@ dberr_t trx_t::drop_table_statistics(const table_name_t &name)
@return error code */
dberr_t trx_t::drop_table(const dict_table_t &table)
{
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ut_ad(state == TRX_STATE_ACTIVE);
ut_ad(dict_operation);
ut_ad(dict_operation_lock_mode == RW_X_LATCH);
@@ -235,7 +235,7 @@ void trx_t::commit(std::vector<pfs_os_file_t> &deleted)
commit_persist();
if (dict_operation)
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
for (const auto &p : mod_tables)
{
if (p.second.is_dropped())
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index dea9cf740c9..2c917c6b23e 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -2098,7 +2098,7 @@ to the .err log. This function is used to open a tablespace when we start
mysqld after the dictionary has been booted, and also in IMPORT TABLESPACE.
NOTE that we assume this operation is used either at the database startup
-or under the protection of the dictionary mutex, so that two users cannot
+or under the protection of dict_sys.latch, so that two users cannot
race here. This operation does not leave the file associated with the
tablespace open, but closes it after we have looked at the space id in it.
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 885b0432ebf..5303c0d6179 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -159,6 +159,7 @@ const fts_index_selector_t fts_index_selector[] = {
/** Default config values for FTS indexes on a table. */
static const char* fts_config_table_insert_values_sql =
+ "PROCEDURE P() IS\n"
"BEGIN\n"
"\n"
"INSERT INTO $config_table VALUES('"
@@ -174,7 +175,8 @@ static const char* fts_config_table_insert_values_sql =
FTS_TOTAL_DELETED_COUNT "', '0');\n"
"" /* Note: 0 == FTS_TABLE_STATE_RUNNING */
"INSERT INTO $config_table VALUES ('"
- FTS_TABLE_STATE "', '0');\n";
+ FTS_TABLE_STATE "', '0');\n"
+ "END;\n";
/** FTS tokenize parmameter for plugin parser */
struct fts_tokenize_param_t {
@@ -185,9 +187,9 @@ struct fts_tokenize_param_t {
/** Free a query graph */
void fts_que_graph_free(que_t *graph)
{
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
que_graph_free(graph);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
/** Run SYNC on the table, i.e., write out data from the cache to the
@@ -455,7 +457,7 @@ fts_load_user_stopword(
fts_stopword_t* stopword_info) /*!< in: Stopword info */
{
if (!fts->dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
/* Validate the user table existence in the right format */
@@ -464,7 +466,7 @@ fts_load_user_stopword(
if (!stopword_info->charset) {
cleanup:
if (!fts->dict_locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
return ret;
@@ -489,8 +491,9 @@ cleanup:
pars_info_bind_function(info, "my_func", fts_read_stopword,
stopword_info);
- que_t* graph = fts_parse_sql_no_dict_lock(
+ que_t* graph = pars_sql(
info,
+ "PROCEDURE P() IS\n"
"DECLARE FUNCTION my_func;\n"
"DECLARE CURSOR c IS"
" SELECT value"
@@ -504,7 +507,8 @@ cleanup:
" EXIT;\n"
" END IF;\n"
"END LOOP;\n"
- "CLOSE c;");
+ "CLOSE c;"
+ "END;\n");
for (;;) {
dberr_t error = fts_eval_sql(trx, graph);
@@ -882,7 +886,7 @@ fts_drop_index(
}
/****************************************************************//**
-Free the query graph but check whether dict_sys.mutex is already
+Free the query graph but check whether dict_sys.latch is already
held */
void
fts_que_graph_free_check_lock(
@@ -904,15 +908,15 @@ fts_que_graph_free_check_lock(
}
if (!has_dict) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
que_graph_free(graph);
if (!has_dict) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
}
@@ -1549,19 +1553,19 @@ static dberr_t fts_lock_table(trx_t *trx, const char *table_name)
{
dberr_t err= lock_table_for_trx(table, trx, LOCK_X);
/* Wait for purge threads to stop using the table. */
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
for (uint n= 15; table->get_ref_count() > 1; )
{
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
if (!--n)
{
err= DB_LOCK_WAIT_TIMEOUT;
goto fail;
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
fail:
table->release();
return err;
@@ -1903,7 +1907,7 @@ fts_create_common_tables(
fts_get_table_name(&fts_table, fts_name, true);
pars_info_bind_id(info, true, "config_table", fts_name);
- graph = fts_parse_sql_no_dict_lock(
+ graph = pars_sql(
info, fts_config_table_insert_values_sql);
error = fts_eval_sql(trx, graph);
@@ -2047,8 +2051,7 @@ fts_create_index_tables(trx_t* trx, const dict_index_t* index, table_id_t id)
dict_table_t* new_table;
/* Create the FTS auxiliary tables that are specific
- to an FTS index. We need to preserve the table_id %s
- which fts_parse_sql_no_dict_lock() will fill in for us. */
+ to an FTS index. */
fts_table.suffix = fts_get_suffix(i);
new_table = fts_create_one_index_table(
@@ -6036,8 +6039,6 @@ fts_init_index(
fts_cache_t* cache = table->fts->cache;
bool need_init = false;
- dict_sys.assert_not_locked();
-
/* First check cache->get_docs is initialized */
if (!has_cache_lock) {
mysql_mutex_lock(&cache->lock);
@@ -6101,10 +6102,10 @@ func_exit:
}
if (need_init) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
/* Register the table with the optimize thread. */
fts_optimize_add_table(table);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
}
diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc
index 7a83930fb1a..40947a16d71 100644
--- a/storage/innobase/fts/fts0opt.cc
+++ b/storage/innobase/fts/fts0opt.cc
@@ -1603,8 +1603,21 @@ fts_optimize_create(
optim->fts_index_table.table = table;
/* The common prefix for all this parent table's aux tables. */
- optim->name_prefix = fts_get_table_name_prefix(
- &optim->fts_common_table);
+ char table_id[FTS_AUX_MIN_TABLE_ID_LENGTH];
+ const size_t table_id_len = 1
+ + size_t(fts_get_table_id(&optim->fts_common_table, table_id));
+ dict_sys.freeze(SRW_LOCK_CALL);
+ /* Include the separator as well. */
+ const size_t dbname_len = table->name.dblen() + 1;
+ ut_ad(dbname_len > 1);
+ const size_t prefix_name_len = dbname_len + 4 + table_id_len;
+ char* prefix_name = static_cast<char*>(
+ ut_malloc_nokey(prefix_name_len));
+ memcpy(prefix_name, table->name.m_name, dbname_len);
+ dict_sys.unfreeze();
+ memcpy(prefix_name + dbname_len, "FTS_", 4);
+ memcpy(prefix_name + dbname_len + 4, table_id, table_id_len);
+ optim->name_prefix =prefix_name;
return(optim);
}
@@ -2591,7 +2604,6 @@ fts_optimize_remove_table(
if (table->fts->in_queue)
{
- dict_sys.assert_not_locked();
fts_msg_t *msg= fts_optimize_create_msg(FTS_MSG_DEL_TABLE, nullptr);
pthread_cond_t cond;
pthread_cond_init(&cond, nullptr);
@@ -2939,7 +2951,7 @@ fts_optimize_init(void)
/* Add fts tables to fts_slots which could be skipped
during dict_load_table_one() because fts_optimize_thread
wasn't even started. */
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
for (dict_table_t* table = UT_LIST_GET_FIRST(dict_sys.table_LRU);
table != NULL;
table = UT_LIST_GET_NEXT(table_LRU, table)) {
@@ -2954,7 +2966,7 @@ fts_optimize_init(void)
fts_optimize_new_table(table);
table->fts->in_queue = true;
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
pthread_cond_init(&fts_opt_shutdown_cond, nullptr);
last_check_sync_time = time(NULL);
@@ -2968,13 +2980,13 @@ fts_optimize_shutdown()
/* If there is an ongoing activity on dictionary, such as
srv_master_evict_from_table_cache(), wait for it */
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
mysql_mutex_lock(&fts_optimize_wq->mutex);
/* Tells FTS optimizer system that we are exiting from
optimizer thread, message send their after will not be
processed */
fts_opt_start_shutdown = true;
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
/* We tell the OPTIMIZE thread to switch to state done, we
can't delete the work queue here because the add thread needs
diff --git a/storage/innobase/fts/fts0sql.cc b/storage/innobase/fts/fts0sql.cc
index c451cb5e3c7..f78778f4a98 100644
--- a/storage/innobase/fts/fts0sql.cc
+++ b/storage/innobase/fts/fts0sql.cc
@@ -86,44 +86,21 @@ fts_get_table_id(
/** Construct the name of an internal FTS table for the given table.
@param[in] fts_table metadata on fulltext-indexed table
-@param[in] dict_locked whether dict_sys.mutex is being held
-@return the prefix, must be freed with ut_free() */
-char* fts_get_table_name_prefix(const fts_table_t* fts_table)
-{
- char table_id[FTS_AUX_MIN_TABLE_ID_LENGTH];
- const size_t table_id_len = size_t(fts_get_table_id(fts_table,
- table_id)) + 1;
- dict_sys.mutex_lock();
- /* Include the separator as well. */
- const size_t dbname_len = fts_table->table->name.dblen() + 1;
- ut_ad(dbname_len > 1);
- const size_t prefix_name_len = dbname_len + 4 + table_id_len;
- char* prefix_name = static_cast<char*>(
- ut_malloc_nokey(prefix_name_len));
- memcpy(prefix_name, fts_table->table->name.m_name, dbname_len);
- dict_sys.mutex_unlock();
- memcpy(prefix_name + dbname_len, "FTS_", 4);
- memcpy(prefix_name + dbname_len + 4, table_id, table_id_len);
- return prefix_name;
-}
-
-/** Construct the name of an internal FTS table for the given table.
-@param[in] fts_table metadata on fulltext-indexed table
@param[out] table_name a name up to MAX_FULL_NAME_LEN
-@param[in] dict_locked whether dict_sys.mutex is being held */
+@param[in] dict_locked whether dict_sys.latch is being held */
void fts_get_table_name(const fts_table_t* fts_table, char* table_name,
bool dict_locked)
{
if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
}
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
/* Include the separator as well. */
const size_t dbname_len = fts_table->table->name.dblen() + 1;
ut_ad(dbname_len > 1);
memcpy(table_name, fts_table->table->name.m_name, dbname_len);
if (!dict_locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
}
memcpy(table_name += dbname_len, "FTS_", 4);
table_name += 4;
@@ -153,14 +130,14 @@ fts_parse_sql(
if (!dict_locked) {
/* The InnoDB SQL parser is not re-entrant. */
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
graph = pars_sql(info, str);
ut_a(graph);
if (!dict_locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
ut_free(str);
@@ -169,30 +146,6 @@ fts_parse_sql(
}
/******************************************************************//**
-Parse an SQL string.
-@return query graph */
-que_t*
-fts_parse_sql_no_dict_lock(
-/*=======================*/
- pars_info_t* info, /*!< in: info struct, or NULL */
- const char* sql) /*!< in: SQL string to evaluate */
-{
- char* str;
- que_t* graph;
-
- dict_sys.assert_locked();
-
- str = ut_str3cat(fts_sql_begin, sql, fts_sql_end);
-
- graph = pars_sql(info, str);
- ut_a(graph);
-
- ut_free(str);
-
- return(graph);
-}
-
-/******************************************************************//**
Evaluate an SQL query graph.
@return DB_SUCCESS or error code */
dberr_t
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index a01ba8ed11c..d0b095eca2a 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -503,7 +503,6 @@ static mysql_pfs_key_t pending_checkpoint_mutex_key;
# ifdef UNIV_PFS_MUTEX
mysql_pfs_key_t buf_pool_mutex_key;
mysql_pfs_key_t dict_foreign_err_mutex_key;
-mysql_pfs_key_t dict_sys_mutex_key;
mysql_pfs_key_t fil_system_mutex_key;
mysql_pfs_key_t flush_list_mutex_key;
mysql_pfs_key_t fts_cache_mutex_key;
@@ -545,7 +544,6 @@ static PSI_mutex_info all_innodb_mutexes[] = {
PSI_KEY(pending_checkpoint_mutex),
PSI_KEY(buf_pool_mutex),
PSI_KEY(dict_foreign_err_mutex),
- PSI_KEY(dict_sys_mutex),
PSI_KEY(recalc_pool_mutex),
PSI_KEY(fil_system_mutex),
PSI_KEY(flush_list_mutex),
@@ -5497,7 +5495,7 @@ is done when the table first opened.
@param[in,out] s_templ InnoDB template structure
@param[in] add_v new virtual columns added along with
add index call
-@param[in] locked true if dict_sys mutex is held */
+@param[in] locked true if dict_sys.latch is held */
void
innobase_build_v_templ(
const TABLE* table,
@@ -5520,12 +5518,18 @@ innobase_build_v_templ(
ut_ad(n_v_col > 0);
if (!locked) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
+#if 0
+ /* This does not (need to) hold for ctx->new_table in
+ alter_rebuild_apply_log() */
+ ut_ad(dict_sys.locked());
+#endif
+
if (s_templ->vtempl) {
if (!locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
DBUG_VOID_RETURN;
}
@@ -5631,7 +5635,7 @@ innobase_build_v_templ(
}
if (!locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
s_templ->db_name = table->s->db.str;
@@ -5919,7 +5923,7 @@ ha_innobase::open(const char* name, int, uint)
key_used_on_scan = m_primary_key;
if (ib_table->n_v_cols) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
if (ib_table->vc_templ == NULL) {
ib_table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
innobase_build_v_templ(
@@ -5927,7 +5931,7 @@ ha_innobase::open(const char* name, int, uint)
true);
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
if (!check_index_consistency(table, ib_table)) {
@@ -9853,7 +9857,7 @@ wsrep_append_foreign_key(
foreign->referenced_table : foreign->foreign_table)) {
WSREP_DEBUG("pulling %s table into cache",
(referenced) ? "referenced" : "foreign");
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
if (referenced) {
foreign->referenced_table =
@@ -9888,7 +9892,7 @@ wsrep_append_foreign_key(
TRUE, FALSE);
}
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
if ( !((referenced) ?
@@ -13016,9 +13020,9 @@ create_table_info_t::create_table_update_dict()
DBUG_RETURN(-1);
}
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
fts_optimize_add_table(innobase_table);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
if (const Field* ai = m_form->found_next_number_field) {
@@ -13277,12 +13281,12 @@ ha_innobase::discard_or_import_tablespace(
btr_cur_instant_init(). */
table_id_t id = m_prebuilt->table->id;
ut_ad(id);
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
dict_table_close(m_prebuilt->table, TRUE, FALSE);
dict_sys.remove(m_prebuilt->table);
m_prebuilt->table = dict_table_open_on_id(id, TRUE,
DICT_TABLE_OP_NORMAL);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
if (!m_prebuilt->table) {
err = DB_TABLE_NOT_FOUND;
} else {
@@ -14303,8 +14307,6 @@ ha_innobase::info_low(
DEBUG_SYNC_C("ha_innobase_info_low");
- dict_sys.assert_not_locked();
-
/* If we are forcing recovery at a high level, we will suppress
statistics calculation on tables, because that may crash the
server if an index is badly corrupted. */
@@ -14355,10 +14357,12 @@ ha_innobase::info_low(
ret = dict_stats_update(ib_table, opt);
if (opt == DICT_STATS_RECALC_PERSISTENT) {
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
+ ib_table->stats_mutex_lock();
ib_table->stats_bg_flag
&= byte(~BG_STAT_SHOULD_QUIT);
- dict_sys.mutex_unlock();
+ ib_table->stats_mutex_unlock();
+ dict_sys.unfreeze();
}
if (ret != DB_SUCCESS) {
@@ -15160,10 +15164,7 @@ get_foreign_key_info(
/* Load referenced table to update FK referenced key name. */
if (foreign->referenced_table == NULL) {
- dict_table_t* ref_table;
-
- dict_sys.assert_locked();
- ref_table = dict_table_open_on_name(
+ dict_table_t* ref_table = dict_table_open_on_name(
foreign->referenced_table_name_lookup,
TRUE, FALSE, DICT_ERR_IGNORE_NONE);
@@ -15217,7 +15218,7 @@ ha_innobase::get_foreign_key_list(
m_prebuilt->trx->op_info = "getting list of foreign keys";
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
for (dict_foreign_set::iterator it
= m_prebuilt->table->foreign_set.begin();
@@ -15234,7 +15235,7 @@ ha_innobase::get_foreign_key_list(
}
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
m_prebuilt->trx->op_info = "";
@@ -15255,7 +15256,7 @@ ha_innobase::get_parent_foreign_key_list(
m_prebuilt->trx->op_info = "getting list of referencing foreign keys";
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
for (dict_foreign_set::iterator it
= m_prebuilt->table->referenced_set.begin();
@@ -15272,7 +15273,7 @@ ha_innobase::get_parent_foreign_key_list(
}
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
m_prebuilt->trx->op_info = "";
@@ -19803,9 +19804,8 @@ TABLE* innobase_init_vc_templ(dict_table_t* table)
DBUG_RETURN(NULL);
}
- dict_sys.mutex_lock();
- innobase_build_v_templ(mysql_table, table, table->vc_templ, NULL, true);
- dict_sys.mutex_unlock();
+ innobase_build_v_templ(mysql_table, table, table->vc_templ, NULL,
+ false);
DBUG_RETURN(mysql_table);
}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 2899613ccf9..361a6dde6b2 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -486,7 +486,7 @@ inline bool dict_table_t::instant_column(const dict_table_t& table,
DBUG_ASSERT(table.n_cols + table.n_dropped() >= n_cols + n_dropped());
DBUG_ASSERT(!table.persistent_autoinc
|| persistent_autoinc == table.persistent_autoinc);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
{
const char* end = table.col_names;
@@ -731,7 +731,7 @@ inline void dict_table_t::rollback_instant(
const char* old_v_col_names,
const ulint* col_map)
{
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
if (cols == old_cols) {
/* Alter fails before instant operation happens.
@@ -2641,7 +2641,7 @@ innobase_init_foreign(
ulint referenced_num_field) /*!< in: number of referenced
columns */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
if (constraint_name) {
ulint db_len;
@@ -3045,7 +3045,7 @@ innobase_get_foreign_key_info(
add_fk[num_fk] = dict_mem_foreign_create();
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
referenced_table_name = dict_get_referenced_table(
table->name.m_name,
@@ -3061,11 +3061,9 @@ innobase_get_foreign_key_info(
referenced_table = NULL;);
if (!referenced_table && trx->check_foreigns) {
- dict_sys.mutex_unlock();
my_error(ER_FK_CANNOT_OPEN_PARENT,
MYF(0), fk_key->ref_table.str);
-
- goto err_exit;
+ goto err_exit_unlock;
}
if (fk_key->ref_columns.elements > 0) {
@@ -3094,12 +3092,11 @@ innobase_get_foreign_key_info(
/* Check whether there exist such
index in the the index create clause */
if (!referenced_index) {
- dict_sys.mutex_unlock();
my_error(ER_FK_NO_INDEX_PARENT, MYF(0),
fk_key->name.str
? fk_key->name.str : "",
fk_key->ref_table.str);
- goto err_exit;
+ goto err_exit_unlock;
}
} else {
ut_a(!trx->check_foreigns);
@@ -3109,10 +3106,9 @@ innobase_get_foreign_key_info(
} else {
/* Not possible to add a foreign key without a
referenced column */
- dict_sys.mutex_unlock();
my_error(ER_CANNOT_ADD_FOREIGN, MYF(0),
fk_key->ref_table.str);
- goto err_exit;
+ goto err_exit_unlock;
}
if (!innobase_init_foreign(
@@ -3121,15 +3117,14 @@ innobase_get_foreign_key_info(
num_col, referenced_table_name,
referenced_table, referenced_index,
referenced_column_names, referenced_num_col)) {
- dict_sys.mutex_unlock();
my_error(
ER_DUP_CONSTRAINT_NAME,
MYF(0),
"FOREIGN KEY", add_fk[num_fk]->id);
- goto err_exit;
+ goto err_exit_unlock;
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
correct_option = innobase_set_foreign_key_option(
add_fk[num_fk], fk_key);
@@ -3160,6 +3155,8 @@ innobase_get_foreign_key_info(
*n_add_fk = num_fk;
DBUG_RETURN(true);
+err_exit_unlock:
+ dict_sys.unlock();
err_exit:
for (ulint i = 0; i <= num_fk; i++) {
if (add_fk[i]) {
@@ -4075,7 +4072,7 @@ online_retry_drop_indexes_low(
dict_table_t* table, /*!< in/out: table */
trx_t* trx) /*!< in/out: transaction */
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(trx->dict_operation);
@@ -4131,9 +4128,9 @@ online_retry_drop_indexes(
trx->free();
}
- ut_d(dict_sys.mutex_lock());
+ ut_d(dict_sys.freeze(SRW_LOCK_CALL));
ut_d(dict_table_check_for_dup_indexes(table, CHECK_ALL_COMPLETE));
- ut_d(dict_sys.mutex_unlock());
+ ut_d(dict_sys.unfreeze());
ut_ad(!table->drop_aborted);
}
@@ -4214,7 +4211,7 @@ innobase_check_foreigns_low(
bool drop)
{
dict_foreign_t* foreign;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
/* Check if any FOREIGN KEY constraints are defined on this
column. */
@@ -4813,7 +4810,7 @@ innobase_update_gis_column_type(
DBUG_ASSERT(trx->dict_operation);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
info = pars_info_create();
@@ -7058,7 +7055,7 @@ error_handling_drop_uncached:
if (fts_index) {
ut_ad(ctx->trx->dict_operation);
ut_ad(ctx->trx->dict_operation_lock_mode == RW_X_LATCH);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS);
if (ctx->need_rebuild()) {
@@ -7344,7 +7341,7 @@ rename_index_try(
trx_t* trx)
{
DBUG_ENTER("rename_index_try");
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
pars_info_t* pinfo;
@@ -7402,7 +7399,7 @@ void
innobase_rename_index_cache(dict_index_t* index, const char* new_name)
{
DBUG_ENTER("innobase_rename_index_cache");
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
size_t old_name_len = strlen(index->name);
size_t new_name_len = strlen(new_name);
@@ -7558,10 +7555,10 @@ ha_innobase::prepare_inplace_alter_table(
}
#endif /* UNIV_DEBUG */
- ut_d(dict_sys.mutex_lock());
+ ut_d(dict_sys.freeze(SRW_LOCK_CALL));
ut_d(dict_table_check_for_dup_indexes(
m_prebuilt->table, CHECK_ABORTED_OK));
- ut_d(dict_sys.mutex_unlock());
+ ut_d(dict_sys.unfreeze());
if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) {
/* Nothing to do */
@@ -8522,10 +8519,10 @@ oom:
KEY* dup_key;
all_done:
case DB_SUCCESS:
- ut_d(dict_sys.mutex_lock());
+ ut_d(dict_sys.freeze(SRW_LOCK_CALL));
ut_d(dict_table_check_for_dup_indexes(
m_prebuilt->table, CHECK_PARTIAL_OK));
- ut_d(dict_sys.mutex_unlock());
+ ut_d(dict_sys.unfreeze());
/* prebuilt->table->n_ref_count can be anything here,
given that we hold at most a shared lock on the table. */
goto ok_exit;
@@ -8586,7 +8583,7 @@ innobase_online_rebuild_log_free(
dict_table_t* table)
{
dict_index_t* clust_index = dict_table_get_first_index(table);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
clust_index->lock.x_lock(SRW_LOCK_CALL);
if (clust_index->online_log) {
@@ -8791,10 +8788,10 @@ inline bool rollback_inplace_alter_table(Alter_inplace_info *ha_alter_info,
purge_sys.resume_FTS();
if (ctx->old_table->fts)
{
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
ut_ad(fts_check_cached_index(ctx->old_table));
fts_optimize_add_table(ctx->old_table);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
goto free_and_exit;
}
@@ -8865,7 +8862,7 @@ innobase_drop_foreign_try(
DBUG_ASSERT(trx->dict_operation);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
/* Drop the constraint from the data dictionary. */
static const char sql[] =
@@ -8921,7 +8918,7 @@ innobase_rename_column_try(
DBUG_ASSERT(trx->dict_operation);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
if (ctx.need_rebuild()) {
goto rename_foreign;
@@ -9239,7 +9236,7 @@ innobase_rename_or_enlarge_column_try(
DBUG_ASSERT(trx->dict_operation);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ulint n_base;
@@ -9665,7 +9662,7 @@ innobase_update_foreign_cache(
DBUG_ENTER("innobase_update_foreign_cache");
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
user_table = ctx->old_table;
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index 3b2207beed5..340156249fc 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -1335,12 +1335,12 @@ i_s_cmp_per_index_fill_low(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
/* Create a snapshot of the stats so we do not bump into lock
- order violations with dict_sys.mutex below. */
+ order violations with dict_sys.latch below. */
mysql_mutex_lock(&page_zip_stat_per_index_mutex);
page_zip_stat_per_index_t snap (page_zip_stat_per_index);
mysql_mutex_unlock(&page_zip_stat_per_index_mutex);
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
page_zip_stat_per_index_t::iterator iter;
ulint i;
@@ -1393,18 +1393,18 @@ i_s_cmp_per_index_fill_low(
status = 1;
break;
}
- /* Release and reacquire the dict mutex to allow other
+ /* Release and reacquire the dict_sys.latch to allow other
threads to proceed. This could eventually result in the
contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
inconsistent, but it is an acceptable compromise. */
if (i == 1000) {
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
i = 0;
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
}
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
if (reset) {
page_zip_reset_stat_per_index();
@@ -3974,7 +3974,7 @@ i_s_innodb_buffer_page_fill(
if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
bool ret = false;
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
const dict_index_t* index =
dict_index_get_if_in_cache_low(
@@ -3999,7 +3999,7 @@ i_s_innodb_buffer_page_fill(
system_charset_info);
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
OK(ret);
@@ -4478,7 +4478,7 @@ i_s_innodb_buf_page_lru_fill(
if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
bool ret = false;
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
const dict_index_t* index =
dict_index_get_if_in_cache_low(
@@ -4503,7 +4503,7 @@ i_s_innodb_buf_page_lru_fill(
system_charset_info);
}
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
OK(ret);
@@ -4856,8 +4856,8 @@ i_s_sys_tables_fill_table(
DBUG_RETURN(0);
}
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
for (const rec_t *rec = dict_startscan_system(&pcur, &mtr,
dict_sys.sys_tables);
@@ -4873,7 +4873,7 @@ i_s_sys_tables_fill_table(
information from SYS_TABLES row */
err_msg = i_s_sys_tables_rec(pcur, rec, &table_rec);
mtr.commit();
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
if (!err_msg) {
i_s_dict_fill_sys_tables(thd, table_rec,
@@ -4889,12 +4889,12 @@ i_s_sys_tables_fill_table(
}
/* Get the next record */
- dict_sys.mutex_lock();
mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
}
mtr.commit();
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
DBUG_RETURN(0);
}
@@ -5131,7 +5131,6 @@ i_s_sys_tables_fill_table_stats(
/* Get the next record */
mtr.start();
dict_sys.lock(SRW_LOCK_CALL);
-
if (table_rec) {
dict_sys.allow_eviction(table_rec);
}
@@ -5333,7 +5332,7 @@ i_s_sys_indexes_fill_table(
}
heap = mem_heap_create(1000);
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
mtr_start(&mtr);
/* Start scan the SYS_INDEXES table */
@@ -5354,8 +5353,8 @@ i_s_sys_indexes_fill_table(
rec, DICT_FLD__SYS_INDEXES__SPACE, &space_id);
space_id = space_id == 4 ? mach_read_from_4(field)
: ULINT_UNDEFINED;
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
if (!err_msg) {
if (int err = i_s_dict_fill_sys_indexes(
@@ -5373,13 +5372,13 @@ i_s_sys_indexes_fill_table(
mem_heap_empty(heap);
/* Get the next record */
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_getnext_system(&pcur, &mtr);
}
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
mem_heap_free(heap);
DBUG_RETURN(0);
@@ -5552,8 +5551,8 @@ i_s_sys_columns_fill_table(
}
heap = mem_heap_create(1000);
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_columns);
@@ -5569,8 +5568,8 @@ i_s_sys_columns_fill_table(
&table_id, &col_name,
&nth_v_col);
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
if (!err_msg) {
i_s_dict_fill_sys_columns(thd, table_id, col_name,
@@ -5585,17 +5584,18 @@ i_s_sys_columns_fill_table(
mem_heap_empty(heap);
/* Get the next record */
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_getnext_system(&pcur, &mtr);
}
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
mem_heap_free(heap);
DBUG_RETURN(0);
}
+
/*******************************************************************//**
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns
@return 0 on success */
@@ -5745,8 +5745,8 @@ i_s_sys_virtual_fill_table(
DBUG_RETURN(0);
}
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_virtual);
@@ -5760,8 +5760,8 @@ i_s_sys_virtual_fill_table(
&table_id, &pos,
&base_pos);
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
if (!err_msg) {
i_s_dict_fill_sys_virtual(thd, table_id, pos, base_pos,
@@ -5773,13 +5773,13 @@ i_s_sys_virtual_fill_table(
}
/* Get the next record */
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_getnext_system(&pcur, &mtr);
}
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
DBUG_RETURN(0);
}
@@ -5931,13 +5931,13 @@ i_s_sys_fields_fill_table(
}
heap = mem_heap_create(1000);
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
/* will save last index id so that we know whether we move to
the next index. This is used to calculate prefix length */
last_id = 0;
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_fields);
while (rec) {
@@ -5951,8 +5951,8 @@ i_s_sys_fields_fill_table(
err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
&pos, &index_id, last_id);
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
if (!err_msg) {
i_s_dict_fill_sys_fields(thd, index_id, &field_rec,
@@ -5967,13 +5967,13 @@ i_s_sys_fields_fill_table(
mem_heap_empty(heap);
/* Get the next record */
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_getnext_system(&pcur, &mtr);
}
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
mem_heap_free(heap);
DBUG_RETURN(0);
@@ -6134,8 +6134,8 @@ i_s_sys_foreign_fill_table(
}
heap = mem_heap_create(1000);
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign);
@@ -6147,8 +6147,8 @@ i_s_sys_foreign_fill_table(
a SYS_FOREIGN row */
err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
if (!err_msg) {
i_s_dict_fill_sys_foreign(thd, &foreign_rec,
@@ -6162,13 +6162,13 @@ i_s_sys_foreign_fill_table(
mem_heap_empty(heap);
/* Get the next record */
- mtr_start(&mtr);
- dict_sys.mutex_lock();
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_getnext_system(&pcur, &mtr);
}
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
mem_heap_free(heap);
DBUG_RETURN(0);
@@ -6327,8 +6327,8 @@ i_s_sys_foreign_cols_fill_table(
}
heap = mem_heap_create(1000);
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign_cols);
@@ -6343,8 +6343,8 @@ i_s_sys_foreign_cols_fill_table(
err_msg = dict_process_sys_foreign_col_rec(
heap, rec, &name, &for_col_name, &ref_col_name, &pos);
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
if (!err_msg) {
i_s_dict_fill_sys_foreign_cols(
@@ -6359,13 +6359,13 @@ i_s_sys_foreign_cols_fill_table(
mem_heap_empty(heap);
/* Get the next record */
- dict_sys.mutex_lock();
- mtr_start(&mtr);
+ mtr.start();
+ dict_sys.lock(SRW_LOCK_CALL);
rec = dict_getnext_system(&pcur, &mtr);
}
- mtr_commit(&mtr);
- dict_sys.mutex_unlock();
+ mtr.commit();
+ dict_sys.unlock();
mem_heap_free(heap);
DBUG_RETURN(0);
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 6f5d2377b07..5760ec9378b 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -934,8 +934,8 @@ dict_table_copy_types(
const dict_table_t* table) /*!< in: table */
MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
-Looks for an index with the given id. NOTE that we do not reserve
-the dictionary mutex: this function is for emergency purposes like
+Looks for an index with the given id. NOTE that we do not acquire
+dict_sys.latch: this function is for emergency purposes like
printing info of a corrupt database page!
@return index or NULL if not found from cache */
dict_index_t*
@@ -1146,7 +1146,6 @@ dict_field_get_col(
/**********************************************************************//**
Returns an index object if it is found in the dictionary cache.
-Assumes that dict_sys.mutex is already being held.
@return index, NULL if not found */
dict_index_t*
dict_index_get_if_in_cache_low(
@@ -1352,13 +1351,12 @@ extern mysql_mutex_t dict_foreign_err_mutex;
/** InnoDB data dictionary cache */
class dict_sys_t
{
- /** The my_hrtime_coarse().val of the oldest mutex_lock_wait() start, or 0 */
- std::atomic<ulonglong> mutex_wait_start;
+ /** The my_hrtime_coarse().val of the oldest lock_wait() start, or 0 */
+ std::atomic<ulonglong> latch_ex_wait_start;
/** @brief the data dictionary rw-latch protecting dict_sys
- Table create, drop, etc. reserve this in X-mode (along with
- acquiring dict_sys.mutex); implicit or
+ Table create, drop, etc. reserve this in X-mode; implicit or
backround operations that are not fully covered by MDL
(rollback, foreign key checks) reserve this in S-mode.
@@ -1368,11 +1366,9 @@ class dict_sys_t
#ifdef UNIV_DEBUG
/** whether latch is being held in exclusive mode (by any thread) */
bool latch_ex;
+ /** number of S-latch holders */
+ Atomic_counter<uint32_t> latch_readers;
#endif
- /** Mutex protecting dict_sys. Whenever latch is acquired
- exclusively, also the mutex will be acquired.
- FIXME: merge the mutex and the latch, once MDEV-23484 has been fixed */
- mysql_mutex_t mutex;
public:
/** Indexes of SYS_TABLE[] */
enum
@@ -1429,7 +1425,7 @@ private:
/** The synchronization interval of row_id */
static constexpr size_t ROW_ID_WRITE_MARGIN= 256;
public:
- /** Diagnostic message for exceeding the mutex_lock_wait() timeout */
+ /** Diagnostic message for exceeding the lock_wait() timeout */
static const char fatal_msg[];
/** @return A new value for GEN_CLUST_INDEX(DB_ROW_ID) */
@@ -1457,7 +1453,7 @@ public:
(should only happen during the rollback of CREATE...SELECT) */
dict_table_t *acquire_temporary_table(table_id_t id)
{
- mysql_mutex_assert_owner(&mutex);
+ ut_ad(frozen());
dict_table_t *table;
ulint fold = ut_fold_ull(id);
HASH_SEARCH(id_hash, &temp_id_hash, fold, dict_table_t*, table,
@@ -1477,7 +1473,7 @@ public:
@retval nullptr if not cached */
dict_table_t *find_table(table_id_t id)
{
- mysql_mutex_assert_owner(&mutex);
+ ut_ad(frozen());
dict_table_t *table;
ulint fold= ut_fold_ull(id);
HASH_SEARCH(id_hash, &table_id_hash, fold, dict_table_t*, table,
@@ -1511,7 +1507,7 @@ public:
{
ut_ad(table);
ut_ad(table->can_be_evicted == in_lru);
- mysql_mutex_assert_owner(&mutex);
+ ut_ad(frozen());
for (const dict_table_t* t= in_lru ? table_LRU.start : table_non_LRU.start;
t; t = UT_LIST_GET_NEXT(table_LRU, t))
{
@@ -1531,6 +1527,7 @@ public:
@return whether the table was evictable */
bool prevent_eviction(dict_table_t *table)
{
+ ut_d(locked());
ut_ad(find(table));
if (!table->can_be_evicted)
return false;
@@ -1542,6 +1539,7 @@ public:
/** Move a table from the non-LRU list to the LRU list. */
void allow_eviction(dict_table_t *table)
{
+ ut_d(locked());
ut_ad(find(table));
ut_ad(!table->can_be_evicted);
table->can_be_evicted= true;
@@ -1551,47 +1549,70 @@ public:
/** Acquire a reference to a cached table. */
inline void acquire(dict_table_t *table);
-
- /** Assert that the mutex is locked */
- void assert_locked() const { mysql_mutex_assert_owner(&mutex); }
- /** Assert that the mutex is not locked */
- void assert_not_locked() const { mysql_mutex_assert_not_owner(&mutex); }
-#ifdef SAFE_MUTEX
- bool mutex_is_locked() const { return mysql_mutex_is_owner(&mutex); }
+#ifdef UNIV_DEBUG
+ /** @return whether any thread (not necessarily the current thread)
+ is holding the latch; that is, this check may return false
+ positives */
+ bool frozen() const { return latch_readers || locked(); }
+ /** @return whether any thread (not necessarily the current thread)
+ is holding the exclusive latch; that is, this check may return false
+ positives */
+ bool locked() const { return latch_ex; }
#endif
private:
- /** Acquire the mutex */
- ATTRIBUTE_NOINLINE void mutex_lock_wait();
+ /** Acquire the exclusive latch */
+ ATTRIBUTE_NOINLINE
+ void lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line));
public:
- /** @return the my_hrtime_coarse().val of the oldest mutex_lock_wait() start,
+ /** @return the my_hrtime_coarse().val of the oldest lock_wait() start,
assuming that requests are served on a FIFO basis */
ulonglong oldest_wait() const
- { return mutex_wait_start.load(std::memory_order_relaxed); }
+ { return latch_ex_wait_start.load(std::memory_order_relaxed); }
-#ifdef HAVE_PSI_MUTEX_INTERFACE
- /** Acquire the mutex */
- ATTRIBUTE_NOINLINE void mutex_lock();
- /** Release the mutex */
- ATTRIBUTE_NOINLINE void mutex_unlock();
-#else
- /** Acquire the mutex */
- void mutex_lock() { if (mysql_mutex_trylock(&mutex)) mutex_lock_wait(); }
-
- /** Release the mutex */
- void mutex_unlock() { mysql_mutex_unlock(&mutex); }
-#endif
-
- /** Lock the data dictionary cache. */
- void lock(SRW_LOCK_ARGS(const char *file, unsigned line));
+ /** Exclusively lock the dictionary cache. */
+ void lock(SRW_LOCK_ARGS(const char *file, unsigned line))
+ {
+ if (latch.wr_lock_try())
+ {
+ ut_ad(!latch_readers);
+ ut_ad(!latch_ex);
+ ut_d(latch_ex= true);
+ }
+ else
+ lock_wait(SRW_LOCK_ARGS(file, line));
+ }
+#ifdef UNIV_PFS_RWLOCK
+ /** Unlock the data dictionary cache. */
+ ATTRIBUTE_NOINLINE void unlock();
+ /** Acquire a shared lock on the dictionary cache. */
+ ATTRIBUTE_NOINLINE void freeze(const char *file, unsigned line);
+ /** Release a shared lock on the dictionary cache. */
+ ATTRIBUTE_NOINLINE void unfreeze();
+#else
/** Unlock the data dictionary cache. */
void unlock()
{
ut_ad(latch_ex);
+ ut_ad(!latch_readers);
ut_d(latch_ex= false);
- mutex_unlock();
latch.wr_unlock();
}
+ /** Acquire a shared lock on the dictionary cache. */
+ void freeze()
+ {
+ latch.rd_lock();
+ ut_ad(!latch_ex);
+ ut_d(latch_readers++);
+ }
+ /** Release a shared lock on the dictionary cache. */
+ void unfreeze()
+ {
+ ut_ad(!latch_ex);
+ ut_ad(latch_readers--);
+ latch.rd_unlock();
+ }
+#endif
/** Estimate the used memory occupied by the data dictionary
table and index objects.
@@ -1621,7 +1642,7 @@ public:
@retval nullptr if not found */
dict_table_t *find_table(const span<const char> &name) const
{
- assert_locked();
+ ut_ad(frozen());
for (dict_table_t *table= static_cast<dict_table_t*>
(HASH_GET_FIRST(&table_hash, table_hash.calc_hash
(my_crc32c(0, name.data(), name.size()))));
@@ -1650,9 +1671,6 @@ public:
/** the data dictionary cache */
extern dict_sys_t dict_sys;
-#define dict_sys_lock() dict_sys.lock(SRW_LOCK_CALL)
-#define dict_sys_unlock() dict_sys.unlock()
-
/*********************************************************************//**
Converts a database and table name from filesystem encoding
(e.g. d@i1b/a@q1b@1Kc, same format as used in dict_table_t::name) in two
diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
index a494eefdc32..a98ca38d9b3 100644
--- a/storage/innobase/include/dict0dict.ic
+++ b/storage/innobase/include/dict0dict.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2020, MariaDB Corporation.
+Copyright (c) 2013, 2021, 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
@@ -1141,7 +1141,7 @@ dict_table_is_file_per_table(
/** Acquire the table handle. */
inline void dict_table_t::acquire()
{
- dict_sys.assert_locked();
+ ut_ad(dict_sys.frozen());
n_ref_count++;
}
diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
index 591dd30f211..072773694a9 100644
--- a/storage/innobase/include/dict0load.h
+++ b/storage/innobase/include/dict0load.h
@@ -53,12 +53,9 @@ We also scan the biggest space id, and store it to fil_system. */
void dict_check_tablespaces_and_store_max_id();
/** Make sure the data_file_name is saved in dict_table_t if needed.
-@param[in] table Table object
-@param[in] dict_mutex_own true if dict_sys.mutex is owned already */
-void
-dict_get_and_save_data_dir_path(
- dict_table_t* table,
- bool dict_mutex_own);
+@param[in,out] table Table object
+@param[in] dict_locked dict_sys.frozen() */
+void dict_get_and_save_data_dir_path(dict_table_t* table, bool dict_locked);
/***********************************************************************//**
Loads a table object based on the table id.
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 6614b015665..8a23ee22a44 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1026,8 +1026,7 @@ struct dict_index_t {
/*!< enum online_index_status.
Transitions from ONLINE_INDEX_COMPLETE (to
ONLINE_INDEX_CREATION) are protected
- by dict_sys.latch and
- dict_sys.mutex. Other changes are
+ by dict_sys.latch. Other changes are
protected by index->lock. */
unsigned uncommitted:1;
/*!< a flag that is set for secondary indexes
@@ -1935,7 +1934,7 @@ struct dict_table_t {
inline size_t get_overflow_field_local_len() const;
/** Parse the table file name into table name and database name.
- @tparam dict_locked whether dict_sys.mutex is being held
+ @tparam dict_locked whether dict_sys.lock() was called
@param[in,out] db_name database name buffer
@param[in,out] tbl_name table name buffer
@param[out] db_name_len database name length
@@ -2177,7 +2176,7 @@ public:
dict_foreign_set referenced_set;
/** Statistics for query optimization. Mostly protected by
- dict_sys.mutex. @{ */
+ dict_sys.latch and stats_mutex_lock(). @{ */
/** TRUE if statistics have been calculated the first time after
database startup or table creation. */
@@ -2259,7 +2258,7 @@ public:
/** The state of the background stats thread wrt this table.
See BG_STAT_NONE, BG_STAT_IN_PROGRESS and BG_STAT_SHOULD_QUIT.
- Writes are covered by dict_sys.mutex. Dirty reads are possible. */
+ Writes are covered by dict_sys.latch and stats_mutex_lock(). */
byte stats_bg_flag;
bool stats_error_printed;
diff --git a/storage/innobase/include/dict0stats.ic b/storage/innobase/include/dict0stats.ic
index 68592404253..e49153eb099 100644
--- a/storage/innobase/include/dict0stats.ic
+++ b/storage/innobase/include/dict0stats.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
-Copyright (c) 2017, 2020, MariaDB Corporation.
+Copyright (c) 2017, 2021, 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
@@ -75,7 +75,7 @@ dict_stats_is_persistent_enabled(const dict_table_t* table)
+ dict_stats_update(DICT_STATS_RECALC_TRANSIENT) on a table that has
just been PS-enabled.
This is acceptable. Avoiding this would mean that we would have to
- protect the stat_persistent with dict_sys.mutex like the
+ hold dict_sys.latch or stats_mutex_lock() like for accessing the
other ::stat_ members which would be too big performance penalty,
especially when this function is called from
dict_stats_update_if_needed(). */
diff --git a/storage/innobase/include/dict0stats_bg.h b/storage/innobase/include/dict0stats_bg.h
index e9318a0116d..e621dcf89a5 100644
--- a/storage/innobase/include/dict0stats_bg.h
+++ b/storage/innobase/include/dict0stats_bg.h
@@ -67,25 +67,25 @@ dict_stats_stop_bg(
dict_table_t* table) /*!< in/out: table */
{
ut_ad(!srv_read_only_mode);
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
if (!(table->stats_bg_flag & BG_STAT_IN_PROGRESS)) {
return(true);
}
+ /* In dict_stats_update_persistent() this flag is being read
+ while holding the mutex, not dict_sys.latch. */
+ table->stats_mutex_lock();
table->stats_bg_flag |= BG_STAT_SHOULD_QUIT;
+ table->stats_mutex_unlock();
return(false);
}
/*****************************************************************//**
Wait until background stats thread has stopped using the specified table.
-The caller must have locked the data dictionary using
-row_mysql_lock_data_dictionary() and this function may unlock it temporarily
-and restore the lock before it exits.
The background stats thread is guaranteed not to start using the specified
-table after this function returns and before the caller unlocks the data
-dictionary because it sets the BG_STAT_IN_PROGRESS bit in table->stats_bg_flag
-under dict_sys.mutex. */
+table after this function returns and before the caller releases
+dict_sys.latch. */
void
dict_stats_wait_bg_to_stop_using_table(
/*===================================*/
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index 9fd0b076520..445a8085320 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -1660,7 +1660,7 @@ right in it. If does not succeed, prints an error message to the .err log. This
function is used to open a tablespace when we start up mysqld, and also in
IMPORT TABLESPACE.
NOTE that we assume this operation is used either at the database startup
-or under the protection of the dictionary mutex, so that two users cannot
+or under the protection of dict_sys.latch, so that two users cannot
race here. This operation does not leave the file associated with the
tablespace open, but closes it after we have looked at the space id in it.
diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h
index bb61eae43f2..24bbde9e922 100644
--- a/storage/innobase/include/fts0fts.h
+++ b/storage/innobase/include/fts0fts.h
@@ -318,7 +318,7 @@ public:
/** Whether the ADDED table record sync-ed after crash recovery */
unsigned added_synced:1;
- /** Whether the table holds dict_sys.mutex */
+ /** Whether the table holds dict_sys.latch */
unsigned dict_locked:1;
/** Work queue for scheduling jobs for the FTS 'Add' thread, or NULL
@@ -741,7 +741,7 @@ FTS auxiliary INDEX table and clear the cache at the end.
dberr_t fts_sync_table(dict_table_t* table, bool wait = true);
/****************************************************************//**
-Free the query graph but check whether dict_sys.mutex is already
+Free the query graph but check whether dict_sys.latch is already
held */
void
fts_que_graph_free_check_lock(
diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h
index fbe2acdc712..a8647b4dd1d 100644
--- a/storage/innobase/include/fts0priv.h
+++ b/storage/innobase/include/fts0priv.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2020, MariaDB Corporation.
+Copyright (c) 2017, 2021, 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
@@ -135,7 +135,7 @@ fts_eval_sql(
/** Construct the name of an internal FTS table for the given table.
@param[in] fts_table metadata on fulltext-indexed table
@param[out] table_name a name up to MAX_FULL_NAME_LEN
-@param[in] dict_locked whether dict_sys.mutex is being held */
+@param[in] dict_locked whether dict_sys.latch is being held */
void fts_get_table_name(const fts_table_t* fts_table, char* table_name,
bool dict_locked = false)
MY_ATTRIBUTE((nonnull));
@@ -295,16 +295,6 @@ fts_trx_table_id_cmp(
#define fts_sql_commit(trx) trx_commit_for_mysql(trx)
#define fts_sql_rollback(trx) (trx)->rollback()
/******************************************************************//**
-Parse an SQL string. %s is replaced with the table's id. Don't acquire
-the dict mutex
-@return query graph */
-que_t*
-fts_parse_sql_no_dict_lock(
-/*=======================*/
- pars_info_t* info, /*!< in: parser info */
- const char* sql) /*!< in: SQL string to evaluate */
- MY_ATTRIBUTE((nonnull(2), malloc, warn_unused_result));
-/******************************************************************//**
Get value from config table. The caller must ensure that enough
space is allocated for value to hold the column contents
@return DB_SUCCESS or error code */
@@ -469,12 +459,6 @@ fts_get_table_id(
FTS_AUX_MIN_TABLE_ID_LENGTH bytes
long */
MY_ATTRIBUTE((nonnull, warn_unused_result));
-/** Construct the name of an internal FTS table for the given table.
-@param[in] fts_table metadata on fulltext-indexed table
-@param[in] dict_locked whether dict_sys.mutex is being held
-@return the prefix, must be freed with ut_free() */
-char* fts_get_table_name_prefix(const fts_table_t* fts_table)
- MY_ATTRIBUTE((nonnull, malloc, warn_unused_result));
/******************************************************************//**
Add node positions. */
void
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index ca792f9e439..a651a56e8a0 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -77,7 +77,7 @@ log_reserve_and_write_fast(
Checks if there is need for a log buffer flush or a new checkpoint, and does
this if yes. Any database operation should call this when it has modified
more than about 4 pages. NOTE that this function may only be called when the
-OS thread owns no synchronization objects except the dictionary mutex. */
+OS thread owns no synchronization objects except dict_sys.latch. */
UNIV_INLINE
void
log_free_check(void);
diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic
index aebe511d659..c29c0bfa55f 100644
--- a/storage/innobase/include/log0log.ic
+++ b/storage/innobase/include/log0log.ic
@@ -294,7 +294,7 @@ log_reserve_and_write_fast(
Checks if there is need for a log buffer flush or a new checkpoint, and does
this if yes. Any database operation should call this when it has modified
more than about 4 pages. NOTE that this function may only be called when the
-OS thread owns no synchronization objects except the dictionary mutex. */
+OS thread owns no synchronization objects except dict_sys.latch. */
UNIV_INLINE
void
log_free_check(void)
diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
index 1a30ea45194..d81c77e3d36 100644
--- a/storage/innobase/include/que0que.h
+++ b/storage/innobase/include/que0que.h
@@ -207,9 +207,9 @@ que_eval_sql(
/*=========*/
pars_info_t* info, /*!< in: info struct, or NULL */
const char* sql, /*!< in: SQL string */
- bool reserve_dict_mutex,
+ bool lock_dict,
/*!< in: whether to acquire/release
- dict_sys.mutex around call to pars_sql. */
+ dict_sys.latch around call to pars_sql(). */
trx_t* trx); /*!< in: trx */
/**********************************************************************//**
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index eb32e91298d..88f0b2d185b 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -537,7 +537,6 @@ typedef unsigned int mysql_pfs_key_t;
# ifdef UNIV_PFS_MUTEX
extern mysql_pfs_key_t buf_pool_mutex_key;
extern mysql_pfs_key_t dict_foreign_err_mutex_key;
-extern mysql_pfs_key_t dict_sys_mutex_key;
extern mysql_pfs_key_t fil_system_mutex_key;
extern mysql_pfs_key_t flush_list_mutex_key;
extern mysql_pfs_key_t fts_cache_mutex_key;
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index bcdf430e476..9f8fdd308aa 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -3846,7 +3846,7 @@ released:
#if defined SAFE_MUTEX && defined UNIV_DEBUG
if (to_evict.empty())
return;
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
LockMutexGuard g{SRW_LOCK_CALL};
for (const table_id_t id : to_evict)
{
@@ -3854,7 +3854,7 @@ released:
if (!table->get_ref_count() && !UT_LIST_GET_LEN(table->locks))
dict_sys.remove(table, true);
}
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
#endif
}
diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc
index 1c3802f05e4..d2a33600ed0 100644
--- a/storage/innobase/pars/pars0pars.cc
+++ b/storage/innobase/pars/pars0pars.cc
@@ -1973,7 +1973,7 @@ pars_sql(
heap = mem_heap_create(16000);
/* Currently, the parser is not reentrant: */
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
pars_sym_tab_global = sym_tab_create(heap);
diff --git a/storage/innobase/pars/pars0sym.cc b/storage/innobase/pars/pars0sym.cc
index b65021a375a..d68e352e795 100644
--- a/storage/innobase/pars/pars0sym.cc
+++ b/storage/innobase/pars/pars0sym.cc
@@ -67,7 +67,7 @@ sym_tab_free_private(
sym_node_t* sym;
func_node_t* func;
- dict_sys.assert_locked();
+ ut_ad(dict_sys.locked());
for (sym = UT_LIST_GET_FIRST(sym_tab->sym_list);
sym != NULL;
diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc
index d97466a9219..074f8c54e24 100644
--- a/storage/innobase/que/que0que.cc
+++ b/storage/innobase/que/que0que.cc
@@ -748,9 +748,9 @@ que_eval_sql(
/*=========*/
pars_info_t* info, /*!< in: info struct, or NULL */
const char* sql, /*!< in: SQL string */
- bool reserve_dict_mutex,
+ bool lock_dict,
/*!< in: whether to acquire/release
- dict_sys.mutex around call to pars_sql. */
+ dict_sys.latch around call to pars_sql(). */
trx_t* trx) /*!< in: trx */
{
que_thr_t* thr;
@@ -761,14 +761,14 @@ que_eval_sql(
ut_a(trx->error_state == DB_SUCCESS);
- if (reserve_dict_mutex) {
- dict_sys.mutex_lock();
+ if (lock_dict) {
+ dict_sys.lock(SRW_LOCK_CALL);
}
graph = pars_sql(info, sql);
- if (reserve_dict_mutex) {
- dict_sys.mutex_unlock();
+ if (lock_dict) {
+ dict_sys.unlock();
}
graph->trx = trx;
@@ -778,14 +778,14 @@ que_eval_sql(
que_run_threads(thr);
- if (reserve_dict_mutex) {
- dict_sys.mutex_lock();
+ if (lock_dict) {
+ dict_sys.lock(SRW_LOCK_CALL);
}
que_graph_free(graph);
- if (reserve_dict_mutex) {
- dict_sys.mutex_unlock();
+ if (lock_dict) {
+ dict_sys.unlock();
}
DBUG_RETURN(trx->error_state);
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 07124f6c8f9..f3a583d1564 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -1411,8 +1411,6 @@ row_import::set_root_by_heuristic() UNIV_NOTHROW
" the tablespace has " << m_n_indexes << " indexes";
}
- dict_sys.mutex_lock();
-
ulint i = 0;
dberr_t err = DB_SUCCESS;
@@ -1452,8 +1450,6 @@ row_import::set_root_by_heuristic() UNIV_NOTHROW
}
}
- dict_sys.mutex_unlock();
-
return(err);
}
@@ -4098,8 +4094,6 @@ 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 locked 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 651d5444ccb..95aa0b84c7a 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -3040,9 +3040,7 @@ row_ins_sec_index_entry_low(
if (!index->is_committed()) {
ut_ad(!thr_get_trx(thr)
->dict_operation_lock_mode);
- dict_sys.mutex_lock();
- dict_set_corrupted_index_cache_only(index);
- dict_sys.mutex_unlock();
+ index->type |= DICT_CORRUPT;
/* Do not return any error to the
caller. The duplicate will be reported
by ALTER TABLE or CREATE UNIQUE INDEX.
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index c6bd09e43fd..459f0db3997 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -3680,7 +3680,7 @@ row_merge_drop_index_dict(
ut_ad(!srv_read_only_mode);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(trx->dict_operation);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
info = pars_info_create();
pars_info_add_ull_literal(info, "indexid", index_id);
@@ -3742,7 +3742,7 @@ row_merge_drop_indexes_dict(
ut_ad(!srv_read_only_mode);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(trx->dict_operation);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
/* It is possible that table->n_ref_count > 1 when
locked=TRUE. In this case, all code that should have an open
@@ -3815,7 +3815,7 @@ row_merge_drop_indexes(
ut_ad(!srv_read_only_mode);
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(trx->dict_operation);
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
index = dict_table_get_first_index(table);
ut_ad(dict_index_is_clust(index));
@@ -3900,7 +3900,7 @@ row_merge_drop_indexes(
index->lock.x_unlock();
DEBUG_SYNC_C("merge_drop_index_after_abort");
- /* covered by dict_sys.mutex */
+ /* covered by dict_sys.latch */
MONITOR_INC(MONITOR_BACKGROUND_DROP_INDEX);
/* fall through */
case ONLINE_INDEX_ABORTED:
@@ -3967,7 +3967,7 @@ row_merge_drop_indexes(
break;
case ONLINE_INDEX_ABORTED:
case ONLINE_INDEX_ABORTED_DROPPED:
- /* covered by dict_sys.mutex */
+ /* covered by dict_sys.latch */
MONITOR_DEC(MONITOR_BACKGROUND_DROP_INDEX);
}
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index f84755a5c4a..1d8a0180f1c 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1440,7 +1440,8 @@ error_exit:
srv_stats.n_rows_inserted.inc(size_t(trx->id));
}
- /* Not protected by dict_sys.mutex for performance
+ /* Not protected by dict_sys.latch or table->stats_mutex_lock()
+ for performance
reasons, we would rather get garbage in stat_n_rows (which is
just an estimate anyway) than protecting the following code
with a latch. */
@@ -1777,7 +1778,8 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
ut_ad(is_delete == (node->is_delete == PLAIN_DELETE));
if (is_delete) {
- /* Not protected by dict_sys.mutex for performance
+ /* Not protected by dict_sys.latch
+ or prebuilt->table->stats_mutex_lock() for performance
reasons, we would rather get garbage in stat_n_rows (which is
just an estimate anyway) than protecting the following code
with a latch. */
@@ -2124,7 +2126,8 @@ row_update_cascade_for_mysql(
bool stats;
if (node->is_delete == PLAIN_DELETE) {
- /* Not protected by dict_sys.mutex for
+ /* Not protected by dict_sys.latch
+ or node->table->stats_mutex_lock() for
performance reasons, we would rather
get garbage in stat_n_rows (which is
just an estimate anyway) than
@@ -2200,7 +2203,7 @@ row_create_table_for_mysql(
que_thr_t* thr;
dberr_t err;
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
DEBUG_SYNC_C("create_table");
@@ -2288,7 +2291,7 @@ row_create_index_for_mysql(
ulint len;
dict_table_t* table = index->table;
- ut_d(dict_sys.assert_locked());
+ ut_ad(dict_sys.locked());
for (i = 0; i < index->n_def; i++) {
/* Check that prefix_len and actual length
@@ -2577,7 +2580,6 @@ dberr_t row_discard_tablespace_for_mysql(dict_table_t *table, trx_t *trx)
if (err != DB_SUCCESS)
{
rollback:
- table->stats_bg_flag= BG_STAT_NONE;
if (fts_exist)
{
purge_sys.resume_FTS();
@@ -2594,12 +2596,13 @@ rollback:
trx->op_info = "discarding tablespace";
trx->dict_operation= true;
- /* Serialize data dictionary operations with dictionary mutex:
+ /* We serialize data dictionary operations with dict_sys.latch:
this is to avoid deadlocks during data dictionary operations */
err= row_discard_tablespace_foreign_key_checks(trx, table);
if (err != DB_SUCCESS)
{
+ table->stats_bg_flag= BG_STAT_NONE;
row_mysql_unlock_data_dictionary(trx);
goto rollback;
}
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index d07288a9e23..d8e1cdfc0b6 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -115,12 +115,12 @@ row_purge_remove_clust_if_poss_low(
if (table_id) {
retry:
purge_sys.check_stop_FTS();
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
table = dict_table_open_on_id(
table_id, true, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED,
node->purge_thd, &mdl_ticket);
if (!table) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
} else if (table->n_rec_locks) {
for (dict_index_t* ind = UT_LIST_GET_FIRST(
table->indexes); ind;
@@ -145,7 +145,7 @@ close_and_exit:
if (table) {
dict_table_close(table, true, false,
node->purge_thd, mdl_ticket);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
return success;
}
@@ -176,7 +176,7 @@ close_and_exit:
table->file_unreadable = true;
}
table = nullptr;
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
if (!mdl_ticket);
else if (MDL_context* mdl_context =
static_cast<MDL_context*>(
@@ -194,7 +194,7 @@ close_and_exit:
if (table) {
dict_table_close(table, true, false,
node->purge_thd, mdl_ticket);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
table = nullptr;
}
diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc
index 74c7b9b35fc..04de3465dcf 100644
--- a/storage/innobase/row/row0quiesce.cc
+++ b/storage/innobase/row/row0quiesce.cc
@@ -486,8 +486,6 @@ row_quiesce_table_has_fts_index(
{
bool exists = false;
- dict_sys.mutex_lock();
-
for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
index != 0;
index = UT_LIST_GET_NEXT(indexes, index)) {
@@ -498,8 +496,6 @@ row_quiesce_table_has_fts_index(
}
}
- dict_sys.mutex_unlock();
-
return(exists);
}
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index 704c067fc43..2c7408c950a 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -182,7 +182,7 @@ restart:
lock_release_on_rollback(node->trx,
table);
if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
}
if (table->release()) {
dict_sys.remove(table);
@@ -192,7 +192,7 @@ restart:
table->file_unreadable = true;
}
if (!dict_locked) {
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
}
table = nullptr;
if (!mdl_ticket);
@@ -432,9 +432,9 @@ static bool row_undo_ins_parse_undo_rec(undo_node_t* node, bool dict_locked)
node->table = dict_table_open_on_id(table_id, dict_locked,
DICT_TABLE_OP_NORMAL);
} else if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
node->table = dict_sys.acquire_temporary_table(table_id);
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
} else {
node->table = dict_sys.acquire_temporary_table(table_id);
}
@@ -642,21 +642,19 @@ row_undo_ins(
log_free_check();
- if (node->table->id == DICT_INDEXES_ID) {
- ut_ad(!node->table->is_temporary());
- if (!dict_locked) {
- dict_sys.mutex_lock();
- }
+ if (!dict_locked && node->table->id == DICT_INDEXES_ID) {
+ dict_sys.lock(SRW_LOCK_CALL);
err = row_undo_ins_remove_clust_rec(node);
- if (!dict_locked) {
- dict_sys.mutex_unlock();
- }
+ dict_sys.unlock();
} else {
+ ut_ad(node->table->id != DICT_INDEXES_ID
+ || !node->table->is_temporary());
err = row_undo_ins_remove_clust_rec(node);
}
if (err == DB_SUCCESS && node->table->stat_initialized) {
- /* Not protected by dict_sys.mutex for
+ /* Not protected by dict_sys.latch
+ or table->stats_mutex_lock() for
performance reasons, we would rather get garbage
in stat_n_rows (which is just an estimate anyway)
than protecting the following code with a latch. */
@@ -665,7 +663,7 @@ row_undo_ins(
/* Do not attempt to update statistics when
executing ROLLBACK in the InnoDB SQL
interpreter, because in that case we would
- already be holding dict_sys.mutex, which
+ already be holding dict_sys.latch, which
would be acquired when updating statistics. */
if (!dict_locked) {
dict_stats_update_if_needed(node->table,
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index ba675c927eb..5039df2e1a6 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -1215,9 +1215,9 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked)
node->table = dict_table_open_on_id(table_id, dict_locked,
DICT_TABLE_OP_NORMAL);
} else if (!dict_locked) {
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
node->table = dict_sys.acquire_temporary_table(table_id);
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
} else {
node->table = dict_sys.acquire_temporary_table(table_id);
}
@@ -1391,7 +1391,7 @@ rollback_clust:
/* Do not attempt to update statistics when
executing ROLLBACK in the InnoDB SQL
interpreter, because in that case we would
- already be holding dict_sys.mutex, which
+ already be holding dict_sys.latch, which
would be acquired when updating statistics. */
if (update_statistics && !dict_locked) {
dict_stats_update_if_needed(node->table,
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 41cae945c99..88cd90fe778 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -157,7 +157,7 @@ wsrep_row_upd_index_is_foreign(
/* No MDL protects dereferencing the members of table->foreign_set. */
const bool no_lock= !trx->dict_operation_lock_mode;
if (no_lock)
- dict_sys.mutex_lock();
+ dict_sys.freeze(SRW_LOCK_CALL);
auto end= table->foreign_set.end();
const bool is_referenced= end !=
@@ -165,7 +165,7 @@ wsrep_row_upd_index_is_foreign(
[index](const dict_foreign_t* f)
{return f->foreign_index == index;});
if (no_lock)
- dict_sys.mutex_unlock();
+ dict_sys.unfreeze();
return is_referenced;
}
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 81e0a3d2b79..d76a98e83e7 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -1297,7 +1297,7 @@ void srv_monitor_task(void*)
|| waited == threshold / 2
|| waited == threshold / 4 * 3) {
ib::warn() << "Long wait (" << waited
- << " seconds) for dict_sys.mutex";
+ << " seconds) for dict_sys.latch";
}
}
}
@@ -1371,8 +1371,6 @@ void purge_sys_t::stop_SYS()
/** Stop purge during FLUSH TABLES FOR EXPORT */
void purge_sys_t::stop()
{
- dict_sys.assert_not_locked();
-
for (;;)
{
latch.wr_lock(SRW_LOCK_CALL);
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 18c1eea3ab5..f983719f95b 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -604,10 +604,10 @@ trx_resurrect_table_locks(
if (dict_table_t* table = dict_table_open_on_id(
p.first, FALSE, DICT_TABLE_OP_LOAD_TABLESPACE)) {
if (!table->is_readable()) {
- dict_sys.mutex_lock();
+ dict_sys.lock(SRW_LOCK_CALL);
dict_table_close(table, TRUE, FALSE);
dict_sys.remove(table);
- dict_sys.mutex_unlock();
+ dict_sys.unlock();
continue;
}