summaryrefslogtreecommitdiff
path: root/src/mongo/db/concurrency/lock_state.cpp
diff options
context:
space:
mode:
authorMatthew Russotto <matthew.russotto@10gen.com>2018-08-07 13:08:06 -0400
committerMatthew Russotto <matthew.russotto@10gen.com>2018-08-08 15:30:29 -0400
commit210bb5d91cb3c77bb3ed169114f8b85cd1062fb3 (patch)
treedfdc9abae187ae5e653f5d01390a0d8b4f04e16b /src/mongo/db/concurrency/lock_state.cpp
parenta014dce43e6f55fd6611a865902e46b34953ad72 (diff)
downloadmongo-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.cpp22
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()) {