summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp22
-rw-r--r--src/mongo/db/session.cpp6
-rw-r--r--src/mongo/db/session.h4
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();