diff options
-rw-r--r-- | jstests/multiVersion/internal_sessions.js | 117 | ||||
-rw-r--r-- | jstests/sharding/internal_sessions_reaping.js (renamed from jstests/replsets/internal_sessions_reaping.js) | 38 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/initialize_operation_session_info.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/logical_session_cache_impl.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/logical_session_cache_test.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/session_catalog.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/session_catalog_test.cpp | 23 |
8 files changed, 136 insertions, 78 deletions
diff --git a/jstests/multiVersion/internal_sessions.js b/jstests/multiVersion/internal_sessions.js index d17bffe5629..ff17804eede 100644 --- a/jstests/multiVersion/internal_sessions.js +++ b/jstests/multiVersion/internal_sessions.js @@ -6,75 +6,70 @@ (function() { 'use strict'; -TestData.disableImplicitSessions = true; +function runTest(downgradeFCV) { + TestData.disableImplicitSessions = true; -const rst = new ReplSetTest({nodes: 1, nodeOptions: {setParameter: {maxSessions: 1}}}); + const st = new ShardingTest({shards: 1}); + const shard0Rst = st.rs0; + const shard0Primary = shard0Rst.getPrimary(); -rst.startSet(); -rst.initiate(); + const kDbName = "testDb"; + const kCollName = "testColl"; + const testDB = shard0Primary.getDB(kDbName); -const kDbName = "testDb"; -const kCollName = "testColl"; -const primary = rst.getPrimary(); -const testDB = primary.getDB(kDbName); + const sessionUUID = UUID(); + const lsid0 = {id: sessionUUID, txnNumber: NumberLong(35), stmtId: NumberInt(0)}; + const txnNumber0 = NumberLong(0); + const lsid1 = {id: sessionUUID, txnUUID: UUID()}; + const txnNumber1 = NumberLong(35); -const sessionUUID = UUID(); -const lsid0 = { - id: sessionUUID, - txnNumber: NumberLong(35), - stmtId: NumberInt(0) -}; -const txnNumber0 = NumberLong(0); -const lsid1 = { - id: sessionUUID, - txnUUID: UUID() -}; -const txnNumber1 = NumberLong(35); + assert.commandWorked(shard0Primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV})); -assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV})); + assert.commandFailedWithCode(testDB.runCommand({ + insert: kCollName, + documents: [{x: 0}], + lsid: lsid0, + txnNumber: txnNumber0, + startTransaction: true, + autocommit: false + }), + ErrorCodes.InvalidOptions); + assert.commandFailedWithCode(testDB.runCommand({ + insert: kCollName, + documents: [{x: 1}], + lsid: lsid1, + txnNumber: txnNumber1, + startTransaction: true, + autocommit: false + }), + ErrorCodes.InvalidOptions); -assert.commandFailedWithCode(testDB.runCommand({ - insert: kCollName, - documents: [{x: 0}], - lsid: lsid0, - txnNumber: txnNumber0, - startTransaction: true, - autocommit: false -}), - ErrorCodes.InvalidOptions); -assert.commandFailedWithCode(testDB.runCommand({ - insert: kCollName, - documents: [{x: 1}], - lsid: lsid1, - txnNumber: txnNumber1, - startTransaction: true, - autocommit: false -}), - ErrorCodes.InvalidOptions); + assert.commandWorked(shard0Primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); -assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); + assert.commandWorked(testDB.runCommand({ + insert: kCollName, + documents: [{x: 0}], + lsid: lsid0, + txnNumber: txnNumber0, + startTransaction: true, + autocommit: false + })); + assert.commandWorked(testDB.adminCommand( + {commitTransaction: 1, lsid: lsid0, txnNumber: txnNumber0, autocommit: false})); -assert.commandWorked(testDB.runCommand({ - insert: kCollName, - documents: [{x: 0}], - lsid: lsid0, - txnNumber: txnNumber0, - startTransaction: true, - autocommit: false -})); -assert.commandWorked(testDB.adminCommand( - {commitTransaction: 1, lsid: lsid0, txnNumber: txnNumber0, autocommit: false})); + assert.commandWorked(testDB.runCommand({ + insert: kCollName, + documents: [{x: 1}], + lsid: lsid1, + txnNumber: txnNumber1, + startTransaction: true, + autocommit: false + })); + assert.commandWorked(testDB.adminCommand( + {commitTransaction: 1, lsid: lsid1, txnNumber: txnNumber1, autocommit: false})); -assert.commandWorked(testDB.runCommand({ - insert: kCollName, - documents: [{x: 1}], - lsid: lsid1, - txnNumber: txnNumber1, - startTransaction: true, - autocommit: false -})); -assert.commandWorked(testDB.adminCommand( - {commitTransaction: 1, lsid: lsid1, txnNumber: txnNumber1, autocommit: false})); + st.stop(); +} -rst.stopSet(); +runFeatureFlagMultiversionTest('featureFlagInternalTransactions', runTest); })(); diff --git a/jstests/replsets/internal_sessions_reaping.js b/jstests/sharding/internal_sessions_reaping.js index deada3aeba6..22d2e2f9407 100644 --- a/jstests/replsets/internal_sessions_reaping.js +++ b/jstests/sharding/internal_sessions_reaping.js @@ -13,10 +13,9 @@ // implicit sessions. TestData.disableImplicitSessions = true; -let rst = new ReplSetTest({ - name: 'reaping', - nodes: 2, - nodeOptions: { +const st = new ShardingTest({ + shards: 1, + shardOptions: { setParameter: { maxSessions: 1, TransactionRecordMinimumLifetimeMinutes: 0, @@ -25,8 +24,8 @@ let rst = new ReplSetTest({ } }); -rst.startSet(); -rst.initiate(); +const shard0Rst = st.rs0; +const shard0Primary = shard0Rst.getPrimary(); const kDbName = "testDb"; const kCollName = "testColl"; @@ -35,16 +34,16 @@ const kConfigSessionsNs = "config.system.sessions"; const kConfigTxnsNs = "config.transactions"; const kImageCollNs = "config.image_collection"; -let primary = rst.getPrimary(); -let sessionsCollOnPrimary = primary.getCollection(kConfigSessionsNs); -let transactionsCollOnPrimary = primary.getCollection(kConfigTxnsNs); -let imageCollOnPrimary = primary.getCollection(kImageCollNs); -let testDB = primary.getDB(kDbName); +let sessionsCollOnPrimary = shard0Primary.getCollection(kConfigSessionsNs); +let transactionsCollOnPrimary = shard0Primary.getCollection(kConfigTxnsNs); +let imageCollOnPrimary = shard0Primary.getCollection(kImageCollNs); +let testDB = shard0Primary.getDB(kDbName); const sessionUUID = UUID(); const parentLsid = { id: sessionUUID }; + const kInternalTxnNumber = NumberLong(0); let numTransactionsCollEntries = 0; @@ -57,6 +56,7 @@ const childLsid0 = { id: sessionUUID, txnUUID: UUID() }; + assert.commandWorked(testDB.runCommand({ update: kCollName, updates: [{q: {_id: 0}, u: {$set: {a: 0}}}], @@ -88,6 +88,7 @@ const childLsid1 = { txnNumber: parentTxnNumber1, stmtId: NumberInt(0) }; + assert.commandWorked(testDB.runCommand({ update: kCollName, updates: [{q: {_id: 0}, u: {$set: {c: 0}}}], @@ -119,6 +120,7 @@ const childLsid2 = { txnNumber: parentTxnNumber2, stmtId: NumberInt(0) }; + assert.commandWorked(testDB.runCommand({ findAndModify: kCollName, query: {_id: 0}, @@ -148,17 +150,19 @@ assert.eq({_id: 0, a: 0, b: 0, c: 0, d: 0, e: 0}, testDB.getCollection(kCollName).findOne({_id: 0})); assert.eq({_id: 1}, testDB.getCollection(kCollName).findOne({_id: 1})); -assert.commandWorked(primary.adminCommand({refreshLogicalSessionCacheNow: 1})); -assert.eq(1, sessionsCollOnPrimary.find().itcount()); +assert.commandWorked(shard0Primary.adminCommand({refreshLogicalSessionCacheNow: 1})); + +assert.eq(1, sessionsCollOnPrimary.find({"_id.id": sessionUUID}).itcount()); assert.eq(numTransactionsCollEntries, transactionsCollOnPrimary.find().itcount()); // assert.eq(numImageCollEntries, imageCollOnPrimary.find().itcount()); -assert.commandWorked(primary.adminCommand({reapLogicalSessionCacheNow: 1})); +assert.commandWorked(shard0Primary.adminCommand({reapLogicalSessionCacheNow: 1})); jsTest.log("Verify that the config.transactions entries for internal transactions did not get " + "reaped although they are expired since the config.system.sessions entry for the " + "parent session still has not been deleted"); -assert.eq(1, sessionsCollOnPrimary.find().itcount()); + +assert.eq(1, sessionsCollOnPrimary.find({"_id.id": sessionUUID}).itcount()); assert.eq(numTransactionsCollEntries, transactionsCollOnPrimary.find().itcount(), tojson(transactionsCollOnPrimary.find().toArray())); @@ -166,7 +170,7 @@ assert.eq(numTransactionsCollEntries, // Remove the session doc so the parent session gets reaped when reapLogicalSessionCacheNow is run. assert.commandWorked(sessionsCollOnPrimary.remove({})); -assert.commandWorked(primary.adminCommand({reapLogicalSessionCacheNow: 1})); +assert.commandWorked(shard0Primary.adminCommand({reapLogicalSessionCacheNow: 1})); jsTest.log("Verify that the config.transactions entries got reaped since the " + "config.system.sessions entry for the parent session had already been deleted"); @@ -176,5 +180,5 @@ assert.eq(0, tojson(transactionsCollOnPrimary.find().toArray())); assert.eq(0, imageCollOnPrimary.find().itcount()); -rst.stopSet(); +st.stop(); })(); diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index f83373e8d84..48f82c37580 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -678,6 +678,7 @@ env.Library( 'logical_session_id_helpers', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/s/is_mongos', 'internal_transactions_feature_flag', 'service_context', ] @@ -1554,6 +1555,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/s/sharding_api_d', + '$BUILD_DIR/mongo/s/is_mongos', '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 d50af9c090c..dbde1760c24 100644 --- a/src/mongo/db/initialize_operation_session_info.cpp +++ b/src/mongo/db/initialize_operation_session_info.cpp @@ -36,6 +36,7 @@ #include "mongo/db/logical_session_cache.h" #include "mongo/db/logical_session_id_helpers.h" #include "mongo/db/operation_context.h" +#include "mongo/s/is_mongos.h" namespace mongo { @@ -103,6 +104,9 @@ OperationSessionInfoFromClient initializeOperationSessionInfo(OperationContext* uassert(ErrorCodes::InvalidOptions, "Internal sessions are not supported outside of transactions", osi.getTxnNumber() && osi.getAutocommit() && !osi.getAutocommit().value()); + uassert(ErrorCodes::InvalidOptions, + "Internal sessions are only supported in sharded clusters", + isMongos() || serverGlobalParams.clusterRole != ClusterRole::None); } opCtx->setLogicalSessionId(std::move(lsid)); diff --git a/src/mongo/db/logical_session_cache_impl.cpp b/src/mongo/db/logical_session_cache_impl.cpp index 43f800c6820..2fcb2654c90 100644 --- a/src/mongo/db/logical_session_cache_impl.cpp +++ b/src/mongo/db/logical_session_cache_impl.cpp @@ -43,6 +43,7 @@ #include "mongo/logv2/log.h" #include "mongo/logv2/log_severity_suppressor.h" #include "mongo/platform/atomic_word.h" +#include "mongo/s/is_mongos.h" #include "mongo/util/duration.h" #include "mongo/util/scopeguard.h" @@ -100,6 +101,9 @@ Status LogicalSessionCacheImpl::vivify(OperationContext* opCtx, const LogicalSes "Internal transactions are not enabled", feature_flags::gFeatureFlagInternalTransactions.isEnabled( serverGlobalParams.featureCompatibility)); + uassert(ErrorCodes::InvalidOptions, + "Internal transactions are only supported in sharded clusters", + isMongos() || serverGlobalParams.clusterRole != ClusterRole::None); } stdx::lock_guard lg(_mutex); diff --git a/src/mongo/db/logical_session_cache_test.cpp b/src/mongo/db/logical_session_cache_test.cpp index 9500f65f3d1..8ee71e6bd62 100644 --- a/src/mongo/db/logical_session_cache_test.cpp +++ b/src/mongo/db/logical_session_cache_test.cpp @@ -112,6 +112,17 @@ public: return _opCtx.get(); } +protected: + void setUp() final { + ServiceContextTest::setUp(); + serverGlobalParams.clusterRole = ClusterRole::ShardServer; + } + + void tearDown() final { + serverGlobalParams.clusterRole = ClusterRole::None; + ServiceContextTest::tearDown(); + } + private: ServiceContext::UniqueOperationContext _opCtx; @@ -203,6 +214,17 @@ TEST_F(LogicalSessionCacheTest, CannotVivifySessionWithParentSessionIfFeatureFla ASSERT_EQ(0UL, cache()->size()); } +TEST_F(LogicalSessionCacheTest, CannotVivifySessionWithParentSessionIfNotRunningInShardedCluster) { + serverGlobalParams.clusterRole = ClusterRole::None; + 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 runTest = [&](const LogicalSessionId& lsid0, const LogicalSessionId& lsid1) { diff --git a/src/mongo/db/session_catalog.cpp b/src/mongo/db/session_catalog.cpp index 4d204b58b05..478e3b7e07e 100644 --- a/src/mongo/db/session_catalog.cpp +++ b/src/mongo/db/session_catalog.cpp @@ -40,6 +40,7 @@ #include "mongo/db/server_options.h" #include "mongo/db/service_context.h" #include "mongo/logv2/log.h" +#include "mongo/s/is_mongos.h" namespace mongo { namespace { @@ -80,6 +81,9 @@ SessionCatalog::ScopedCheckedOutSession SessionCatalog::_checkOutSessionWithPare "Internal transactions are not enabled", feature_flags::gFeatureFlagInternalTransactions.isEnabled( serverGlobalParams.featureCompatibility)); + uassert(ErrorCodes::InvalidOptions, + "Internal transactions are only supported in sharded clusters", + isMongos() || serverGlobalParams.clusterRole != ClusterRole::None); if (killToken) { invariant(killToken->lsidToKill == lsid); diff --git a/src/mongo/db/session_catalog_test.cpp b/src/mongo/db/session_catalog_test.cpp index f1dd57145b2..59abe2e3921 100644 --- a/src/mongo/db/session_catalog_test.cpp +++ b/src/mongo/db/session_catalog_test.cpp @@ -50,6 +50,16 @@ namespace { class SessionCatalogTest : public ServiceContextTest { protected: + void setUp() final { + ServiceContextTest::setUp(); + serverGlobalParams.clusterRole = ClusterRole::ShardServer; + } + + void tearDown() final { + serverGlobalParams.clusterRole = ClusterRole::None; + ServiceContextTest::tearDown(); + } + SessionCatalog* catalog() { return SessionCatalog::get(getServiceContext()); } @@ -132,6 +142,19 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, ASSERT_EQ(0UL, catalog()->size()); } +TEST_F(SessionCatalogTestWithDefaultOpCtx, + CannotCheckoutSessionWithParentSessionIfNotRunningInShardedCluster) { + serverGlobalParams.clusterRole = ClusterRole::None; + + _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); |