diff options
author | Jason Carey <jcarey@argv.me> | 2019-02-27 13:40:18 -0500 |
---|---|---|
committer | Jason Carey <jcarey@argv.me> | 2019-03-05 10:05:45 -0500 |
commit | 32a067938731d184b271ba3d7f43ca6727e3109c (patch) | |
tree | 759f22c263da841521a1653701a94e4b7c05c8f0 /src/mongo/db/operation_context_test.cpp | |
parent | 602bfb9c52b2274d55492f73eeac8513d9048d10 (diff) | |
download | mongo-32a067938731d184b271ba3d7f43ca6727e3109c.tar.gz |
SERVER-39427 Modify interrupt semantics for opCtx
* rename opCtx->runWithoutInterruption to
runWithoutInterruptionExceptAtGlobalShutdown
* add a opCtx->setIsExecutingShutdown method which makes the op immune
to all forms of interruption, including global shutdown
This clarifies what opCtx->runWithoutInterruption actually did and
offers an escape hatch that turns off interruption at process exit for
the thread doing cleanup.
Diffstat (limited to 'src/mongo/db/operation_context_test.cpp')
-rw-r--r-- | src/mongo/db/operation_context_test.cpp | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/src/mongo/db/operation_context_test.cpp b/src/mongo/db/operation_context_test.cpp index 9c8c40ec63e..8195a57cf26 100644 --- a/src/mongo/db/operation_context_test.cpp +++ b/src/mongo/db/operation_context_test.cpp @@ -210,7 +210,7 @@ TEST(OperationContextTest, IgnoreInterruptsWorks) { ASSERT_THROWS_CODE(opCtx->checkForInterrupt(), DBException, ErrorCodes::BadValue); ASSERT_EQUALS(opCtx->getKillStatus(), ErrorCodes::BadValue); - opCtx->runWithoutInterruption([&] { + opCtx->runWithoutInterruptionExceptAtGlobalShutdown([&] { ASSERT_OK(opCtx->checkForInterruptNoAssert()); ASSERT_OK(opCtx->getKillStatus()); }); @@ -218,6 +218,33 @@ TEST(OperationContextTest, IgnoreInterruptsWorks) { ASSERT_THROWS_CODE(opCtx->checkForInterrupt(), DBException, ErrorCodes::BadValue); ASSERT_EQUALS(opCtx->getKillStatus(), ErrorCodes::BadValue); + + serviceCtx->setKillAllOperations(); + + opCtx->runWithoutInterruptionExceptAtGlobalShutdown([&] { + ASSERT_THROWS_CODE( + opCtx->checkForInterrupt(), DBException, ErrorCodes::InterruptedAtShutdown); + }); +} + +TEST(OperationContextTest, setIsExecutingShutdownWorks) { + auto serviceCtx = ServiceContext::make(); + auto client = serviceCtx->makeClient("OperationContextTest"); + auto opCtx = client->makeOperationContext(); + + opCtx->markKilled(ErrorCodes::BadValue); + ASSERT_THROWS_CODE(opCtx->checkForInterrupt(), DBException, ErrorCodes::BadValue); + ASSERT_EQUALS(opCtx->getKillStatus(), ErrorCodes::BadValue); + + opCtx->setIsExecutingShutdown(); + + ASSERT_OK(opCtx->checkForInterruptNoAssert()); + ASSERT_OK(opCtx->getKillStatus()); + + serviceCtx->setKillAllOperations(); + + ASSERT_OK(opCtx->checkForInterruptNoAssert()); + ASSERT_OK(opCtx->getKillStatus()); } class OperationDeadlineTests : public unittest::Test { @@ -471,7 +498,7 @@ TEST_F(OperationDeadlineTests, DeadlineAfterIgnoreInterruptsReopens) { mockClock->now() + Milliseconds(500), ErrorCodes::ExceededTimeLimit, [&] { ASSERT_OK(opCtx->checkForInterruptNoAssert()); - opCtx->runWithoutInterruption([&] { + opCtx->runWithoutInterruptionExceptAtGlobalShutdown([&] { try { opCtx->runWithDeadline( mockClock->now() + Seconds(1), ErrorCodes::ExceededTimeLimit, [&] { @@ -500,12 +527,52 @@ TEST_F(OperationDeadlineTests, DeadlineAfterIgnoreInterruptsReopens) { ASSERT(reachedC); } +TEST_F(OperationDeadlineTests, DeadlineAfterSetIsExecutingShutdownReopens) { + auto opCtx = client->makeOperationContext(); + + bool reachedA = false; + bool reachedB = false; + bool reachedC = false; + + try { + opCtx->runWithDeadline( + mockClock->now() + Milliseconds(500), ErrorCodes::ExceededTimeLimit, [&] { + ASSERT_OK(opCtx->checkForInterruptNoAssert()); + + opCtx->setIsExecutingShutdown(); + try { + opCtx->runWithDeadline( + mockClock->now() + Seconds(1), ErrorCodes::ExceededTimeLimit, [&] { + ASSERT_OK(opCtx->checkForInterruptNoAssert()); + ASSERT_OK(opCtx->getKillStatus()); + mockClock->advance(Milliseconds(750)); + ASSERT_OK(opCtx->checkForInterruptNoAssert()); + mockClock->advance(Milliseconds(500)); + reachedA = true; + opCtx->checkForInterrupt(); + }); + } catch (const ExceptionFor<ErrorCodes::ExceededTimeLimit>&) { + opCtx->checkForInterrupt(); + reachedB = true; + } + + opCtx->checkForInterrupt(); + }); + } catch (const ExceptionFor<ErrorCodes::ExceededTimeLimit>&) { + reachedC = true; + } + + ASSERT(reachedA); + ASSERT(reachedB); + ASSERT_FALSE(reachedC); +} + TEST_F(OperationDeadlineTests, DeadlineAfterRunWithoutInterruptSeesViolatedMaxMS) { auto opCtx = client->makeOperationContext(); opCtx->setDeadlineByDate(mockClock->now() + Milliseconds(100), ErrorCodes::MaxTimeMSExpired); - ASSERT_THROWS_CODE(opCtx->runWithoutInterruption([&] { + ASSERT_THROWS_CODE(opCtx->runWithoutInterruptionExceptAtGlobalShutdown([&] { opCtx->runWithDeadline( mockClock->now() + Milliseconds(200), ErrorCodes::ExceededTimeLimit, [&] { mockClock->advance(Milliseconds(300)); @@ -521,7 +588,7 @@ TEST_F(OperationDeadlineTests, DeadlineAfterRunWithoutInterruptDoesntSeeUnviolat opCtx->setDeadlineByDate(mockClock->now() + Milliseconds(200), ErrorCodes::MaxTimeMSExpired); - ASSERT_THROWS_CODE(opCtx->runWithoutInterruption([&] { + ASSERT_THROWS_CODE(opCtx->runWithoutInterruptionExceptAtGlobalShutdown([&] { opCtx->runWithDeadline( mockClock->now() + Milliseconds(100), ErrorCodes::ExceededTimeLimit, [&] { mockClock->advance(Milliseconds(150)); |