summaryrefslogtreecommitdiff
path: root/src/mongo/db/concurrency/lock_state.cpp
diff options
context:
space:
mode:
authorGregory Noma <gregory.noma@gmail.com>2023-03-23 13:16:20 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-03-23 14:24:04 +0000
commit642d0a1318833017fe865e8c3b4216ae48a00991 (patch)
tree08dd1ab199de6c98afd64afa119f88feaa2397df /src/mongo/db/concurrency/lock_state.cpp
parentbc98db16ed770bd20e2dafee726703993a5c8792 (diff)
downloadmongo-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.cpp34
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 '"