diff options
Diffstat (limited to 'src/mongo/db/operation_context.cpp')
-rw-r--r-- | src/mongo/db/operation_context.cpp | 70 |
1 files changed, 19 insertions, 51 deletions
diff --git a/src/mongo/db/operation_context.cpp b/src/mongo/db/operation_context.cpp index 94a5ea312d2..873972a8c30 100644 --- a/src/mongo/db/operation_context.cpp +++ b/src/mongo/db/operation_context.cpp @@ -88,7 +88,9 @@ void OperationContext::setDeadlineAndMaxTime(Date_t when, ErrorCodes::Error timeoutError) { invariant(!getClient()->isInDirectClient()); invariant(ErrorCodes::isExceededTimeLimitError(timeoutError)); - uassert(40120, "Illegal attempt to change operation deadline", !hasDeadline()); + uassert(40120, + "Illegal attempt to change operation deadline", + _hasArtificialDeadline || !hasDeadline()); _deadline = when; _maxTime = maxTime; _timeoutError = timeoutError; @@ -165,10 +167,6 @@ Microseconds OperationContext::getRemainingMaxTimeMicros() const { return _maxTime - getElapsedTime(); } -void OperationContext::checkForInterrupt() { - uassertStatusOK(checkForInterruptNoAssert()); -} - namespace { // Helper function for checkForInterrupt fail point. Decides whether the operation currently @@ -190,7 +188,7 @@ bool opShouldFail(Client* client, const BSONObj& failPointInfo) { } // namespace -Status OperationContext::checkForInterruptNoAssert() { +Status OperationContext::checkForInterruptNoAssert() noexcept { // TODO: Remove the MONGO_likely(getClient()) once all operation contexts are constructed with // clients. if (MONGO_likely(getClient() && getServiceContext()) && @@ -199,10 +197,16 @@ Status OperationContext::checkForInterruptNoAssert() { } if (hasDeadlineExpired()) { - markKilled(_timeoutError); + if (!_hasArtificialDeadline) { + markKilled(_timeoutError); + } return Status(_timeoutError, "operation exceeded time limit"); } + if (_ignoreInterrupts) { + return Status::OK(); + } + MONGO_FAIL_POINT_BLOCK(checkForInterruptFail, scopedFailPoint) { if (opShouldFail(getClient(), scopedFailPoint.getData())) { log() << "set pending kill on op " << getOpID() << ", for checkForInterruptFail"; @@ -218,41 +222,6 @@ Status OperationContext::checkForInterruptNoAssert() { return Status::OK(); } -void OperationContext::sleepUntil(Date_t deadline) { - stdx::mutex m; - stdx::condition_variable cv; - stdx::unique_lock<stdx::mutex> lk(m); - invariant(!waitForConditionOrInterruptUntil(cv, lk, deadline, [] { return false; })); -} - -void OperationContext::sleepFor(Milliseconds duration) { - stdx::mutex m; - stdx::condition_variable cv; - stdx::unique_lock<stdx::mutex> lk(m); - invariant(!waitForConditionOrInterruptFor(cv, lk, duration, [] { return false; })); -} - -void OperationContext::waitForConditionOrInterrupt(stdx::condition_variable& cv, - stdx::unique_lock<stdx::mutex>& m) { - uassertStatusOK(waitForConditionOrInterruptNoAssert(cv, m)); -} - -Status OperationContext::waitForConditionOrInterruptNoAssert( - stdx::condition_variable& cv, stdx::unique_lock<stdx::mutex>& m) noexcept { - auto status = waitForConditionOrInterruptNoAssertUntil(cv, m, Date_t::max()); - if (!status.isOK()) { - return status.getStatus(); - } - invariant(status.getValue() == stdx::cv_status::no_timeout); - return status.getStatus(); -} - -stdx::cv_status OperationContext::waitForConditionOrInterruptUntil( - stdx::condition_variable& cv, stdx::unique_lock<stdx::mutex>& m, Date_t deadline) { - - return uassertStatusOK(waitForConditionOrInterruptNoAssertUntil(cv, m, deadline)); -} - // Theory of operation for waitForConditionOrInterruptNoAssertUntil and markKilled: // // An operation indicates to potential killers that it is waiting on a condition variable by setting @@ -312,14 +281,15 @@ StatusWith<stdx::cv_status> OperationContext::waitForConditionOrInterruptNoAsser const auto waitStatus = [&] { if (Date_t::max() == deadline) { - cv.wait(m); + Waitable::wait(_baton.get(), getServiceContext()->getPreciseClockSource(), cv, m); return stdx::cv_status::no_timeout; } - return getServiceContext()->getPreciseClockSource()->waitForConditionUntil(cv, m, deadline); + return getServiceContext()->getPreciseClockSource()->waitForConditionUntil( + cv, m, deadline, _baton.get()); }(); // Continue waiting on cv until no other thread is attempting to kill this one. - cv.wait(m, [this] { + Waitable::wait(_baton.get(), getServiceContext()->getPreciseClockSource(), cv, m, [this] { stdx::lock_guard<Client> clientLock(*getClient()); if (0 == _numKillers) { _waitMutex = nullptr; @@ -338,9 +308,12 @@ StatusWith<stdx::cv_status> OperationContext::waitForConditionOrInterruptNoAsser // is slightly ahead of the FastClock used in checkForInterrupt. In this case, // we treat the operation as though it has exceeded its time limit, just as if the // FastClock and system clock had agreed. - markKilled(_timeoutError); + if (!_hasArtificialDeadline) { + markKilled(_timeoutError); + } return Status(_timeoutError, "operation exceeded time limit"); } + return waitStatus; } @@ -361,11 +334,6 @@ void OperationContext::markKilled(ErrorCodes::Error killCode) { invariant(_waitCV); _waitCV->notify_all(); } - - // If we have a baton, we need to wake it up. The baton itself will check for interruption - if (_baton) { - _baton->schedule([] {}); - } } void OperationContext::setLogicalSessionId(LogicalSessionId lsid) { |