summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-10-21 20:41:10 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-10-21 20:41:10 +0300
commit4f59f9078fd9af1e958f4a30788084598053bf50 (patch)
treea2ec7a8be96098370ad61e890410a200717e0191
parent193f9df9bc4c353c0c3bd259da8afab545c14130 (diff)
downloadmariadb-git-4f59f9078fd9af1e958f4a30788084598053bf50.tar.gz
Fix hang due to lock_sys_t::cancel()
TODO: file a bug for this
-rw-r--r--storage/innobase/lock/lock0lock.cc21
1 files changed, 19 insertions, 2 deletions
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 6abbc58f9be..234d215d1df 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -5690,10 +5690,25 @@ dberr_t lock_sys_t::cancel(trx_t *trx, lock_t *lock)
{
resolve_table_lock:
dict_table_t *table= lock->un_member.tab_lock.table;
- table->lock_mutex_lock();
+ if (!table->lock_mutex_trylock())
+ {
+ /* The correct latching order is:
+ lock_sys.latch, table->lock_mutex_lock(), lock_sys.wait_mutex.
+ Thus, we must release lock_sys.wait_mutex for a blocking wait. */
+ mysql_mutex_unlock(&lock_sys.wait_mutex);
+ table->lock_mutex_lock();
+ mysql_mutex_lock(&lock_sys.wait_mutex);
+ lock= trx->lock.wait_lock;
+ if (!lock)
+ goto retreat;
+ else if (check_victim && trx->lock.was_chosen_as_deadlock_victim)
+ {
+ err= DB_DEADLOCK;
+ goto retreat;
+ }
+ }
if (lock->is_waiting())
lock_cancel_waiting_and_release(lock);
- table->lock_mutex_unlock();
/* Even if lock->is_waiting() did not hold above, we must return
DB_LOCK_WAIT, or otherwise optimistic parallel replication could
occasionally hang. Potentially affected tests:
@@ -5701,6 +5716,8 @@ resolve_table_lock:
rpl.rpl_parallel_optimistic_nobinlog
rpl.rpl_parallel_optimistic_xa_lsu_off */
err= DB_LOCK_WAIT;
+retreat:
+ table->lock_mutex_unlock();
}
lock_sys.rd_unlock();
}