Skip to content

Commit 8d16da1

Browse files
committed
MDEV-24789: Reduce lock_sys mutex contention further
lock_sys_t::deadlock_check(): Assume that only lock_sys.wait_mutex is being held by the caller. lock_sys_t::rd_lock_try(): New function. lock_sys_t::cancel(trx_t*): Kill an active transaction that may be holding a lock. lock_sys_t::cancel(trx_t*, lock_t*): Cancel a waiting lock request. lock_trx_handle_wait(): Avoid acquiring mutexes in some cases, and in never acquire lock_sys.latch in exclusive mode. This function is only invoked in a semi-consistent read (locking a clustered index record only if it matches the search condition). Normally, lock_wait() will take care of lock waits. lock_wait(): Invoke the new function lock_sys_t::cancel() at the end, to avoid acquiring exclusive lock_sys.latch. lock_rec_other_trx_holds_expl(): Use LockGuard instead of LockMutexGuard. lock_release_autoinc_locks(): Explicitly acquire table->lock_mutex, in case only a shared lock_sys.latch is being held. Deadlock::report() will still hold exclusive lock_sys.latch while invoking lock_cancel_waiting_and_release(). lock_cancel_waiting_and_release(): Acquire trx->mutex in this function, instead of expecting the caller to do so. lock_unlock_table_autoinc(): Only acquire shared lock_sys.latch. lock_table_has_locks(): Do not acquire lock_sys.latch at all. Deadlock::check_and_resolve(): Only acquire shared lock_sys.latchm for invoking lock_sys_t::cancel(trx, wait_lock). innobase_query_caching_table_check_low(), row_drop_tables_for_mysql_in_background(): Do not acquire lock_sys.latch.
1 parent ebb2db5 commit 8d16da1

File tree

4 files changed

+212
-144
lines changed

4 files changed

+212
-144
lines changed

storage/innobase/handler/ha_innodb.cc

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,8 +2688,7 @@ the query cache.
26882688
@param[in] trx transaction object
26892689
@return whether the storing or retrieving from the query cache is permitted */
26902690
static bool innobase_query_caching_table_check_low(
2691-
const dict_table_t* table,
2692-
trx_t* trx)
2691+
dict_table_t* table, trx_t* trx)
26932692
{
26942693
/* The following conditions will decide the query cache
26952694
retrieval or storing into:
@@ -2714,8 +2713,10 @@ static bool innobase_query_caching_table_check_low(
27142713
return false;
27152714
}
27162715

2717-
LockMutexGuard g{SRW_LOCK_CALL};
2718-
return UT_LIST_GET_LEN(table->locks) == 0;
2716+
table->lock_mutex_lock();
2717+
auto len= UT_LIST_GET_LEN(table->locks);
2718+
table->lock_mutex_unlock();
2719+
return len == 0;
27192720
}
27202721

27212722
/** Checks if MySQL at the moment is allowed for this table to retrieve a
@@ -4483,21 +4484,7 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
44834484
DBUG_VOID_RETURN;
44844485
#endif /* WITH_WSREP */
44854486
if (trx->lock.wait_lock)
4486-
{
4487-
{
4488-
LockMutexGuard g{SRW_LOCK_CALL};
4489-
mysql_mutex_lock(&lock_sys.wait_mutex);
4490-
if (lock_t *lock= trx->lock.wait_lock)
4491-
{
4492-
trx->mutex_lock();
4493-
trx->error_state= DB_INTERRUPTED;
4494-
lock_cancel_waiting_and_release(lock);
4495-
trx->mutex_unlock();
4496-
}
4497-
lock_sys.deadlock_check(true);
4498-
}
4499-
mysql_mutex_unlock(&lock_sys.wait_mutex);
4500-
}
4487+
lock_sys_t::cancel(trx);
45014488
}
45024489

45034490
DBUG_VOID_RETURN;

storage/innobase/include/lock0lock.h

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -504,15 +504,9 @@ lock_rec_get_index(
504504
/*===============*/
505505
const lock_t* lock); /*!< in: lock */
506506

507-
/*******************************************************************//**
508-
Check if there are any locks (table or rec) against table.
509-
@return TRUE if locks exist */
510-
bool
511-
lock_table_has_locks(
512-
/*=================*/
513-
const dict_table_t* table); /*!< in: check if there are any locks
514-
held on records in this table or on the
515-
table itself */
507+
/** Check if there are any locks on a table.
508+
@return true if table has either table or record locks. */
509+
bool lock_table_has_locks(dict_table_t *table);
516510

517511
/** Wait for a lock to be released.
518512
@retval DB_DEADLOCK if this transaction was chosen as the deadlock victim
@@ -528,15 +522,15 @@ void
528522
lock_unlock_table_autoinc(
529523
/*======================*/
530524
trx_t* trx); /*!< in/out: transaction */
531-
/*********************************************************************//**
532-
Check whether the transaction has already been rolled back because it
533-
was selected as a deadlock victim, or if it has to wait then cancel
534-
the wait lock.
535-
@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
536-
dberr_t
537-
lock_trx_handle_wait(
538-
/*=================*/
539-
trx_t* trx); /*!< in/out: trx lock state */
525+
526+
/** Handle a pending lock wait (DB_LOCK_WAIT) in a semi-consistent read
527+
while holding a clustered index leaf page latch.
528+
@param trx transaction that is or was waiting for a lock
529+
@retval DB_SUCCESS if the lock was granted
530+
@retval DB_DEADLOCK if the transaction must be aborted due to a deadlock
531+
@retval DB_LOCK_WAIT if a lock wait would be necessary; the pending
532+
lock request was released */
533+
dberr_t lock_trx_handle_wait(trx_t *trx);
540534

541535
/*********************************************************************//**
542536
Checks that a transaction id is sensible, i.e., not in the future.
@@ -775,6 +769,16 @@ class lock_sys_t
775769
std::memory_order_relaxed));
776770
return true;
777771
}
772+
/** Try to acquire shared lock_sys.latch
773+
@return whether the latch was acquired */
774+
bool rd_lock_try()
775+
{
776+
ut_ad(!is_writer());
777+
if (!latch.rd_lock_try()) return false;
778+
ut_ad(!writer.load(std::memory_order_relaxed));
779+
ut_d(readers.fetch_add(1, std::memory_order_relaxed));
780+
return true;
781+
}
778782

779783
/** Assert that wr_lock() has been invoked by this thread */
780784
void assert_locked() const { ut_ad(is_writer()); }
@@ -816,10 +820,15 @@ class lock_sys_t
816820
void close();
817821

818822

819-
/** Check for deadlocks
820-
@param locked lock_sys.is_writer() */
821-
static void deadlock_check(bool locked);
823+
/** Check for deadlocks while holding only lock_sys.wait_mutex. */
824+
void deadlock_check();
822825

826+
/** Cancel a waiting lock request.
827+
@param lock waiting lock request
828+
@param trx active transaction */
829+
static void cancel(trx_t *trx, lock_t *lock);
830+
/** Cancel a waiting lock request (if any) when killing a transaction */
831+
static void cancel(trx_t *trx);
823832

824833
/** Note that a record lock wait started */
825834
inline void wait_start();
@@ -1034,9 +1043,6 @@ lock_rtr_move_rec_list(
10341043
moved */
10351044
ulint num_move); /*!< in: num of rec to move */
10361045

1037-
/** Cancel a waiting lock request and release possibly waiting transactions */
1038-
void lock_cancel_waiting_and_release(lock_t *lock);
1039-
10401046
#include "lock0lock.ic"
10411047

10421048
#endif

0 commit comments

Comments
 (0)