1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Revert "MDEV-32899 InnoDB is holding shared dict_sys.latch while waiting for FOREIGN KEY child table lock on DDL"

This reverts commit 569da6a7ba,
commit 768a736174, and
commit ba6bf7ad9e
because of a regression that was filed as MDEV-33104.
This commit is contained in:
Marko Mäkelä
2024-01-19 12:46:11 +02:00
parent 7e65e3027e
commit 21560bee9d
8 changed files with 79 additions and 128 deletions

View File

@ -1,22 +0,0 @@
@@ -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;

View File

@ -5,7 +5,6 @@
--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';

View File

@ -958,12 +958,11 @@ 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;
} }
@ -978,39 +977,33 @@ 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));
#endif ut_ad(!latch_readers);
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()
{ {
# ifdef UNIV_DEBUG ut_ad(latch_ex == pthread_self());
latch.x_unlock(); ut_ad(!latch_readers);
# else ut_d(latch_ex= 0);
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);
# endif ut_ad(!latch_ex);
ut_d(latch_readers++);
} }
ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze() ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze()
{ {
# ifdef UNIV_DEBUG ut_ad(!latch_ex);
latch.s_unlock(); ut_ad(latch_readers--);
# else
latch.rd_unlock(); latch.rd_unlock();
# endif
} }
#endif /* UNIV_PFS_RWLOCK */ #endif /* UNIV_PFS_RWLOCK */
@ -4544,11 +4537,7 @@ 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);

View File

@ -598,13 +598,7 @@ 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", { &dict_operation_lock_key, "dict_operation_lock", 0 },
# 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 },
@ -13546,7 +13540,14 @@ int ha_innobase::delete_table(const char *name)
/* FOREIGN KEY constraints cannot exist on partitioned tables. */; /* FOREIGN KEY constraints cannot exist on partitioned tables. */;
#endif #endif
else else
err= lock_table_children(table, trx); {
dict_sys.freeze(SRW_LOCK_CALL);
for (const dict_foreign_t* f : table->referenced_set)
if (dict_table_t* child= f->foreign_table)
if ((err= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS)
break;
dict_sys.unfreeze();
}
} }
dict_table_t *table_stats= nullptr, *index_stats= nullptr; dict_table_t *table_stats= nullptr, *index_stats= nullptr;
@ -13944,7 +13945,14 @@ int ha_innobase::truncate()
dict_table_t *table_stats = nullptr, *index_stats = nullptr; dict_table_t *table_stats = nullptr, *index_stats = nullptr;
MDL_ticket *mdl_table = nullptr, *mdl_index = nullptr; MDL_ticket *mdl_table = nullptr, *mdl_index = nullptr;
dberr_t error= lock_table_children(ib_table, trx); dberr_t error= DB_SUCCESS;
dict_sys.freeze(SRW_LOCK_CALL);
for (const dict_foreign_t *f : ib_table->referenced_set)
if (dict_table_t *child= f->foreign_table)
if ((error= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS)
break;
dict_sys.unfreeze();
if (error == DB_SUCCESS) if (error == DB_SUCCESS)
error= lock_table_for_trx(ib_table, trx, LOCK_X); error= lock_table_for_trx(ib_table, trx, LOCK_X);
@ -14135,7 +14143,16 @@ ha_innobase::rename_table(
/* There is no need to lock any FOREIGN KEY child tables. */ /* There is no need to lock any FOREIGN KEY child tables. */
} else if (dict_table_t *table = dict_table_open_on_name( } else if (dict_table_t *table = dict_table_open_on_name(
norm_from, false, DICT_ERR_IGNORE_FK_NOKEY)) { norm_from, false, DICT_ERR_IGNORE_FK_NOKEY)) {
error = lock_table_children(table, trx); dict_sys.freeze(SRW_LOCK_CALL);
for (const dict_foreign_t* f : table->referenced_set) {
if (dict_table_t* child = f->foreign_table) {
error = lock_table_for_trx(child, trx, LOCK_X);
if (error != DB_SUCCESS) {
break;
}
}
}
dict_sys.unfreeze();
if (error == DB_SUCCESS) { if (error == DB_SUCCESS) {
error = lock_table_for_trx(table, trx, LOCK_X); error = lock_table_for_trx(table, trx, LOCK_X);
} }

View File

@ -11203,7 +11203,16 @@ ha_innobase::commit_inplace_alter_table(
fts_optimize_remove_table(ctx->old_table); fts_optimize_remove_table(ctx->old_table);
} }
error = lock_table_children(ctx->old_table, trx); dict_sys.freeze(SRW_LOCK_CALL);
for (auto f : ctx->old_table->referenced_set) {
if (dict_table_t* child = f->foreign_table) {
error = lock_table_for_trx(child, trx, LOCK_X);
if (error != DB_SUCCESS) {
break;
}
}
}
dict_sys.unfreeze();
if (ctx->new_table->fts) { if (ctx->new_table->fts) {
ut_ad(!ctx->new_table->fts->add_wq); ut_ad(!ctx->new_table->fts->add_wq);

View File

@ -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;
#ifdef UNIV_DEBUG
typedef index_lock dict_lock;
#else
typedef srw_lock dict_lock;
#endif
/** the rw-latch protecting the data dictionary cache */ /** the rw-latch protecting the data dictionary cache */
alignas(CPU_LEVEL1_DCACHE_LINESIZE) dict_lock latch; 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;
#endif
public: public:
/** Indexes of SYS_TABLE[] */ /** Indexes of SYS_TABLE[] */
enum enum
@ -1491,12 +1491,15 @@ public:
} }
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** @return whether the current thread is holding the latch */ /** @return whether any thread (not necessarily the current thread)
bool frozen() const { return latch.have_any(); } is holding the latch; that is, this check may return false
/** @return whether the current thread is holding a shared latch */ positives */
bool frozen_not_locked() const { return latch.have_s(); } 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 holds the exclusive latch */ /** @return whether the current thread holds the exclusive latch */
bool locked() const { return latch.have_x(); } bool locked() const { return latch_ex == pthread_self(); }
#endif #endif
private: private:
/** Acquire the exclusive latch */ /** Acquire the exclusive latch */
@ -1511,12 +1514,13 @@ public:
/** 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))
{ {
#ifdef UNIV_DEBUG if (latch.wr_lock_try())
ut_ad(!latch.have_any()); {
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));
} }
@ -1531,30 +1535,24 @@ public:
/** Unlock the data dictionary cache. */ /** Unlock the data dictionary cache. */
void unlock() void unlock()
{ {
# ifdef UNIV_DEBUG ut_ad(latch_ex == pthread_self());
latch.x_unlock(); ut_ad(!latch_readers);
# else ut_d(latch_ex= 0);
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
ut_ad(!latch.have_any());
latch.s_lock();
# else
latch.rd_lock(); latch.rd_lock();
# endif ut_ad(!latch_ex);
ut_d(latch_readers++);
} }
/** Release a shared lock on the dictionary cache. */ /** Release a shared lock on the dictionary cache. */
void unfreeze() void unfreeze()
{ {
# ifdef UNIV_DEBUG ut_ad(!latch_ex);
latch.s_unlock(); ut_ad(latch_readers--);
# else
latch.rd_unlock(); latch.rd_unlock();
# endif
} }
#endif #endif

View File

@ -438,13 +438,6 @@ dberr_t lock_table_for_trx(dict_table_t *table, trx_t *trx, lock_mode mode,
bool no_wait= false) bool no_wait= false)
MY_ATTRIBUTE((nonnull, warn_unused_result)); MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Lock the child tables of a table.
@param table parent table
@param trx transaction
@return error code */
dberr_t lock_table_children(dict_table_t *table, trx_t *trx)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Exclusively lock the data dictionary tables. /** Exclusively lock the data dictionary tables.
@param trx dictionary transaction @param trx dictionary transaction
@return error code @return error code

View File

@ -3940,8 +3940,6 @@ 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);
@ -3978,36 +3976,6 @@ run_again:
return err; return err;
} }
/** Lock the child tables of a table.
@param table parent table
@param trx transaction
@return error code */
dberr_t lock_table_children(dict_table_t *table, trx_t *trx)
{
dict_sys.freeze(SRW_LOCK_CALL);
std::vector<dict_table_t*> children;
for (auto f : table->referenced_set)
if (dict_table_t *child= f->foreign_table)
{
child->acquire();
children.emplace_back(child);
}
dict_sys.unfreeze();
dberr_t err= DB_SUCCESS;
for (auto child : children)
if ((err= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS)
break;
for (auto child : children)
child->release();
return err;
}
/** Exclusively lock the data dictionary tables. /** Exclusively lock the data dictionary tables.
@param trx dictionary transaction @param trx dictionary transaction
@return error code @return error code