diff options
author | Randolph Tan <randolph@10gen.com> | 2017-07-26 16:31:59 -0400 |
---|---|---|
committer | Randolph Tan <randolph@10gen.com> | 2017-07-28 17:04:04 -0400 |
commit | 9abf0ffe9f50d069078b5cb708cc8aaf518f5405 (patch) | |
tree | 20fef3e9f3c4d6db71ad848599f17f4a72c85c4a /src | |
parent | 356a36dea183db5afedb932ed4c086f17c4173d0 (diff) | |
download | mongo-9abf0ffe9f50d069078b5cb708cc8aaf518f5405.tar.gz |
SERVER-30318 Allow multiple instances of OperationContextSession per OperationContext
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/session_catalog.cpp | 45 | ||||
-rw-r--r-- | src/mongo/db/session_catalog.h | 4 | ||||
-rw-r--r-- | src/mongo/db/session_catalog_test.cpp | 22 |
3 files changed, 60 insertions, 11 deletions
diff --git a/src/mongo/db/session_catalog.cpp b/src/mongo/db/session_catalog.cpp index e10c643ce11..e14f875ff9e 100644 --- a/src/mongo/db/session_catalog.cpp +++ b/src/mongo/db/session_catalog.cpp @@ -45,11 +45,22 @@ namespace mongo { namespace { +struct CheckedOutSession { + CheckedOutSession(ScopedSession&& session) : scopedSession(std::move(session)) {} + + ScopedSession scopedSession; + + // This numbers gets incremented every time a request tries to check out this session + // including the cases when it was already checked out. Level of 0 means that it's + // available or is completely released. + int checkOutNestingLevel = 0; +}; + const auto sessionTransactionTableDecoration = ServiceContext::declareDecoration<boost::optional<SessionCatalog>>(); const auto operationSessionDecoration = - OperationContext::declareDecoration<boost::optional<ScopedSession>>(); + OperationContext::declareDecoration<boost::optional<CheckedOutSession>>(); } // namespace @@ -158,25 +169,39 @@ OperationContextSession::OperationContextSession(OperationContext* opCtx) : _opC return; } - auto sessionTransactionTable = SessionCatalog::get(opCtx); + auto& checkedOutSession = operationSessionDecoration(opCtx); + if (!checkedOutSession) { + auto sessionTransactionTable = SessionCatalog::get(opCtx); + checkedOutSession.emplace(sessionTransactionTable->checkOutSession(opCtx)); + } + + auto session = checkedOutSession->scopedSession.get(); + invariant(opCtx->getLogicalSessionId() == session->getSessionId()); + checkedOutSession->checkOutNestingLevel++; - auto& operationSession = operationSessionDecoration(opCtx); - operationSession.emplace(sessionTransactionTable->checkOutSession(opCtx)); + if (checkedOutSession->checkOutNestingLevel > 1) { + return; + } if (opCtx->getTxnNumber()) { - operationSession->get()->begin(opCtx, opCtx->getTxnNumber().get()); + checkedOutSession->scopedSession->begin(opCtx, opCtx->getTxnNumber().get()); } } OperationContextSession::~OperationContextSession() { - auto& operationSession = operationSessionDecoration(_opCtx); - operationSession.reset(); + auto& checkedOutSession = operationSessionDecoration(_opCtx); + if (checkedOutSession) { + invariant(checkedOutSession->checkOutNestingLevel > 0); + if (--checkedOutSession->checkOutNestingLevel == 0) { + checkedOutSession.reset(); + } + } } Session* OperationContextSession::get(OperationContext* opCtx) { - auto& operationSession = operationSessionDecoration(opCtx); - if (operationSession) { - return operationSession->get(); + auto& checkedOutSession = operationSessionDecoration(opCtx); + if (checkedOutSession) { + return checkedOutSession->scopedSession.get(); } return nullptr; diff --git a/src/mongo/db/session_catalog.h b/src/mongo/db/session_catalog.h index 5d2ab0c17e1..a504d24bf6c 100644 --- a/src/mongo/db/session_catalog.h +++ b/src/mongo/db/session_catalog.h @@ -151,7 +151,9 @@ class ScopedSession { public: ScopedSession(OperationContext* opCtx, std::shared_ptr<SessionCatalog::SessionRuntimeInfo> sri) - : _opCtx(opCtx), _sri(std::move(sri)) {} + : _opCtx(opCtx), _sri(std::move(sri)) { + invariant(_sri); + } ScopedSession(ScopedSession&&) = default; diff --git a/src/mongo/db/session_catalog_test.cpp b/src/mongo/db/session_catalog_test.cpp index 0d5f4e9122a..0250850b8af 100644 --- a/src/mongo/db/session_catalog_test.cpp +++ b/src/mongo/db/session_catalog_test.cpp @@ -62,5 +62,27 @@ TEST_F(SessionCatalogTest, CheckoutAndReleaseSession) { ASSERT_EQ(*opCtx->getLogicalSessionId(), scopedSession->getSessionId()); } +TEST_F(SessionCatalogTest, NestedOperationContextSession) { + auto opCtx = Client::getCurrent()->makeOperationContext(); + opCtx->setLogicalSessionId(LogicalSessionId()); + + { + OperationContextSession outerScopedSession(opCtx.get()); + + { + OperationContextSession innerScopedSession(opCtx.get()); + auto session = OperationContextSession::get(opCtx.get()); + ASSERT_TRUE(nullptr != session); + ASSERT_EQ(*opCtx->getLogicalSessionId(), session->getSessionId()); + } + + auto session = OperationContextSession::get(opCtx.get()); + ASSERT_TRUE(nullptr != session); + ASSERT_EQ(*opCtx->getLogicalSessionId(), session->getSessionId()); + } + + ASSERT_TRUE(nullptr == OperationContextSession::get(opCtx.get())); +} + } // namespace } // namespace mongo |