LockResult LockerImpl<IsForMMAPV1>::_lockGlobalBegin(LockMode mode, Milliseconds timeout) { dassert(isLocked() == (_modeForTicket != MODE_NONE)); if (_modeForTicket == MODE_NONE) { const bool reader = isSharedLockMode(mode); auto holder = ticketHolders[mode]; if (holder) { _clientState.store(reader ? kQueuedReader : kQueuedWriter); if (timeout == Milliseconds::max()) { holder->waitForTicket(); } else if (!holder->waitForTicketUntil(Date_t::now() + timeout)) { _clientState.store(kInactive); return LOCK_TIMEOUT; } } _clientState.store(reader ? kActiveReader : kActiveWriter); _modeForTicket = mode; } const LockResult result = lockBegin(resourceIdGlobal, mode); if (result == LOCK_OK) return LOCK_OK; // Currently, deadlock detection does not happen inline with lock acquisition so the only // unsuccessful result that the lock manager would return is LOCK_WAITING. invariant(result == LOCK_WAITING); return result; }
Status TicketHolder::resize(int newSize) { stdx::lock_guard<stdx::mutex> lk(_resizeMutex); if (newSize < 5) return Status(ErrorCodes::BadValue, str::stream() << "Minimum value for semaphore is 5; given " << newSize); if (newSize > SEM_VALUE_MAX) return Status(ErrorCodes::BadValue, str::stream() << "Maximum value for semaphore is " << SEM_VALUE_MAX << "; given " << newSize); while (_outof.load() < newSize) { release(); _outof.fetchAndAdd(1); } while (_outof.load() > newSize) { waitForTicket(); _outof.subtractAndFetch(1); } invariant(_outof.load() == newSize); return Status::OK(); }
LockResult LockerImpl<IsForMMAPV1>::_acquireTicket(OperationContext* opCtx, LockMode mode, Date_t deadline) { const bool reader = isSharedLockMode(mode); auto holder = shouldAcquireTicket() ? ticketHolders[mode] : nullptr; if (holder) { _clientState.store(reader ? kQueuedReader : kQueuedWriter); // If the ticket wait is interrupted, restore the state of the client. auto restoreStateOnErrorGuard = MakeGuard([&] { _clientState.store(kInactive); }); if (deadline == Date_t::max()) { holder->waitForTicket(opCtx); } else if (!holder->waitForTicketUntil(opCtx, deadline)) { return LOCK_TIMEOUT; } restoreStateOnErrorGuard.Dismiss(); } _clientState.store(reader ? kActiveReader : kActiveWriter); return LOCK_OK; }
LockResult LockerImpl::_acquireTicket(OperationContext* opCtx, LockMode mode, Date_t deadline) { const bool reader = isSharedLockMode(mode); auto holder = shouldAcquireTicket() ? ticketHolders[mode] : nullptr; 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); }); OperationContext* interruptible = _uninterruptibleLocksRequested ? nullptr : opCtx; if (deadline == Date_t::max()) { holder->waitForTicket(interruptible); } else if (!holder->waitForTicketUntil(interruptible, deadline)) { return LOCK_TIMEOUT; } restoreStateOnErrorGuard.Dismiss(); } _clientState.store(reader ? kActiveReader : kActiveWriter); return LOCK_OK; }