mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
22
mysql-test/suite/perfschema/r/sxlock_func,debug.rdiff
Normal file
22
mysql-test/suite/perfschema/r/sxlock_func,debug.rdiff
Normal file
@ -0,0 +1,22 @@
|
||||
@@ -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 @@ public:
|
||||
}
|
||||
|
||||
#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 @@ public:
|
||||
/** 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 @@ public:
|
||||
/** 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);
|
||||
|
Reference in New Issue
Block a user