MDEV-20612: Enable concurrent lock_release()
lock_release_try(): Try to release locks while only holding shared lock_sys.latch. lock_release(): If 5 attempts of lock_release_try() fail, proceed to acquire exclusive lock_sys.latch.
This commit is contained in:
parent
b08448de64
commit
26d6224dd6
@ -1972,6 +1972,14 @@ struct dict_table_t {
|
|||||||
lock_mutex.wr_lock();
|
lock_mutex.wr_lock();
|
||||||
ut_ad(!lock_mutex_owner.exchange(os_thread_get_curr_id()));
|
ut_ad(!lock_mutex_owner.exchange(os_thread_get_curr_id()));
|
||||||
}
|
}
|
||||||
|
/** Try to acquire lock_mutex */
|
||||||
|
bool lock_mutex_trylock()
|
||||||
|
{
|
||||||
|
ut_ad(!lock_mutex_is_owner());
|
||||||
|
bool acquired= lock_mutex.wr_lock_try();
|
||||||
|
ut_ad(!acquired || !lock_mutex_owner.exchange(os_thread_get_curr_id()));
|
||||||
|
return acquired;
|
||||||
|
}
|
||||||
/** Release lock_mutex */
|
/** Release lock_mutex */
|
||||||
void lock_mutex_unlock()
|
void lock_mutex_unlock()
|
||||||
{
|
{
|
||||||
|
@ -581,8 +581,10 @@ class lock_sys_t
|
|||||||
{
|
{
|
||||||
/** Wait for an exclusive lock */
|
/** Wait for an exclusive lock */
|
||||||
void wait();
|
void wait();
|
||||||
|
/** Try to acquire a lock */
|
||||||
|
bool try_acquire() { return write_trylock(); }
|
||||||
/** Acquire a lock */
|
/** Acquire a lock */
|
||||||
void acquire() { if (!write_trylock()) wait(); }
|
void acquire() { if (!try_acquire()) wait(); }
|
||||||
/** Release a lock */
|
/** Release a lock */
|
||||||
void release();
|
void release();
|
||||||
#else
|
#else
|
||||||
@ -590,6 +592,8 @@ class lock_sys_t
|
|||||||
private:
|
private:
|
||||||
srw_lock_low lock;
|
srw_lock_low lock;
|
||||||
public:
|
public:
|
||||||
|
/** Try to acquire a lock */
|
||||||
|
bool try_acquire() { return lock.wr_lock_try(); }
|
||||||
/** Acquire a lock */
|
/** Acquire a lock */
|
||||||
void acquire() { lock.wr_lock(); }
|
void acquire() { lock.wr_lock(); }
|
||||||
/** Release a lock */
|
/** Release a lock */
|
||||||
|
@ -3939,12 +3939,10 @@ released:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Release the explicit locks of a committing transaction,
|
/** Release the explicit locks of a committing transaction,
|
||||||
and release possible other transactions waiting because of these locks. */
|
and release possible other transactions waiting because of these locks.
|
||||||
void lock_release(trx_t *trx)
|
@return whether the operation succeeded */
|
||||||
|
static bool lock_release_try(trx_t *trx)
|
||||||
{
|
{
|
||||||
ulint count= 0;
|
|
||||||
|
|
||||||
ut_ad(!trx->mutex_is_owner());
|
|
||||||
/* At this point, trx->lock.trx_locks cannot be modified by other
|
/* At this point, trx->lock.trx_locks cannot be modified by other
|
||||||
threads, because our transaction has been committed.
|
threads, because our transaction has been committed.
|
||||||
See the checks and assertions in lock_rec_create_low() and
|
See the checks and assertions in lock_rec_create_low() and
|
||||||
@ -3956,11 +3954,82 @@ void lock_release(trx_t *trx)
|
|||||||
DBUG_ASSERT(trx->state == TRX_STATE_COMMITTED_IN_MEMORY);
|
DBUG_ASSERT(trx->state == TRX_STATE_COMMITTED_IN_MEMORY);
|
||||||
DBUG_ASSERT(!trx->is_referenced());
|
DBUG_ASSERT(!trx->is_referenced());
|
||||||
|
|
||||||
LockMutexGuard g{SRW_LOCK_CALL};
|
bool all_released= true;
|
||||||
|
restart:
|
||||||
|
ulint count= 1000;
|
||||||
|
lock_sys.rd_lock(SRW_LOCK_CALL);
|
||||||
trx->mutex_lock();
|
trx->mutex_lock();
|
||||||
|
|
||||||
for (lock_t *lock= UT_LIST_GET_LAST(trx->lock.trx_locks); lock;
|
/* Note: Anywhere else, trx->mutex is not held while acquiring
|
||||||
lock= UT_LIST_GET_LAST(trx->lock.trx_locks))
|
a lock table latch, but here we are following the opposite order.
|
||||||
|
To avoid deadlocks, we only try to acquire the lock table latches
|
||||||
|
but not keep waiting for them. */
|
||||||
|
|
||||||
|
for (lock_t *lock= UT_LIST_GET_LAST(trx->lock.trx_locks); lock; )
|
||||||
|
{
|
||||||
|
ut_ad(lock->trx == trx);
|
||||||
|
lock_t *prev= UT_LIST_GET_PREV(trx_locks, lock);
|
||||||
|
if (!lock->is_table())
|
||||||
|
{
|
||||||
|
ut_ad(!lock->index->table->is_temporary());
|
||||||
|
ut_ad(lock->mode() != LOCK_X ||
|
||||||
|
lock->index->table->id >= DICT_HDR_FIRST_ID ||
|
||||||
|
trx->dict_operation);
|
||||||
|
auto &lock_hash= lock_sys.hash_get(lock->type_mode);
|
||||||
|
auto latch= lock_hash.lock_get(lock->un_member.rec_lock.page_id.fold());
|
||||||
|
if (!latch->try_acquire())
|
||||||
|
all_released= false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock_rec_dequeue_from_page(lock, false);
|
||||||
|
latch->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dict_table_t *table= lock->un_member.tab_lock.table;
|
||||||
|
ut_ad(!table->is_temporary());
|
||||||
|
ut_ad(table->id >= DICT_HDR_FIRST_ID ||
|
||||||
|
(lock->mode() != LOCK_IX && lock->mode() != LOCK_X) ||
|
||||||
|
trx->dict_operation);
|
||||||
|
if (!table->lock_mutex_trylock())
|
||||||
|
all_released= false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock_table_dequeue(lock, false);
|
||||||
|
table->lock_mutex_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock= all_released ? UT_LIST_GET_LAST(trx->lock.trx_locks) : prev;
|
||||||
|
if (!--count)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_sys.rd_unlock();
|
||||||
|
trx->mutex_unlock();
|
||||||
|
if (all_released && !count)
|
||||||
|
goto restart;
|
||||||
|
return all_released;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release the explicit locks of a committing transaction,
|
||||||
|
and release possible other transactions waiting because of these locks. */
|
||||||
|
void lock_release(trx_t *trx)
|
||||||
|
{
|
||||||
|
ulint count;
|
||||||
|
|
||||||
|
for (count= 5; count--; )
|
||||||
|
if (lock_release_try(trx))
|
||||||
|
goto released;
|
||||||
|
|
||||||
|
/* Fall back to acquiring lock_sys.latch in exclusive mode */
|
||||||
|
restart:
|
||||||
|
count= 1000;
|
||||||
|
lock_sys.wr_lock(SRW_LOCK_CALL);
|
||||||
|
trx->mutex_lock();
|
||||||
|
|
||||||
|
while (lock_t *lock= UT_LIST_GET_LAST(trx->lock.trx_locks))
|
||||||
{
|
{
|
||||||
ut_ad(lock->trx == trx);
|
ut_ad(lock->trx == trx);
|
||||||
if (!lock->is_table())
|
if (!lock->is_table())
|
||||||
@ -3981,20 +4050,16 @@ void lock_release(trx_t *trx)
|
|||||||
lock_table_dequeue(lock, false);
|
lock_table_dequeue(lock, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 1000)
|
if (!--count)
|
||||||
{
|
break;
|
||||||
/* Release the latch for a while, so that we do not monopolize it */
|
|
||||||
lock_sys.wr_unlock();
|
|
||||||
trx->mutex_unlock();
|
|
||||||
count= 0;
|
|
||||||
lock_sys.wr_lock(SRW_LOCK_CALL);
|
|
||||||
trx->mutex_lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
++count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock_sys.wr_unlock();
|
||||||
trx->mutex_unlock();
|
trx->mutex_unlock();
|
||||||
|
if (!count)
|
||||||
|
goto restart;
|
||||||
|
|
||||||
|
released:
|
||||||
trx->lock.was_chosen_as_deadlock_victim= false;
|
trx->lock.was_chosen_as_deadlock_victim= false;
|
||||||
trx->lock.n_rec_locks= 0;
|
trx->lock.n_rec_locks= 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user