diff options
Diffstat (limited to 'src/mongo/db/operation_context.cpp')
| -rw-r--r-- | src/mongo/db/operation_context.cpp | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/src/mongo/db/operation_context.cpp b/src/mongo/db/operation_context.cpp index 649ad363b0c..66fbfad5b6b 100644 --- a/src/mongo/db/operation_context.cpp +++ b/src/mongo/db/operation_context.cpp @@ -318,27 +318,36 @@ StatusWith<stdx::cv_status> OperationContext::waitForConditionOrInterruptNoAsser deadline = std::min(deadline, getDeadline()); } - const auto waitStatus = [&] { - if (Date_t::max() == deadline) { - Waitable::wait(_baton.get(), getServiceContext()->getPreciseClockSource(), cv, m); - return stdx::cv_status::no_timeout; - } - return getServiceContext()->getPreciseClockSource()->waitForConditionUntil( - cv, m, deadline, _baton.get()); - }(); - - if (opHasDeadline && waitStatus == stdx::cv_status::timeout && deadline == getDeadline()) { - // It's possible that the system clock used in stdx::condition_variable::wait_until - // 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. - if (!_hasArtificialDeadline) { - interruptible_detail::doWithoutLock(m, [&] { markKilled(_timeoutError); }); + try { + const auto waitStatus = [&] { + if (Date_t::max() == deadline) { + Waitable::wait(_baton.get(), getServiceContext()->getPreciseClockSource(), cv, m); + return stdx::cv_status::no_timeout; + } + return getServiceContext()->getPreciseClockSource()->waitForConditionUntil( + cv, m, deadline, _baton.get()); + }(); + + if (opHasDeadline && waitStatus == stdx::cv_status::timeout && deadline == getDeadline()) { + // It's possible that the system clock used in stdx::condition_variable::wait_until + // 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. + if (!_hasArtificialDeadline) { + interruptible_detail::doWithoutLock(m, [&] { markKilled(_timeoutError); }); + } + return Status(_timeoutError, "operation exceeded time limit"); } - return Status(_timeoutError, "operation exceeded time limit"); - } - return waitStatus; + return waitStatus; + } catch (const ExceptionFor<ErrorCodes::DurationOverflow>& ex) { + // Inside waitForConditionUntil() is a conversion from deadline's Date_t type to the system + // clock's time_point type. If the time_point's compiler-dependent resolution is higher + // than Date_t's milliseconds, it's possible for the conversion from Date_t to time_point + // to overflow and trigger an exception. We catch that here to maintain the noexcept + // contract. + return ex.toStatus(); + } } void OperationContext::markKilled(ErrorCodes::Error killCode) { |
