diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 5348a67e8c923..453aa6870ad78 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1719,7 +1719,12 @@ ATTRIBUTE_COLD void mtr_t::index_lock_upgrade() return; ut_ad(slot.type == MTR_MEMO_SX_LOCK); index_lock *lock= static_cast(slot.object); - lock->u_x_upgrade(SRW_LOCK_CALL); + if (!lock->u_x_upgrade_try()) + { + lock->u_unlock(); + ut_ad(!lock->have_any()); + lock->x_lock(SRW_LOCK_CALL); + } slot.type= MTR_MEMO_X_LOCK; } diff --git a/storage/innobase/include/srw_lock.h b/storage/innobase/include/srw_lock.h index 79a3e7c42a7b0..7a0b4d8c33092 100644 --- a/storage/innobase/include/srw_lock.h +++ b/storage/innobase/include/srw_lock.h @@ -289,6 +289,15 @@ class ssux_lock_impl bool rd_u_upgrade_try() noexcept { return writer.wr_lock_try(); } + bool u_wr_upgrade_try() noexcept + { + DBUG_ASSERT(writer.is_locked()); + uint32_t lk= 0; + return readers.compare_exchange_strong(lk, WRITER, + std::memory_order_acquire, + std::memory_order_relaxed); + } + void u_wr_upgrade() noexcept { DBUG_ASSERT(writer.is_locked()); @@ -496,6 +505,7 @@ class ssux_lock else lock.u_wr_upgrade(); } + bool u_wr_upgrade_try() noexcept { return lock.u_wr_upgrade_try(); } bool rd_lock_try() noexcept { return lock.rd_lock_try(); } bool u_lock_try() noexcept { return lock.u_lock_try(); } bool wr_lock_try() noexcept { return lock.wr_lock_try(); } diff --git a/storage/innobase/include/sux_lock.h b/storage/innobase/include/sux_lock.h index 83fa552aafc9c..0f18210084979 100644 --- a/storage/innobase/include/sux_lock.h +++ b/storage/innobase/include/sux_lock.h @@ -196,8 +196,18 @@ class sux_lock final /** Upgrade an update lock */ inline void u_x_upgrade(); inline void u_x_upgrade(const char *file, unsigned line); + /** @return whether an update lock was upgraded to exclusive */ + bool u_x_upgrade_try() noexcept + { + ut_ad(have_u_not_x()); + if (!lock.u_wr_upgrade_try()) + return false; + recursive/= RECURSIVE_U; + return true; + } + /** @return whether a shared lock was upgraded to exclusive */ - bool s_x_upgrade_try() + bool s_x_upgrade_try() noexcept { ut_ad(have_s()); ut_ad(!have_u_or_x()); @@ -205,7 +215,12 @@ class sux_lock final return false; claim_ownership(); s_unlock(); - lock.u_wr_upgrade(); + if (!lock.u_wr_upgrade_try()) + { + ut_d(recursive= RECURSIVE_U); + u_s_downgrade(); + return false; + } recursive= RECURSIVE_X; return true; }