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 @@
--source include/not_embedded.inc
--source include/have_perfschema.inc
--source include/have_innodb.inc
--source include/maybe_debug.inc
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))
if (latch_ex_wait_start.compare_exchange_strong
(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));
#endif
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;
}
......@@ -977,33 +978,39 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line))
if (waited > threshold / 4)
ib::warn() << "A long wait (" << waited
<< " 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));
ut_ad(!latch_readers);
ut_ad(!latch_ex);
ut_d(latch_ex= pthread_self());
#endif
}
#ifdef UNIV_PFS_RWLOCK
ATTRIBUTE_NOINLINE void dict_sys_t::unlock()
{
ut_ad(latch_ex == pthread_self());
ut_ad(!latch_readers);
ut_d(latch_ex= 0);
# ifdef UNIV_DEBUG
latch.x_unlock();
# else
latch.wr_unlock();
# endif
}
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);
ut_ad(!latch_ex);
ut_d(latch_readers++);
# endif
}
ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze()
{
ut_ad(!latch_ex);
ut_ad(latch_readers--);
# ifdef UNIV_DEBUG
latch.s_unlock();
# else
latch.rd_unlock();
# endif
}
#endif /* UNIV_PFS_RWLOCK */
......@@ -4533,7 +4540,11 @@ void dict_sys_t::close()
temp_id_hash.free();
unlock();
#ifdef UNIV_DEBUG
latch.free();
#else
latch.destroy();
#endif
mysql_mutex_destroy(&dict_foreign_err_mutex);
......
......@@ -598,7 +598,13 @@ static PSI_rwlock_info all_innodb_rwlocks[] =
# ifdef BTR_CUR_HASH_ADAPT
{ &btr_search_latch_key, "btr_search_latch", 0 },
# 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 },
{ &trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0 },
{ &trx_purge_latch_key, "trx_purge_latch", 0 },
......
......@@ -1316,14 +1316,14 @@ class dict_sys_t
/** The my_hrtime_coarse().val of the oldest lock_wait() start, or 0 */
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
/** whether latch is being held in exclusive mode (by any thread) */
Atomic_relaxed<pthread_t> latch_ex;
/** number of S-latch holders */
Atomic_counter<uint32_t> latch_readers;
typedef index_lock dict_lock;
#else
typedef srw_lock dict_lock;
#endif
/** the rw-latch protecting the data dictionary cache */
alignas(CPU_LEVEL1_DCACHE_LINESIZE) dict_lock latch;
public:
/** Indexes of SYS_TABLE[] */
enum
......@@ -1491,15 +1491,12 @@ class dict_sys_t
}
#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 || latch_ex; }
/** @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 is holding the latch */
bool frozen() const { return latch.have_any(); }
/** @return whether the current thread is holding a shared latch */
bool frozen_not_locked() const { return latch.have_s(); }
/** @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
private:
/** Acquire the exclusive latch */
......@@ -1514,13 +1511,11 @@ class dict_sys_t
/** 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= pthread_self());
}
else
#ifdef UNIV_DEBUG
if (!latch.x_lock_try())
#else
if (!latch.wr_lock_try())
#endif
lock_wait(SRW_LOCK_ARGS(file, line));
}
......@@ -1535,24 +1530,29 @@ class dict_sys_t
/** Unlock the data dictionary cache. */
void unlock()
{
ut_ad(latch_ex == pthread_self());
ut_ad(!latch_readers);
ut_d(latch_ex= 0);
# ifdef UNIV_DEBUG
latch.x_unlock();
# else
latch.wr_unlock();
# endif
}
/** Acquire a shared lock on the dictionary cache. */
void freeze()
{
# ifdef UNIV_DEBUG
latch.s_lock();
# else
latch.rd_lock();
ut_ad(!latch_ex);
ut_d(latch_readers++);
# endif
}
/** Release a shared lock on the dictionary cache. */
void unfreeze()
{
ut_ad(!latch_ex);
ut_ad(latch_readers--);
# ifdef UNIV_DEBUG
latch.s_unlock();
# else
latch.rd_unlock();
# endif
}
#endif
......
......@@ -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,
bool no_wait)
{
ut_ad(!dict_sys.frozen());
mem_heap_t *heap= mem_heap_create(512);
sel_node_t *node= sel_node_create(heap);
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