Commit ba6bf7ad authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-32899 instrumentation

In debug builds, let us declare dict_sys.latch as index_lock instead of
srw_lock, so that we will benefit from the full tracking of lock ownership.

lock_table_for_trx(): Assert that the current thread is not holding
dict_sys.latch. If the dict_sys.unfreeze() call were moved to the end of
lock_table_children(), this assertion would fail in the test innodb.innodb
and many other tests that use FOREIGN KEY.
parent 569da6a7
@@ -7,7 +7,6 @@
WHERE name LIKE 'wait/synch/rwlock/innodb/%'
AND name!='wait/synch/rwlock/innodb/btr_search_latch' ORDER BY name;
name
-wait/synch/rwlock/innodb/dict_operation_lock
wait/synch/rwlock/innodb/fil_space_latch
wait/synch/rwlock/innodb/lock_latch
wait/synch/rwlock/innodb/trx_i_s_cache_lock
@@ -19,11 +18,13 @@
select name from performance_schema.setup_instruments
where name like "wait/synch/sxlock/%" order by name;
name
+wait/synch/sxlock/innodb/dict_operation_lock
wait/synch/sxlock/innodb/index_tree_rw_lock
SELECT DISTINCT name FROM performance_schema.rwlock_instances
WHERE name LIKE 'wait/synch/sxlock/innodb/%'
ORDER BY name;
name
+wait/synch/sxlock/innodb/dict_operation_lock
wait/synch/sxlock/innodb/index_tree_rw_lock
create table t1(a int) engine=innodb;
begin;
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/have_perfschema.inc --source include/have_perfschema.inc
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/maybe_debug.inc
UPDATE performance_schema.setup_instruments SET enabled = 'NO', timed = 'YES'; UPDATE performance_schema.setup_instruments SET enabled = 'NO', timed = 'YES';
......
...@@ -958,11 +958,12 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) ...@@ -958,11 +958,12 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line))
if (latch_ex_wait_start.compare_exchange_strong if (latch_ex_wait_start.compare_exchange_strong
(old, now, std::memory_order_relaxed, std::memory_order_relaxed)) (old, now, std::memory_order_relaxed, std::memory_order_relaxed))
{ {
#ifdef UNIV_DEBUG
latch.x_lock(SRW_LOCK_ARGS(file, line));
#else
latch.wr_lock(SRW_LOCK_ARGS(file, line)); latch.wr_lock(SRW_LOCK_ARGS(file, line));
#endif
latch_ex_wait_start.store(0, std::memory_order_relaxed); latch_ex_wait_start.store(0, std::memory_order_relaxed);
ut_ad(!latch_readers);
ut_ad(!latch_ex);
ut_d(latch_ex= pthread_self());
return; return;
} }
...@@ -977,33 +978,39 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) ...@@ -977,33 +978,39 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line))
if (waited > threshold / 4) if (waited > threshold / 4)
ib::warn() << "A long wait (" << waited ib::warn() << "A long wait (" << waited
<< " seconds) was observed for dict_sys.latch"; << " seconds) was observed for dict_sys.latch";
#ifdef UNIV_DEBUG
latch.x_lock(SRW_LOCK_ARGS(file, line));
#else
latch.wr_lock(SRW_LOCK_ARGS(file, line)); latch.wr_lock(SRW_LOCK_ARGS(file, line));
ut_ad(!latch_readers); #endif
ut_ad(!latch_ex);
ut_d(latch_ex= pthread_self());
} }
#ifdef UNIV_PFS_RWLOCK #ifdef UNIV_PFS_RWLOCK
ATTRIBUTE_NOINLINE void dict_sys_t::unlock() ATTRIBUTE_NOINLINE void dict_sys_t::unlock()
{ {
ut_ad(latch_ex == pthread_self()); # ifdef UNIV_DEBUG
ut_ad(!latch_readers); latch.x_unlock();
ut_d(latch_ex= 0); # else
latch.wr_unlock(); latch.wr_unlock();
# endif
} }
ATTRIBUTE_NOINLINE void dict_sys_t::freeze(const char *file, unsigned line) ATTRIBUTE_NOINLINE void dict_sys_t::freeze(const char *file, unsigned line)
{ {
# ifdef UNIV_DEBUG
latch.s_lock(file, line);
# else
latch.rd_lock(file, line); latch.rd_lock(file, line);
ut_ad(!latch_ex); # endif
ut_d(latch_readers++);
} }
ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze() ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze()
{ {
ut_ad(!latch_ex); # ifdef UNIV_DEBUG
ut_ad(latch_readers--); latch.s_unlock();
# else
latch.rd_unlock(); latch.rd_unlock();
# endif
} }
#endif /* UNIV_PFS_RWLOCK */ #endif /* UNIV_PFS_RWLOCK */
...@@ -4533,7 +4540,11 @@ void dict_sys_t::close() ...@@ -4533,7 +4540,11 @@ void dict_sys_t::close()
temp_id_hash.free(); temp_id_hash.free();
unlock(); unlock();
#ifdef UNIV_DEBUG
latch.free();
#else
latch.destroy(); latch.destroy();
#endif
mysql_mutex_destroy(&dict_foreign_err_mutex); mysql_mutex_destroy(&dict_foreign_err_mutex);
......
...@@ -598,7 +598,13 @@ static PSI_rwlock_info all_innodb_rwlocks[] = ...@@ -598,7 +598,13 @@ static PSI_rwlock_info all_innodb_rwlocks[] =
# ifdef BTR_CUR_HASH_ADAPT # ifdef BTR_CUR_HASH_ADAPT
{ &btr_search_latch_key, "btr_search_latch", 0 }, { &btr_search_latch_key, "btr_search_latch", 0 },
# endif # endif
{ &dict_operation_lock_key, "dict_operation_lock", 0 }, { &dict_operation_lock_key, "dict_operation_lock",
# ifdef UNIV_DEBUG
PSI_RWLOCK_FLAG_SX
# else
0
# endif
},
{ &fil_space_latch_key, "fil_space_latch", 0 }, { &fil_space_latch_key, "fil_space_latch", 0 },
{ &trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0 }, { &trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0 },
{ &trx_purge_latch_key, "trx_purge_latch", 0 }, { &trx_purge_latch_key, "trx_purge_latch", 0 },
......
...@@ -1316,14 +1316,14 @@ class dict_sys_t ...@@ -1316,14 +1316,14 @@ class dict_sys_t
/** The my_hrtime_coarse().val of the oldest lock_wait() start, or 0 */ /** The my_hrtime_coarse().val of the oldest lock_wait() start, or 0 */
std::atomic<ulonglong> latch_ex_wait_start; std::atomic<ulonglong> latch_ex_wait_start;
/** the rw-latch protecting the data dictionary cache */
alignas(CPU_LEVEL1_DCACHE_LINESIZE) srw_lock latch;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** whether latch is being held in exclusive mode (by any thread) */ typedef index_lock dict_lock;
Atomic_relaxed<pthread_t> latch_ex; #else
/** number of S-latch holders */ typedef srw_lock dict_lock;
Atomic_counter<uint32_t> latch_readers;
#endif #endif
/** the rw-latch protecting the data dictionary cache */
alignas(CPU_LEVEL1_DCACHE_LINESIZE) dict_lock latch;
public: public:
/** Indexes of SYS_TABLE[] */ /** Indexes of SYS_TABLE[] */
enum enum
...@@ -1491,15 +1491,12 @@ class dict_sys_t ...@@ -1491,15 +1491,12 @@ class dict_sys_t
} }
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** @return whether any thread (not necessarily the current thread) /** @return whether the current thread is holding the latch */
is holding the latch; that is, this check may return false bool frozen() const { return latch.have_any(); }
positives */ /** @return whether the current thread is holding a shared latch */
bool frozen() const { return latch_readers || latch_ex; } bool frozen_not_locked() const { return latch.have_s(); }
/** @return whether any thread (not necessarily the current thread)
is holding a shared latch */
bool frozen_not_locked() const { return latch_readers; }
/** @return whether the current thread holds the exclusive latch */ /** @return whether the current thread holds the exclusive latch */
bool locked() const { return latch_ex == pthread_self(); } bool locked() const { return latch.have_x(); }
#endif #endif
private: private:
/** Acquire the exclusive latch */ /** Acquire the exclusive latch */
...@@ -1514,13 +1511,11 @@ class dict_sys_t ...@@ -1514,13 +1511,11 @@ class dict_sys_t
/** Exclusively lock the dictionary cache. */ /** Exclusively lock the dictionary cache. */
void lock(SRW_LOCK_ARGS(const char *file, unsigned line)) void lock(SRW_LOCK_ARGS(const char *file, unsigned line))
{ {
if (latch.wr_lock_try()) #ifdef UNIV_DEBUG
{ if (!latch.x_lock_try())
ut_ad(!latch_readers); #else
ut_ad(!latch_ex); if (!latch.wr_lock_try())
ut_d(latch_ex= pthread_self()); #endif
}
else
lock_wait(SRW_LOCK_ARGS(file, line)); lock_wait(SRW_LOCK_ARGS(file, line));
} }
...@@ -1535,24 +1530,29 @@ class dict_sys_t ...@@ -1535,24 +1530,29 @@ class dict_sys_t
/** Unlock the data dictionary cache. */ /** Unlock the data dictionary cache. */
void unlock() void unlock()
{ {
ut_ad(latch_ex == pthread_self()); # ifdef UNIV_DEBUG
ut_ad(!latch_readers); latch.x_unlock();
ut_d(latch_ex= 0); # else
latch.wr_unlock(); latch.wr_unlock();
# endif
} }
/** Acquire a shared lock on the dictionary cache. */ /** Acquire a shared lock on the dictionary cache. */
void freeze() void freeze()
{ {
# ifdef UNIV_DEBUG
latch.s_lock();
# else
latch.rd_lock(); latch.rd_lock();
ut_ad(!latch_ex); # endif
ut_d(latch_readers++);
} }
/** Release a shared lock on the dictionary cache. */ /** Release a shared lock on the dictionary cache. */
void unfreeze() void unfreeze()
{ {
ut_ad(!latch_ex); # ifdef UNIV_DEBUG
ut_ad(latch_readers--); latch.s_unlock();
# else
latch.rd_unlock(); latch.rd_unlock();
# endif
} }
#endif #endif
......
...@@ -3940,6 +3940,8 @@ static void lock_table_dequeue(lock_t *in_lock, bool owns_wait_mutex) ...@@ -3940,6 +3940,8 @@ static void lock_table_dequeue(lock_t *in_lock, bool owns_wait_mutex)
dberr_t lock_table_for_trx(dict_table_t *table, trx_t *trx, lock_mode mode, dberr_t lock_table_for_trx(dict_table_t *table, trx_t *trx, lock_mode mode,
bool no_wait) bool no_wait)
{ {
ut_ad(!dict_sys.frozen());
mem_heap_t *heap= mem_heap_create(512); mem_heap_t *heap= mem_heap_create(512);
sel_node_t *node= sel_node_create(heap); sel_node_t *node= sel_node_create(heap);
que_thr_t *thr= pars_complete_graph_for_exec(node, trx, heap, nullptr); que_thr_t *thr= pars_complete_graph_for_exec(node, trx, heap, nullptr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment