diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2023-03-23 13:16:20 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-03-23 14:24:04 +0000 |
commit | 642d0a1318833017fe865e8c3b4216ae48a00991 (patch) | |
tree | 08dd1ab199de6c98afd64afa119f88feaa2397df /src/mongo/db/concurrency/lock_state.cpp | |
parent | bc98db16ed770bd20e2dafee726703993a5c8792 (diff) | |
download | mongo-642d0a1318833017fe865e8c3b4216ae48a00991.tar.gz |
SERVER-74959 Ignore max lock timeout for ticket acquisition
Diffstat (limited to 'src/mongo/db/concurrency/lock_state.cpp')
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index aba538ee670..d2e4a513182 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -354,15 +354,29 @@ void LockerImpl::reacquireTicket(OperationContext* opCtx) { if (clientState != kInactive) return; - if (!_maxLockTimeout || _uninterruptibleLocksRequested) { - invariant(_acquireTicket(opCtx, _modeForTicket, Date_t::max())); - } else { - uassert(ErrorCodes::LockTimeout, - str::stream() << "Unable to acquire ticket with mode '" << _modeForTicket - << "' within a max lock request timeout of '" << *_maxLockTimeout - << "' milliseconds.", - _acquireTicket(opCtx, _modeForTicket, Date_t::now() + *_maxLockTimeout)); + if (_acquireTicket(opCtx, _modeForTicket, Date_t::now())) { + return; } + + do { + for (auto it = _requests.begin(); it; it.next()) { + invariant(it->mode == LockMode::MODE_IS || it->mode == LockMode::MODE_IX); + opCtx->checkForInterrupt(); + + // If we've reached this point then that means we tried to acquire a ticket but were + // unsuccessful, implying that tickets are currently exhausted. Additionally, since + // we're holding an IS or IX lock for this resource, any pending requests for the same + // resource must be S or X and will not be able to be granted. Thus, since such a + // pending lock request may also be holding a ticket, if there are any present we fail + // this ticket reacquisition in order to avoid a deadlock. + uassert(ErrorCodes::LockTimeout, + fmt::format("Unable to acquire ticket with mode '{}' due to detected lock " + "conflict for resource {}", + _modeForTicket, + it.key().toString()), + !getGlobalLockManager()->hasConflictingRequests(it.objAddr())); + } + } while (!_acquireTicket(opCtx, _modeForTicket, Date_t::now() + Milliseconds{100})); } bool LockerImpl::_acquireTicket(OperationContext* opCtx, LockMode mode, Date_t deadline) { @@ -406,12 +420,10 @@ void LockerImpl::lockGlobal(OperationContext* opCtx, LockMode mode, Date_t deadl dassert(isLocked() == (_modeForTicket != MODE_NONE)); if (_modeForTicket == MODE_NONE) { if (_uninterruptibleLocksRequested) { - // Ignore deadline and _maxLockTimeout. + // Ignore deadline. invariant(_acquireTicket(opCtx, mode, Date_t::max())); } else { auto beforeAcquire = Date_t::now(); - deadline = std::min(deadline, - _maxLockTimeout ? beforeAcquire + *_maxLockTimeout : Date_t::max()); uassert(ErrorCodes::LockTimeout, str::stream() << "Unable to acquire ticket with mode '" << mode << "' within a max lock request timeout of '" |