diff options
author | Matthew Russotto <matthew.russotto@10gen.com> | 2018-08-07 13:08:06 -0400 |
---|---|---|
committer | Matthew Russotto <matthew.russotto@10gen.com> | 2018-08-08 15:30:29 -0400 |
commit | 210bb5d91cb3c77bb3ed169114f8b85cd1062fb3 (patch) | |
tree | dfdc9abae187ae5e653f5d01390a0d8b4f04e16b /src/mongo/db/concurrency/lock_state.cpp | |
parent | a014dce43e6f55fd6611a865902e46b34953ad72 (diff) | |
download | mongo-210bb5d91cb3c77bb3ed169114f8b85cd1062fb3.tar.gz |
SERVER-35770 Running a multi-statement transaction when all WiredTiger write tickets are exhausted may lead to deadlock
Diffstat (limited to 'src/mongo/db/concurrency/lock_state.cpp')
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index 5d649f06996..6198276f0de 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -291,7 +291,25 @@ LockResult LockerImpl::lockGlobal(OperationContext* opCtx, LockMode mode) { void LockerImpl::reacquireTicket(OperationContext* opCtx) { invariant(_modeForTicket != MODE_NONE); + auto clientState = _clientState.load(); + const bool reader = isSharedLockMode(_modeForTicket); + + // Ensure that either we don't have a ticket, or the current ticket mode matches the lock mode. + invariant(clientState == kInactive || (clientState == kActiveReader && reader) || + (clientState == kActiveWriter && !reader)); + + // If we already have a ticket, there's nothing to do. + if (clientState != kInactive) + return; + auto acquireTicketResult = _acquireTicket(opCtx, _modeForTicket, Date_t::max()); + uassert(ErrorCodes::LockTimeout, + str::stream() << "Unable to acquire ticket with mode '" << _modeForTicket + << "' within a max lock request timeout of '" + << _maxLockTimeout.get() + << "' milliseconds.", + acquireTicketResult == LOCK_OK || !_maxLockTimeout); + // If no deadline is specified we should always get a ticket. invariant(acquireTicketResult == LOCK_OK); } @@ -301,6 +319,10 @@ LockResult LockerImpl::_acquireTicket(OperationContext* opCtx, LockMode mode, Da if (holder) { _clientState.store(reader ? kQueuedReader : kQueuedWriter); + if (_maxLockTimeout && !_uninterruptibleLocksRequested) { + deadline = std::min(deadline, Date_t::now() + _maxLockTimeout.get()); + } + // If the ticket wait is interrupted, restore the state of the client. auto restoreStateOnErrorGuard = MakeGuard([&] { _clientState.store(kInactive); }); if (deadline == Date_t::max()) { |