diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/session.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/session.h | 4 |
3 files changed, 29 insertions, 3 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index 33e3d9b1a3e..d3b95d7b589 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -319,7 +319,25 @@ LockResult LockerImpl<IsForMMAPV1>::lockGlobal(OperationContext* opCtx, LockMode template <bool IsForMMAPV1> void LockerImpl<IsForMMAPV1>::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); } @@ -332,6 +350,10 @@ LockResult LockerImpl<IsForMMAPV1>::_acquireTicket(OperationContext* opCtx, 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()) { diff --git a/src/mongo/db/session.cpp b/src/mongo/db/session.cpp index 47bde4c01f3..cf814e8d6d9 100644 --- a/src/mongo/db/session.cpp +++ b/src/mongo/db/session.cpp @@ -654,13 +654,15 @@ void Session::_checkTxnValid(WithLock, TxnNumber txnNumber) const { txnNumber >= _activeTxnNumber); } -Session::TxnResources::TxnResources(OperationContext* opCtx) { +Session::TxnResources::TxnResources(OperationContext* opCtx, bool keepTicket) { stdx::lock_guard<Client> lk(*opCtx->getClient()); _ruState = opCtx->getWriteUnitOfWork()->release(); opCtx->setWriteUnitOfWork(nullptr); _locker = opCtx->swapLockState(stdx::make_unique<DefaultLockerImpl>()); - _locker->releaseTicket(); + if (!keepTicket) { + _locker->releaseTicket(); + } _locker->unsetThreadId(); // This thread must still respect the transaction lock timeout, since it can prevent the diff --git a/src/mongo/db/session.h b/src/mongo/db/session.h index bfa7487d33f..5ca119f1094 100644 --- a/src/mongo/db/session.h +++ b/src/mongo/db/session.h @@ -72,8 +72,10 @@ public: /** * Stashes transaction state from 'opCtx' in the newly constructed TxnResources. * This ephemerally takes the Client lock associated with the opCtx. + * keepTicket: If true, do not release locker's throttling ticket. + * Use only for short-term stashing. */ - TxnResources(OperationContext* opCtx); + TxnResources(OperationContext* opCtx, bool keepTicket = false); ~TxnResources(); |