diff options
author | Sergey Vojtovich <svoj@mariadb.org> | 2014-04-23 11:34:06 +0400 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2014-04-23 11:34:06 +0400 |
commit | b1232490107fd5b832912f324fb59ae7f56650b8 (patch) | |
tree | 194c2781143f88d114e5fc6fc0ef5c17288ada62 /sql/mdl.cc | |
parent | 504068b093e94e91010a3c9b97069029a27f9d16 (diff) | |
download | mariadb-git-b1232490107fd5b832912f324fb59ae7f56650b8.tar.gz |
MDEV-5792 - Deadlock between SELECTs from METADATA_LOCK_INFO and another
I_S table
mdl_iterate() helper function (which is used by the plugin to iterate mdl
locks) acquired mutexes in reverse order.
Fixed by iterating MDL locks in two stages:
1. Iterate locks hash under the protection of hash mutex, store all
lock pointers in a thread local array and increment reference counter
for the lock.
2. Iterate local array without protection of hash mutex, handle destroyed
locks.
It somewhat echoes hack in MDL_map_partition::move_from_hash_to_lock_mutex.
Diffstat (limited to 'sql/mdl.cc')
-rw-r--r-- | sql/mdl.cc | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/sql/mdl.cc b/sql/mdl.cc index 374a0407f78..2c2d64e96b2 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -718,6 +718,7 @@ static inline int mdl_iterate_lock(MDL_lock *lock, int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg) { + DYNAMIC_ARRAY locks; uint i, j; int res; DBUG_ENTER("mdl_iterate"); @@ -726,18 +727,48 @@ int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg) (res= mdl_iterate_lock(mdl_locks.m_commit_lock, callback, arg))) DBUG_RETURN(res); + my_init_dynamic_array(&locks, sizeof(MDL_lock*), 512, 1, MYF(0)); + for (i= 0; i < mdl_locks.m_partitions.elements(); i++) { MDL_map_partition *part= mdl_locks.m_partitions.at(i); + /* Collect all locks first */ mysql_mutex_lock(&part->m_mutex); + if (allocate_dynamic(&locks, part->m_locks.records)) + { + res= 1; + mysql_mutex_unlock(&part->m_mutex); + break; + } + reset_dynamic(&locks); for (j= 0; j < part->m_locks.records; j++) { - if ((res= mdl_iterate_lock((MDL_lock*) my_hash_element(&part->m_locks, j), - callback, arg))) - break; + MDL_lock *lock= (MDL_lock*) my_hash_element(&part->m_locks, j); + lock->m_ref_usage++; + insert_dynamic(&locks, &lock); } mysql_mutex_unlock(&part->m_mutex); + + /* Now show them */ + for (j= 0; j < locks.elements; j++) + { + MDL_lock *lock= (MDL_lock*) *dynamic_element(&locks, j, MDL_lock**); + res= mdl_iterate_lock(lock, callback, arg); + + mysql_prlock_wrlock(&lock->m_rwlock); + uint ref_usage= lock->m_ref_usage; + uint ref_release= ++lock->m_ref_release; + bool is_destroyed= lock->m_is_destroyed; + mysql_prlock_unlock(&lock->m_rwlock); + + if (unlikely(is_destroyed && ref_usage == ref_release)) + MDL_lock::destroy(lock); + + if (res) + break; + } } + delete_dynamic(&locks); DBUG_RETURN(res); } |