summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Lee <jonathan.lee@mongodb.com>2021-09-28 14:29:54 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-09-28 15:46:10 +0000
commit64c8863c9d387b22d3ebd8b66836191837ece434 (patch)
treef1c51a1883cf26279869dab8eed5b1496fb97611
parentc1f41cbaec4a4d570b072c75634f45d33472aec6 (diff)
downloadmongo-64c8863c9d387b22d3ebd8b66836191837ece434.tar.gz
SERVER-59703 Only support child sessions in sharded clusters
-rw-r--r--jstests/multiVersion/internal_sessions.js117
-rw-r--r--jstests/sharding/internal_sessions_reaping.js (renamed from jstests/replsets/internal_sessions_reaping.js)38
-rw-r--r--src/mongo/db/SConscript2
-rw-r--r--src/mongo/db/initialize_operation_session_info.cpp4
-rw-r--r--src/mongo/db/logical_session_cache_impl.cpp4
-rw-r--r--src/mongo/db/logical_session_cache_test.cpp22
-rw-r--r--src/mongo/db/session_catalog.cpp4
-rw-r--r--src/mongo/db/session_catalog_test.cpp23
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);