MDEV-21423: Replace trx_sys.rw_trx_hash with a locked hash table
The embedded page_hash_latch in buf_pool.page_hash have served us well.
Let us attempt the same approach for trx_sys.rw_trx_hash,
instead of using the lock-free hash table that is unable to shrink.
Compared to the lock-free hash table, any iteration of the entire
hash table, as in rw_trx_hash.for_each() or rw_trx_hash.for_each_until()
may potentially modify a large number of cache lines.
Outside debug checks, trx_sys.rw_trx_hash is being iterated in
ReadView::open(), trx_sys_t::clone_oldest_view(), and
trx_sys_t::get_min_trx_id() (invoked on secondary index lock checks).
To reduce the impact of locking on processors
that support transactional memory, we introduce the predicate
rw_trx_hash_t::empty() so that unnecessary acquisition and releasing
of hash array latches can be avoided when an entire slice of the
hash array is empty.
FIXME: This is reducing throughput in many cases. How to improve this
further?
TODO: Find a reasonable value for the constexpr size_t n_cells.
A few PERFORMANCE_SCHEMA instrumentation keys were not exposed
in all_innodb_mutexes[]. Let us remove them.
The keys fts_pll_tokenize_mutex_key and read_view_mutex_key were
internally used. Let us make ReadView::m_mutex use the simpler
and smaller srw_mutex, hoping to improve memory access patterns.
MDEV-27767 poor scaling with InnoDB and utf8mb3 because of charset stats
Access the all_charsets[] array directly in a hot loop.
This avoids get_charset() that increments a shared counter via
my_collation_statistics_inc_use_count(), causing a scalability issue.
Instead, call get_charset() when a table is opened (and InnoDB
fills in dtype_t values) - this is enough, as charset is marked
ready (MY_CS_READY) only once, on the first get_charset() call,
after that it can be accessed directly.
This also fixes a potential bug in InnoDB. It used to access charsets
directly when filling dtype_t values. This wasn't preceded by any
get_charset() call inside InnoDB. Normally the server would call
get_charset() on reading the frm, but if the table was first opened
from a purge thread InnoDB could, theoretically, access a not-ready
charset in innobase_get_cset_width().