diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/SConscript | 14 | ||||
-rw-r--r-- | src/mongo/db/initialize_operation_session_info.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/internal_transactions_feature_flag.idl (renamed from src/mongo/s/internal_transactions_feature_flag.idl) | 0 | ||||
-rw-r--r-- | src/mongo/db/logical_session_cache_impl.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/logical_session_cache_test.cpp | 187 | ||||
-rw-r--r-- | src/mongo/db/logical_session_id_helpers.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/logical_session_id_test.cpp | 93 | ||||
-rw-r--r-- | src/mongo/db/session_catalog.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/session_catalog_test.cpp | 24 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 1 |
10 files changed, 330 insertions, 46 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index f6296a79e5c..294d0a376b0 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -642,6 +642,18 @@ env.Library( ) env.Library( + target='internal_transactions_feature_flag', + source=[ + 'internal_transactions_feature_flag.idl', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/idl/feature_flag', + '$BUILD_DIR/mongo/idl/server_parameter', + 'server_options_core', + ] +) + +env.Library( target='session_catalog', source=[ 'session_catalog.cpp', @@ -652,6 +664,7 @@ env.Library( 'logical_session_id_helpers', ], LIBDEPS_PRIVATE=[ + 'internal_transactions_feature_flag', 'service_context', ] ) @@ -1517,6 +1530,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/s/sharding_api_d', + 'internal_transactions_feature_flag', ] ) diff --git a/src/mongo/db/initialize_operation_session_info.cpp b/src/mongo/db/initialize_operation_session_info.cpp index afa0c739b6f..c655b9ae7f7 100644 --- a/src/mongo/db/initialize_operation_session_info.cpp +++ b/src/mongo/db/initialize_operation_session_info.cpp @@ -94,6 +94,12 @@ OperationSessionInfoFromClient initializeOperationSessionInfo(OperationContext* return {}; } + if (getParentSessionId(lsid)) { + uassert(ErrorCodes::InvalidOptions, + "Internal sessions are not supported outside of transactions", + osi.getTxnNumber() && osi.getAutocommit() && !osi.getAutocommit().value()); + } + opCtx->setLogicalSessionId(std::move(lsid)); uassertStatusOK(lsc->vivify(opCtx, opCtx->getLogicalSessionId().get())); } else { diff --git a/src/mongo/s/internal_transactions_feature_flag.idl b/src/mongo/db/internal_transactions_feature_flag.idl index 83fe8b1a644..83fe8b1a644 100644 --- a/src/mongo/s/internal_transactions_feature_flag.idl +++ b/src/mongo/db/internal_transactions_feature_flag.idl diff --git a/src/mongo/db/logical_session_cache_impl.cpp b/src/mongo/db/logical_session_cache_impl.cpp index 349da7906f9..52bee61ed64 100644 --- a/src/mongo/db/logical_session_cache_impl.cpp +++ b/src/mongo/db/logical_session_cache_impl.cpp @@ -33,6 +33,7 @@ #include "mongo/db/logical_session_cache_impl.h" +#include "mongo/db/internal_transactions_feature_flag_gen.h" #include "mongo/db/logical_session_id.h" #include "mongo/db/logical_session_id_helpers.h" #include "mongo/db/operation_context.h" @@ -93,8 +94,17 @@ Status LogicalSessionCacheImpl::startSession(OperationContext* opCtx, } Status LogicalSessionCacheImpl::vivify(OperationContext* opCtx, const LogicalSessionId& lsid) { + auto parentLsid = getParentSessionId(lsid); + if (parentLsid) { + uassert(ErrorCodes::InvalidOptions, + "Internal transactions are not enabled", + feature_flags::gFeatureFlagInternalTransactions.isEnabled( + serverGlobalParams.featureCompatibility)); + } + stdx::lock_guard lg(_mutex); - auto it = _activeSessions.find(lsid); + + auto it = _activeSessions.find(parentLsid ? *parentLsid : lsid); if (it == _activeSessions.end()) return _addToCacheIfNotFull(lg, makeLogicalSessionRecord(opCtx, lsid, _service->now())); @@ -374,6 +384,11 @@ void LogicalSessionCacheImpl::_refresh(Client* client) { } void LogicalSessionCacheImpl::endSessions(const LogicalSessionIdSet& sessions) { + for (const auto& lsid : sessions) { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "Cannot specify a session id with parent session id " << lsid, + !getParentSessionId(lsid)); + } stdx::lock_guard<Latch> lk(_mutex); _endingSessions.insert(begin(sessions), end(sessions)); } @@ -435,9 +450,13 @@ std::vector<LogicalSessionId> LogicalSessionCacheImpl::listIds( } boost::optional<LogicalSessionRecord> LogicalSessionCacheImpl::peekCached( - const LogicalSessionId& id) const { + const LogicalSessionId& lsid) const { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "Cannot specify a session id with parent session id " << lsid, + !getParentSessionId(lsid)); + stdx::lock_guard<Latch> lk(_mutex); - const auto it = _activeSessions.find(id); + const auto it = _activeSessions.find(lsid); if (it == _activeSessions.end()) { return boost::none; } diff --git a/src/mongo/db/logical_session_cache_test.cpp b/src/mongo/db/logical_session_cache_test.cpp index d1a6be816e1..9500f65f3d1 100644 --- a/src/mongo/db/logical_session_cache_test.cpp +++ b/src/mongo/db/logical_session_cache_test.cpp @@ -47,6 +47,7 @@ #include "mongo/db/service_context_test_fixture.h" #include "mongo/db/service_liaison_mock.h" #include "mongo/db/sessions_collection_mock.h" +#include "mongo/idl/server_parameter_test_util.h" #include "mongo/stdx/future.h" #include "mongo/unittest/ensure_fcv.h" #include "mongo/unittest/unittest.h" @@ -118,68 +119,172 @@ private: std::shared_ptr<MockSessionsCollectionImpl> _sessions; std::unique_ptr<LogicalSessionCache> _cache; + + RAIIServerParameterControllerForTest _controller{"featureFlagInternalTransactions", true}; }; +TEST_F(LogicalSessionCacheTest, ParentAndChildSessionsHaveEqualLogicalSessionRecord) { + auto parentLsid = makeLogicalSessionIdForTest(); + auto lastUse = Date_t::now(); + auto parentSessionRecord = makeLogicalSessionRecord(parentLsid, lastUse); + + auto childSessionRecord0 = + makeLogicalSessionRecord(makeLogicalSessionIdWithTxnNumberForTest(parentLsid), lastUse); + ASSERT_BSONOBJ_EQ(parentSessionRecord.toBSON(), childSessionRecord0.toBSON()); + + auto childSessionRecord1 = + makeLogicalSessionRecord(makeLogicalSessionIdWithTxnUUIDForTest(parentLsid), lastUse); + ASSERT_BSONOBJ_EQ(parentSessionRecord.toBSON(), childSessionRecord1.toBSON()); +} + // Test that promoting from the cache updates the lastUse date of records TEST_F(LogicalSessionCacheTest, VivifyUpdatesLastUse) { - auto lsid = makeLogicalSessionIdForTest(); + auto runTest = [&](const LogicalSessionId& lsid) { + auto start = service()->now(); - auto start = service()->now(); + // Insert the record into the sessions collection with 'start' + ASSERT_OK(cache()->startSession(opCtx(), makeLogicalSessionRecord(lsid, start))); - // Insert the record into the sessions collection with 'start' - ASSERT_OK(cache()->startSession(opCtx(), makeLogicalSessionRecord(lsid, start))); + // Fast forward time and promote + service()->fastForward(Milliseconds(500)); + ASSERT_OK(cache()->vivify(opCtx(), lsid)); - // Fast forward time and promote - service()->fastForward(Milliseconds(500)); - ASSERT_OK(cache()->vivify(opCtx(), lsid)); + // Now that we promoted, lifetime of session should be extended + service()->fastForward(kSessionTimeout - Milliseconds(500)); + ASSERT_OK(cache()->vivify(opCtx(), lsid)); - // Now that we promoted, lifetime of session should be extended - service()->fastForward(kSessionTimeout - Milliseconds(500)); - ASSERT_OK(cache()->vivify(opCtx(), lsid)); + // We promoted again, so lifetime extended again + service()->fastForward(kSessionTimeout - Milliseconds(500)); + ASSERT_OK(cache()->vivify(opCtx(), lsid)); - // We promoted again, so lifetime extended again - service()->fastForward(kSessionTimeout - Milliseconds(500)); - ASSERT_OK(cache()->vivify(opCtx(), lsid)); + // Fast forward and promote + service()->fastForward(kSessionTimeout - Milliseconds(10)); + ASSERT_OK(cache()->vivify(opCtx(), lsid)); - // Fast forward and promote - service()->fastForward(kSessionTimeout - Milliseconds(10)); - ASSERT_OK(cache()->vivify(opCtx(), lsid)); + // Lifetime extended again + service()->fastForward(Milliseconds(11)); + ASSERT_OK(cache()->vivify(opCtx(), lsid)); + }; - // Lifetime extended again - service()->fastForward(Milliseconds(11)); - ASSERT_OK(cache()->vivify(opCtx(), lsid)); + runTest(makeLogicalSessionIdForTest()); + runTest(makeLogicalSessionIdWithTxnNumberForTest()); + runTest(makeLogicalSessionIdWithTxnUUIDForTest()); +} + +TEST_F(LogicalSessionCacheTest, VivifyUpdatesLastUseOfParentSession) { + auto runTest = [&](const LogicalSessionId& parentLsid, const LogicalSessionId& childLsid) { + ASSERT_OK( + cache()->startSession(opCtx(), makeLogicalSessionRecord(parentLsid, service()->now()))); + service()->fastForward(Minutes(1)); + ASSERT_OK(cache()->vivify(opCtx(), childLsid)); + ASSERT_OK(cache()->refreshNow(opCtx())); + + auto records = sessions()->sessions(); + ASSERT_EQ(1, records.size()); + ASSERT_EQ(service()->now(), records.begin()->second.getLastUse()); + sessions()->clearSessions(); + }; + + auto parentLsid = makeLogicalSessionIdForTest(); + runTest(parentLsid, makeLogicalSessionIdWithTxnNumberForTest(parentLsid)); + runTest(parentLsid, makeLogicalSessionIdWithTxnUUIDForTest(parentLsid)); + runTest(makeLogicalSessionIdWithTxnNumberForTest(parentLsid), + makeLogicalSessionIdWithTxnUUIDForTest(parentLsid)); +} + +TEST_F(LogicalSessionCacheTest, CannotVivifySessionWithParentSessionIfFeatureFlagIsNotEnabled) { + RAIIServerParameterControllerForTest controller{"featureFlagInternalTransactions", false}; + ASSERT_THROWS_CODE(cache()->vivify(opCtx(), makeLogicalSessionIdWithTxnNumberForTest()), + DBException, + ErrorCodes::InvalidOptions); + ASSERT_THROWS_CODE(cache()->vivify(opCtx(), makeLogicalSessionIdWithTxnUUIDForTest()), + DBException, + ErrorCodes::InvalidOptions); + ASSERT_EQ(0UL, cache()->size()); } // Test the startSession method TEST_F(LogicalSessionCacheTest, StartSession) { - auto record = makeLogicalSessionRecord(makeLogicalSessionIdForTest(), service()->now()); - auto lsid = record.getId(); + auto runTest = [&](const LogicalSessionId& lsid0, const LogicalSessionId& lsid1) { + auto parentLsid0 = getParentSessionId(lsid0); + auto record = makeLogicalSessionRecord(lsid0, service()->now()); - // Test starting a new session - ASSERT_OK(cache()->startSession(opCtx(), record)); + // Test starting a new session + ASSERT_OK(cache()->startSession(opCtx(), record)); - // Record will not be in the collection yet; refresh must happen first. - ASSERT(!sessions()->has(lsid)); + // Record will not be in the collection yet; refresh must happen first. + ASSERT(!sessions()->has(lsid0)); - // Do refresh, cached records should get flushed to collection. - ASSERT(cache()->refreshNow(opCtx()).isOK()); - ASSERT(sessions()->has(lsid)); + // Do refresh, cached records should get flushed to collection. + ASSERT(cache()->refreshNow(opCtx()).isOK()); + if (parentLsid0) { + ASSERT(!sessions()->has(lsid0)); + ASSERT(sessions()->has(*parentLsid0)); + } else { + ASSERT(sessions()->has(lsid0)); + } - // Try to start the same session again, should succeed. - ASSERT_OK(cache()->startSession(opCtx(), record)); + // Try to start the same session again, should succeed. + ASSERT_OK(cache()->startSession(opCtx(), record)); - // Try to start a session that is already in the sessions collection but - // is not in our local cache, should succeed. - auto record2 = makeLogicalSessionRecord(makeLogicalSessionIdForTest(), service()->now()); - sessions()->add(record2); - ASSERT_OK(cache()->startSession(opCtx(), record2)); + // Try to start a session that is already in the sessions collection but + // is not in our local cache, should succeed. + auto record1 = makeLogicalSessionRecord(lsid1, service()->now()); + sessions()->add(record1); + ASSERT_OK(cache()->startSession(opCtx(), record1)); + + // Try to start a session that has expired from our cache, and is no + // longer in the sessions collection, should succeed + service()->fastForward(Milliseconds(kSessionTimeout.count() + 5)); + sessions()->remove(parentLsid0 ? *parentLsid0 : lsid0); + if (parentLsid0) { + ASSERT(!sessions()->has(lsid0)); + ASSERT(!sessions()->has(*parentLsid0)); + } else { + ASSERT(!sessions()->has(lsid0)); + } + ASSERT_OK(cache()->startSession(opCtx(), record)); + }; - // Try to start a session that has expired from our cache, and is no - // longer in the sessions collection, should succeed - service()->fastForward(Milliseconds(kSessionTimeout.count() + 5)); - sessions()->remove(lsid); - ASSERT(!sessions()->has(lsid)); - ASSERT_OK(cache()->startSession(opCtx(), record)); + runTest(makeLogicalSessionIdForTest(), makeLogicalSessionIdForTest()); + runTest(makeLogicalSessionIdWithTxnNumberForTest(), makeLogicalSessionIdWithTxnNumberForTest()); + runTest(makeLogicalSessionIdWithTxnUUIDForTest(), makeLogicalSessionIdWithTxnUUIDForTest()); +} + +// Test the endSessions method. +TEST_F(LogicalSessionCacheTest, EndSessions) { + const auto lsids = []() -> std::vector<LogicalSessionId> { + auto lsid0 = makeLogicalSessionIdForTest(); + auto lsid1 = makeLogicalSessionIdForTest(); + auto lsid2 = makeLogicalSessionIdWithTxnNumberForTest(lsid1); + auto lsid3 = makeLogicalSessionIdWithTxnUUIDForTest(lsid1); + return {lsid0, lsid1, lsid2, lsid3}; + }(); + + for (const auto& lsid : lsids) { + ASSERT_OK(cache()->startSession(opCtx(), makeLogicalSessionRecord(lsid, service()->now()))); + } + ASSERT_EQ(2UL, cache()->size()); + + // Verify that it is invalid to pass an lsid with a parent lsid into endSessions. + ASSERT_THROWS_CODE(cache()->endSessions({lsids[2]}), DBException, ErrorCodes::InvalidOptions); + ASSERT_THROWS_CODE(cache()->endSessions({lsids[3]}), DBException, ErrorCodes::InvalidOptions); + + cache()->endSessions({lsids[0], lsids[1]}); +} + +// Test the peekCached method. +TEST_F(LogicalSessionCacheTest, PeekCached) { + auto lsid0 = makeLogicalSessionIdForTest(); + auto record0 = makeLogicalSessionRecord(lsid0, service()->now()); + ASSERT_OK(cache()->startSession(opCtx(), record0)); + ASSERT_BSONOBJ_EQ(record0.toBSON(), cache()->peekCached(lsid0)->toBSON()); + + // Verify that it is invalid to pass an lsid with a parent lsid into peekCached. + auto lsid1 = makeLogicalSessionIdWithTxnNumberForTest(lsid0); + ASSERT_THROWS_CODE(cache()->peekCached(lsid1), DBException, ErrorCodes::InvalidOptions); + auto lsid2 = makeLogicalSessionIdWithTxnUUIDForTest(lsid0); + ASSERT_THROWS_CODE(cache()->peekCached(lsid2), DBException, ErrorCodes::InvalidOptions); } // Test that session cache properly expires lsids after 30 minutes of no use diff --git a/src/mongo/db/logical_session_id_helpers.cpp b/src/mongo/db/logical_session_id_helpers.cpp index 6ec83fe10bc..d5565980859 100644 --- a/src/mongo/db/logical_session_id_helpers.cpp +++ b/src/mongo/db/logical_session_id_helpers.cpp @@ -85,6 +85,18 @@ boost::optional<LogicalSessionId> getParentSessionId(const LogicalSessionId& ses LogicalSessionId makeLogicalSessionId(const LogicalSessionFromClient& fromClient, OperationContext* opCtx, std::initializer_list<Privilege> allowSpoof) { + uassert(ErrorCodes::InvalidOptions, + "Cannot specify both txnNumber and txnUUID in lsid", + !fromClient.getTxnNumber() || !fromClient.getTxnUUID()); + + uassert(ErrorCodes::InvalidOptions, + "Cannot specify txnNumber in lsid without specifying stmtId", + !fromClient.getTxnNumber() || fromClient.getStmtId()); + + uassert(ErrorCodes::InvalidOptions, + "Cannot specify stmtId in lsid without specifying txnNumber", + !fromClient.getStmtId() || fromClient.getTxnNumber()); + LogicalSessionId lsid; lsid.setId(fromClient.getId()); @@ -157,9 +169,13 @@ LogicalSessionRecord makeLogicalSessionRecord(OperationContext* opCtx, Date_t la } LogicalSessionRecord makeLogicalSessionRecord(const LogicalSessionId& lsid, Date_t lastUse) { + LogicalSessionId id{}; LogicalSessionRecord lsr{}; - lsr.setId(lsid); + id.setId(lsid.getId()); + id.setUid(lsid.getUid()); + + lsr.setId(id); lsr.setLastUse(lastUse); return lsr; diff --git a/src/mongo/db/logical_session_id_test.cpp b/src/mongo/db/logical_session_id_test.cpp index e9043f2da01..361406952d1 100644 --- a/src/mongo/db/logical_session_id_test.cpp +++ b/src/mongo/db/logical_session_id_test.cpp @@ -143,6 +143,99 @@ TEST_F(LogicalSessionIdTest, ConstructorFromClientWithoutPassedUid) { ASSERT_EQ(lsid.getUid(), user->getDigest()); } +TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTxnNumberAndStmtId) { + auto id = UUID::gen(); + TxnNumber txnNumber(35); + StmtId stmtId(0); + User* user = addSimpleUser(UserName("simple", "test")); + + LogicalSessionFromClient req; + req.setId(id); + req.getInternalSessionFields().setTxnNumber(txnNumber); + req.getInternalSessionFields().setStmtId(stmtId); + + LogicalSessionId lsid = makeLogicalSessionId(req, _opCtx.get()); + ASSERT_EQ(lsid.getId(), id); + ASSERT_EQ(lsid.getUid(), user->getDigest()); + ASSERT_EQ(*lsid.getTxnNumber(), txnNumber); + ASSERT_EQ(*lsid.getStmtId(), stmtId); +} + +TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTxnUUID) { + auto id = UUID::gen(); + auto txnUUID = UUID::gen(); + User* user = addSimpleUser(UserName("simple", "test")); + + LogicalSessionFromClient req; + req.setId(id); + req.getInternalSessionFields().setTxnUUID(txnUUID); + + LogicalSessionId lsid = makeLogicalSessionId(req, _opCtx.get()); + ASSERT_EQ(lsid.getId(), id); + ASSERT_EQ(lsid.getUid(), user->getDigest()); + ASSERT_EQ(*lsid.getTxnUUID(), txnUUID); +} + +TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTxnNumberWithoutStmtId) { + auto id = UUID::gen(); + TxnNumber txnNumber(35); + addSimpleUser(UserName("simple", "test")); + + LogicalSessionFromClient req; + req.setId(id); + req.getInternalSessionFields().setTxnNumber(txnNumber); + + ASSERT_THROWS_CODE( + makeLogicalSessionId(req, _opCtx.get()), DBException, ErrorCodes::InvalidOptions); +} + +TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTxnUUIDWithStmtId) { + auto id = UUID::gen(); + auto txnUUID = UUID::gen(); + StmtId stmtId(0); + addSimpleUser(UserName("simple", "test")); + + LogicalSessionFromClient req; + req.setId(id); + req.getInternalSessionFields().setTxnUUID(txnUUID); + req.getInternalSessionFields().setStmtId(stmtId); + + ASSERT_THROWS_CODE( + makeLogicalSessionId(req, _opCtx.get()), DBException, ErrorCodes::InvalidOptions); +} + +TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTxnNumberAndTxnUUID) { + auto id = UUID::gen(); + TxnNumber txnNumber(35); + auto txnUUID = UUID::gen(); + addSimpleUser(UserName("simple", "test")); + + LogicalSessionFromClient req; + req.setId(id); + req.getInternalSessionFields().setTxnNumber(txnNumber); + req.getInternalSessionFields().setTxnUUID(txnUUID); + + ASSERT_THROWS_CODE( + makeLogicalSessionId(req, _opCtx.get()), DBException, ErrorCodes::InvalidOptions); +} + +TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTxnNumberAndTxnUUIDAndStmtId) { + auto id = UUID::gen(); + TxnNumber txnNumber(35); + auto txnUUID = UUID::gen(); + StmtId stmtId(0); + addSimpleUser(UserName("simple", "test")); + + LogicalSessionFromClient req; + req.setId(id); + req.getInternalSessionFields().setTxnNumber(txnNumber); + req.getInternalSessionFields().setTxnUUID(txnUUID); + req.getInternalSessionFields().setStmtId(stmtId); + + ASSERT_THROWS_CODE( + makeLogicalSessionId(req, _opCtx.get()), DBException, ErrorCodes::InvalidOptions); +} + TEST_F(LogicalSessionIdTest, ConstructorFromClientWithoutPassedUidAndWithoutAuthedUser) { auto id = UUID::gen(); diff --git a/src/mongo/db/session_catalog.cpp b/src/mongo/db/session_catalog.cpp index 581d65aa27c..7a87b2f6f85 100644 --- a/src/mongo/db/session_catalog.cpp +++ b/src/mongo/db/session_catalog.cpp @@ -35,6 +35,9 @@ #include <memory> +#include "mongo/db/internal_transactions_feature_flag_gen.h" +#include "mongo/db/logical_session_id_helpers.h" +#include "mongo/db/server_options.h" #include "mongo/db/service_context.h" #include "mongo/logv2/log.h" @@ -73,6 +76,11 @@ SessionCatalog* SessionCatalog::get(ServiceContext* service) { SessionCatalog::ScopedCheckedOutSession SessionCatalog::_checkOutSessionWithParentSession( OperationContext* opCtx, const LogicalSessionId& lsid, boost::optional<KillToken> killToken) { + uassert(ErrorCodes::InvalidOptions, + "Internal transactions are not enabled", + feature_flags::gFeatureFlagInternalTransactions.isEnabled( + serverGlobalParams.featureCompatibility)); + if (killToken) { invariant(killToken->lsidToKill == lsid); } else { diff --git a/src/mongo/db/session_catalog_test.cpp b/src/mongo/db/session_catalog_test.cpp index a89ee2561c1..209e68a74e0 100644 --- a/src/mongo/db/session_catalog_test.cpp +++ b/src/mongo/db/session_catalog_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/cancelable_operation_context.h" #include "mongo/db/service_context_test_fixture.h" #include "mongo/db/session_catalog.h" +#include "mongo/idl/server_parameter_test_util.h" #include "mongo/logv2/log.h" #include "mongo/stdx/future.h" #include "mongo/unittest/barrier.h" @@ -52,6 +53,8 @@ protected: SessionCatalog* catalog() { return SessionCatalog::get(getServiceContext()); } + + RAIIServerParameterControllerForTest _controller{"featureFlagInternalTransactions", true}; }; class SessionCatalogTestWithDefaultOpCtx : public SessionCatalogTest { @@ -77,6 +80,14 @@ private: const bool _wasInDirectClient; }; +TEST_F(SessionCatalogTest, GetParentSessionId) { + auto parentLsid = makeLogicalSessionIdForTest(); + ASSERT(!getParentSessionId(parentLsid).has_value()); + ASSERT_EQ(parentLsid, + *getParentSessionId(makeLogicalSessionIdWithTxnNumberForTest(parentLsid))); + ASSERT_EQ(parentLsid, *getParentSessionId(makeLogicalSessionIdWithTxnUUIDForTest(parentLsid))); +} + TEST_F(SessionCatalogTestWithDefaultOpCtx, CheckoutAndReleaseSession) { _opCtx->setLogicalSessionId(makeLogicalSessionIdForTest()); OperationContextSession ocs(_opCtx); @@ -108,6 +119,19 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, CheckoutAndReleaseSessionWithTxnUUID) ASSERT_EQ(*_opCtx->getLogicalSessionId(), session->getSessionId()); } +TEST_F(SessionCatalogTestWithDefaultOpCtx, + CannotCheckoutSessionWithParentSessionIfFeatureFlagIsNotEnabled) { + RAIIServerParameterControllerForTest controller{"featureFlagInternalTransactions", false}; + + _opCtx->setLogicalSessionId(makeLogicalSessionIdWithTxnNumberForTest()); + ASSERT_THROWS_CODE(OperationContextSession(_opCtx), DBException, ErrorCodes::InvalidOptions); + + _opCtx->setLogicalSessionId(makeLogicalSessionIdWithTxnUUIDForTest()); + ASSERT_THROWS_CODE(OperationContextSession(_opCtx), DBException, ErrorCodes::InvalidOptions); + + ASSERT_EQ(0UL, catalog()->size()); +} + TEST_F(SessionCatalogTestWithDefaultOpCtx, CannotCheckOutParentSessionOfCheckedOutSession) { auto runTest = [&](const LogicalSessionId& parentLsid, const LogicalSessionId& childLsid) { _opCtx->setLogicalSessionId(childLsid); diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index bd95a41d023..f1d5a83891e 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -148,7 +148,6 @@ env.Library( 'chunk_version.idl', 'database_version.cpp', 'database_version.idl', - 'internal_transactions_feature_flag.idl', 'load_balancer_feature_flag.idl', 'mongod_and_mongos_server_parameters.idl', 'request_types/abort_reshard_collection.idl', |