summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandolph Tan <randolph@10gen.com>2016-03-23 17:32:02 -0400
committerRandolph Tan <randolph@10gen.com>2016-04-08 13:50:53 -0400
commitbbaf069f100e86664b7795d097f0c802fe3965df (patch)
tree150693d456180395fa99672115417b48ca7485e9
parent11132f69c93a279ebe7f0ccb71929d4cd2b8675d (diff)
downloadmongo-bbaf069f100e86664b7795d097f0c802fe3965df.tar.gz
SERVER-22661 Require --shardsvr for shard aware initialization
-rw-r--r--jstests/sharding/shard_aware_init.js58
-rw-r--r--jstests/sharding/shard_aware_primary_failover.js2
-rw-r--r--jstests/sharding/sharding_state_after_stepdown.js4
-rw-r--r--src/mongo/client/replica_set_monitor.cpp2
-rw-r--r--src/mongo/db/s/SConscript18
-rw-r--r--src/mongo/db/s/sharding_state.cpp19
-rw-r--r--src/mongo/db/s/sharding_state.h12
-rw-r--r--src/mongo/db/s/sharding_state_recovery.cpp4
-rw-r--r--src/mongo/db/s/sharding_state_test.cpp359
-rw-r--r--src/mongo/db/service_context_noop.h2
-rw-r--r--src/mongo/s/grid.cpp1
-rw-r--r--src/mongo/s/grid.h2
-rw-r--r--src/mongo/shell/replsettest.js2
-rw-r--r--src/mongo/shell/shardingtest.js5
14 files changed, 471 insertions, 19 deletions
diff --git a/jstests/sharding/shard_aware_init.js b/jstests/sharding/shard_aware_init.js
index 0679096d1c2..b97c459c007 100644
--- a/jstests/sharding/shard_aware_init.js
+++ b/jstests/sharding/shard_aware_init.js
@@ -27,6 +27,37 @@
clusterId: ObjectId()
};
+ /**
+ * Restarts the server without --shardsvr and replace the shardIdentity doc with a valid
+ * document. Then, restarts the server again with --shardsvr. This also returns a
+ * connection to the server after the last restart.
+ */
+ var restartAndFixShardIdentityDoc = function(startOptions) {
+ var options = Object.extend({}, startOptions);
+ delete options.shardsvr;
+ mongodConn = MongoRunner.runMongod(options);
+ waitForMaster(mongodConn);
+
+ var res = mongodConn.getDB('admin')
+ .system.version.update({_id: 'shardIdentity'}, shardIdentityDoc);
+ assert.eq(1, res.nModified);
+
+ MongoRunner.stopMongod(mongodConn.port);
+
+ newMongodOptions.shardsvr = '';
+ mongodConn = MongoRunner.runMongod(newMongodOptions);
+ waitForMaster(mongodConn);
+
+ res = mongodConn.getDB('admin').runCommand({shardingState: 1});
+
+ assert(res.enabled);
+ assert.eq(shardIdentityDoc.configsvrConnectionString, res.configServer);
+ assert.eq(shardIdentityDoc.shardName, res.shardName);
+ assert.eq(shardIdentityDoc.clusterId, res.clusterId);
+
+ return mongodConn;
+ };
+
assert.writeOK(mongodConn.getDB('admin').system.version.insert(shardIdentityDoc));
//
@@ -51,7 +82,7 @@
assert.eq(shardIdentityDoc.clusterId, res.clusterId);
//
- // Test badly formatted shardIdentity doc
+ // Test shardIdentity doc without configsvrConnectionString, resulting into parse error
//
assert.writeOK(mongodConn.getDB('admin').system.version.update(
@@ -65,25 +96,40 @@
waitForMaster(mongodConn);
});
- // TODO: add more bad format tests.
+ //
+ // Test that it is possible to fix the invalid shardIdentity doc by not passing --shardsvr
+ //
+
+ try {
+ // The server was terminated not by calling stopMongod earlier, this will cleanup
+ // the process from registry in shell_utils_launcher.
+ MongoRunner.stopMongod(newMongodOptions.port);
+ } catch (ex) {
+ if (!(ex instanceof (MongoRunner.StopError))) {
+ throw ex;
+ }
+ }
+
+ mongodConn = restartAndFixShardIdentityDoc(newMongodOptions);
+ res = mongodConn.getDB('admin').runCommand({shardingState: 1});
+ assert(res.enabled);
};
var st = new ShardingTest({shards: 1});
- var mongod = MongoRunner.runMongod();
+ var mongod = MongoRunner.runMongod({shardsvr: ''});
runTest(mongod, st.configRS.getURL());
MongoRunner.stopMongod(mongod.port);
var replTest = new ReplSetTest({nodes: 1});
- replTest.startSet();
+ replTest.startSet({shardsvr: ''});
replTest.initiate();
runTest(replTest.getPrimary(), st.configRS.getURL());
- // TODO: cleanup properly once --shardsvr checks are added
- // replTest.stopSet();
+ replTest.stopSet();
st.stop();
diff --git a/jstests/sharding/shard_aware_primary_failover.js b/jstests/sharding/shard_aware_primary_failover.js
index 6fac918494e..0d939c6e1ea 100644
--- a/jstests/sharding/shard_aware_primary_failover.js
+++ b/jstests/sharding/shard_aware_primary_failover.js
@@ -8,7 +8,7 @@
var st = new ShardingTest({shards: 1});
var replTest = new ReplSetTest({nodes: 3});
- replTest.startSet();
+ replTest.startSet({shardsvr: ''});
var nodes = replTest.nodeList();
replTest.initiate({
_id: replTest.name,
diff --git a/jstests/sharding/sharding_state_after_stepdown.js b/jstests/sharding/sharding_state_after_stepdown.js
index f5d9896a0d0..3007b4b08a2 100644
--- a/jstests/sharding/sharding_state_after_stepdown.js
+++ b/jstests/sharding/sharding_state_after_stepdown.js
@@ -45,8 +45,8 @@
false
});
- st.rs0.start(rs0Primary, {restart: true});
- st.rs1.start(rs1Primary, {restart: true});
+ st.rs0.start(rs0Primary, Object.extend(rs0Primary.savedOptions, {restart: true}));
+ st.rs1.start(rs1Primary, Object.extend(rs1Primary.savedOptions, {restart: true}));
ReplSetTest.awaitRSClientHosts(mongos,
[rs0Primary, rs1Primary],
diff --git a/src/mongo/client/replica_set_monitor.cpp b/src/mongo/client/replica_set_monitor.cpp
index 1df2e9fcb61..771960c38bc 100644
--- a/src/mongo/client/replica_set_monitor.cpp
+++ b/src/mongo/client/replica_set_monitor.cpp
@@ -457,6 +457,8 @@ void ReplicaSetMonitor::cleanup() {
replicaSetMonitorWatcher.stop();
replicaSetMonitorWatcher.wait();
globalRSMonitorManager.removeAllMonitors();
+ asyncConfigChangeHook = ReplicaSetMonitor::ConfigChangeHook();
+ syncConfigChangeHook = ReplicaSetMonitor::ConfigChangeHook();
}
bool ReplicaSetMonitor::isKnownToHaveGoodPrimary() const {
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index 37100b84cdd..0a6abb3f3e8 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -140,3 +140,21 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/s/sharding_test_fixture',
]
)
+
+env.CppUnitTest(
+ target='sharding_state_test',
+ source=[
+ 'sharding_state_test.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/client/remote_command_targeter_mock',
+ '$BUILD_DIR/mongo/db/serveronly',
+ '$BUILD_DIR/mongo/executor/network_test_env',
+ '$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
+ '$BUILD_DIR/mongo/s/catalog/catalog_manager_mock',
+ '$BUILD_DIR/mongo/util/clock_source_mock',
+ '$BUILD_DIR/mongo/util/net/message_port_mock',
+ '$BUILD_DIR/mongo/util/ntservice_mock',
+ ],
+ NO_CRUTCH = True,
+)
diff --git a/src/mongo/db/s/sharding_state.cpp b/src/mongo/db/s/sharding_state.cpp
index 3cf3b62dfac..8e12acc8872 100644
--- a/src/mongo/db/s/sharding_state.cpp
+++ b/src/mongo/db/s/sharding_state.cpp
@@ -121,7 +121,8 @@ VersionChoice chooseNewestVersion(ChunkVersion prevLocalVersion,
ShardingState::ShardingState()
: _initializationState(static_cast<uint32_t>(InitializationState::kNew)),
_initializationStatus(Status(ErrorCodes::InternalError, "Uninitialized value")),
- _configServerTickets(kMaxConfigServerRefreshThreads) {}
+ _configServerTickets(kMaxConfigServerRefreshThreads),
+ _globalInit(initializeGlobalShardingStateForMongod) {}
ShardingState::~ShardingState() = default;
@@ -258,6 +259,10 @@ void ShardingState::resetMetadata(const string& ns) {
_collections.erase(ns);
}
+void ShardingState::setGlobalInitMethodForTest(GlobalInitFunc func) {
+ _globalInit = func;
+}
+
Status ShardingState::onStaleShardVersion(OperationContext* txn,
const NamespaceString& nss,
const ChunkVersion& expectedVersion) {
@@ -354,7 +359,9 @@ void ShardingState::initializeFromConfigConnString(OperationContext* txn, const
Status ShardingState::initializeFromShardIdentity(OperationContext* txn) {
invariant(!txn->lockState()->isLocked());
- // TODO: SERVER-22663 if --shardsvr
+ if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {
+ return Status::OK();
+ }
BSONObj shardIdentityBSON;
try {
@@ -381,7 +388,9 @@ Status ShardingState::initializeFromShardIdentity(OperationContext* txn,
const ShardIdentityType& shardIdentity) {
invariant(!txn->lockState()->isLocked());
- // TODO: SERVER-22663 if --shardsvr
+ if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {
+ return Status::OK();
+ }
log() << "initializing sharding state with: " << shardIdentity;
@@ -459,7 +468,7 @@ Status ShardingState::initializeFromShardIdentity(OperationContext* txn,
&ConfigServer::replicaSetChangeShardRegistryUpdateHook);
try {
- Status status = initializeGlobalShardingStateForMongod(txn, configSvrConnStr);
+ Status status = _globalInit(txn, configSvrConnStr);
// For backwards compatibility with old style inits from metadata commands.
if (status.isOK()) {
@@ -495,7 +504,7 @@ void ShardingState::_initializeImpl(ConnectionString configSvr) {
&ConfigServer::replicaSetChangeShardRegistryUpdateHook);
try {
- Status status = initializeGlobalShardingStateForMongod(txn.get(), configSvr);
+ Status status = _globalInit(txn.get(), configSvr);
_signalInitializationComplete(status);
} catch (const DBException& ex) {
_signalInitializationComplete(ex.toStatus());
diff --git a/src/mongo/db/s/sharding_state.h b/src/mongo/db/s/sharding_state.h
index e100e39f153..79c2906284e 100644
--- a/src/mongo/db/s/sharding_state.h
+++ b/src/mongo/db/s/sharding_state.h
@@ -36,6 +36,7 @@
#include "mongo/bson/oid.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/s/migration_destination_manager.h"
+#include "mongo/stdx/functional.h"
#include "mongo/stdx/memory.h"
#include "mongo/stdx/mutex.h"
#include "mongo/util/concurrency/ticketholder.h"
@@ -85,6 +86,8 @@ public:
OperationContext* const _txn;
};
+ using GlobalInitFunc = stdx::function<Status(OperationContext*, const ConnectionString&)>;
+
ShardingState();
~ShardingState();
@@ -222,6 +225,12 @@ public:
*/
boost::optional<NamespaceString> getActiveMigrationNss();
+ /**
+ * For testing only. Mock the initialization method used by initializeFromConfigConnString and
+ * initializeFromShardIdentity after all checks are performed.
+ */
+ void setGlobalInitMethodForTest(GlobalInitFunc func);
+
private:
friend class ScopedRegisterMigration;
@@ -346,6 +355,9 @@ private:
// The id for the cluster this shard belongs to.
OID _clusterId;
+
+ // Function for initializing the external sharding state components not owned here.
+ GlobalInitFunc _globalInit;
};
} // namespace mongo
diff --git a/src/mongo/db/s/sharding_state_recovery.cpp b/src/mongo/db/s/sharding_state_recovery.cpp
index b3e0c661280..7d229d289d1 100644
--- a/src/mongo/db/s/sharding_state_recovery.cpp
+++ b/src/mongo/db/s/sharding_state_recovery.cpp
@@ -241,6 +241,10 @@ void ShardingStateRecovery::endMetadataOp(OperationContext* txn) {
}
Status ShardingStateRecovery::recover(OperationContext* txn) {
+ if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {
+ return Status::OK();
+ }
+
if (!recoverShardingState) {
warning()
<< "Not checking for ShardingState recovery document because the recoverShardingState "
diff --git a/src/mongo/db/s/sharding_state_test.cpp b/src/mongo/db/s/sharding_state_test.cpp
new file mode 100644
index 00000000000..c5ea81e28b4
--- /dev/null
+++ b/src/mongo/db/s/sharding_state_test.cpp
@@ -0,0 +1,359 @@
+/**
+ * Copyright (C) 2016 MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/base/status_with.h"
+#include "mongo/client/remote_command_targeter_factory_mock.h"
+#include "mongo/client/replica_set_monitor.h"
+#include "mongo/db/service_context_noop.h"
+#include "mongo/executor/network_interface_mock.h"
+#include "mongo/executor/thread_pool_task_executor_test_fixture.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/operation_context_noop.h"
+#include "mongo/db/s/sharding_state.h"
+#include "mongo/db/s/type_shard_identity.h"
+#include "mongo/db/service_context_noop.h"
+#include "mongo/s/catalog/catalog_cache.h"
+#include "mongo/s/catalog/catalog_manager_mock.h"
+#include "mongo/s/client/shard_registry.h"
+#include "mongo/s/grid.h"
+#include "mongo/s/query/cluster_cursor_manager.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/clock_source_mock.h"
+
+
+namespace mongo {
+namespace {
+
+/**
+ * Initializes the grid object with the bare minimum and is not intended to be functional.
+ */
+void initGrid(OperationContext* txn, const ConnectionString& configConnString) {
+ auto targeterFactory(stdx::make_unique<RemoteCommandTargeterFactoryMock>());
+
+ // Set up executor pool used for most operations.
+ auto fixedNet = stdx::make_unique<executor::NetworkInterfaceMock>();
+ auto mockNetwork = fixedNet.get();
+
+ auto fixedExec = makeThreadPoolTestExecutor(std::move(fixedNet));
+
+
+ auto netForPool = stdx::make_unique<executor::NetworkInterfaceMock>();
+ auto execForPool = makeThreadPoolTestExecutor(std::move(netForPool));
+ std::vector<std::unique_ptr<executor::TaskExecutor>> executorsForPool;
+ executorsForPool.emplace_back(std::move(execForPool));
+
+ auto executorPool = stdx::make_unique<executor::TaskExecutorPool>();
+ executorPool->addExecutors(std::move(executorsForPool), std::move(fixedExec));
+
+ // Set up executor used for a few special operations during addShard.
+ auto specialNet(stdx::make_unique<executor::NetworkInterfaceMock>());
+ // auto specialMockNet = specialNet.get();
+ auto specialExec = makeThreadPoolTestExecutor(std::move(specialNet));
+
+ auto shardRegistry(stdx::make_unique<ShardRegistry>(std::move(targeterFactory),
+ std::move(executorPool),
+ mockNetwork,
+ std::move(specialExec),
+ configConnString));
+ shardRegistry->startup();
+
+ grid.init(
+ stdx::make_unique<CatalogManagerMock>(),
+ stdx::make_unique<CatalogCache>(),
+ std::move(shardRegistry),
+ stdx::make_unique<ClusterCursorManager>(txn->getServiceContext()->getPreciseClockSource()));
+}
+
+class ShardingStateTest : public mongo::unittest::Test {
+public:
+ void setUp() override {
+ _service.setPreciseClockSource(stdx::make_unique<ClockSourceMock>());
+
+ serverGlobalParams.clusterRole = ClusterRole::ShardServer;
+ _client = _service.makeClient("ShardingStateTest");
+ _opCtx = _client->makeOperationContext();
+
+ _shardingState.setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ initGrid(txn, connStr);
+ return Status::OK();
+ });
+ }
+
+ void tearDown() override {
+ // ShardingState initialize can modify ReplicaSetMonitor state.
+ ReplicaSetMonitor::cleanup();
+
+ // Cleanup only if shard registry was initialized
+ if (grid.shardRegistry()) {
+ grid.shardRegistry()->shutdown();
+ grid.clearForUnitTests();
+ }
+ }
+
+ OperationContext* txn() {
+ return _opCtx.get();
+ }
+
+ ShardingState* shardingState() {
+ return &_shardingState;
+ }
+
+private:
+ ServiceContextNoop _service;
+ ServiceContext::UniqueClient _client;
+ ServiceContext::UniqueOperationContext _opCtx;
+
+ ShardingState _shardingState;
+};
+
+TEST_F(ShardingStateTest, ValidShardIdentitySucceeds) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(OID::gen());
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+TEST_F(ShardingStateTest, InvalidConfigServerConnStringDoesNotParse) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("invalid:x");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(OID::gen());
+
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity);
+ ASSERT_EQ(ErrorCodes::FailedToParse, status);
+ ASSERT_FALSE(shardingState()->enabled());
+}
+
+TEST_F(ShardingStateTest, CannotHaveNonReplConfigServerConnString) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("a:1");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(OID::gen());
+
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity);
+ ASSERT_EQ(ErrorCodes::UnsupportedFormat, status);
+ ASSERT_FALSE(shardingState()->enabled());
+}
+
+TEST_F(ShardingStateTest, InitWhilePreviouslyInErrorStateWillStayInErrorState) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(OID::gen());
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::ShutdownInProgress, "shutting down"};
+ });
+
+ {
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity);
+ ASSERT_EQ(ErrorCodes::ShutdownInProgress, status);
+ }
+
+ // ShardingState is now in error state, attempting to call it again will still result in error.
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) { return Status::OK(); });
+
+ {
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity);
+ ASSERT_EQ(ErrorCodes::ManualInterventionRequired, status);
+ }
+
+ ASSERT_FALSE(shardingState()->enabled());
+}
+
+TEST_F(ShardingStateTest, InitializeAgainWithMatchingShardIdentitySucceeds) {
+ auto clusterID = OID::gen();
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(clusterID);
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+
+ ShardIdentityType shardIdentity2;
+ shardIdentity2.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity2.setShardName("a");
+ shardIdentity2.setClusterId(clusterID);
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::InternalError, "should not reach here"};
+ });
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity2));
+
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+TEST_F(ShardingStateTest, InitializeAgainWithSameReplSetNameSucceeds) {
+ auto clusterID = OID::gen();
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(clusterID);
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+
+ ShardIdentityType shardIdentity2;
+ shardIdentity2.setConfigsvrConnString("config/b:2,c:3");
+ shardIdentity2.setShardName("a");
+ shardIdentity2.setClusterId(clusterID);
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::InternalError, "should not reach here"};
+ });
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity2));
+
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+TEST_F(ShardingStateTest, InitializeAgainWithDifferentReplSetNameFails) {
+ auto clusterID = OID::gen();
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(clusterID);
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+
+ ShardIdentityType shardIdentity2;
+ shardIdentity2.setConfigsvrConnString("configRS/a:1,b:2");
+ shardIdentity2.setShardName("a");
+ shardIdentity2.setClusterId(clusterID);
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::InternalError, "should not reach here"};
+ });
+
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity2);
+ ASSERT_EQ(ErrorCodes::InconsistentShardIdentity, status);
+
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+TEST_F(ShardingStateTest, InitializeAgainWithDifferentShardNameFails) {
+ auto clusterID = OID::gen();
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(clusterID);
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+
+ ShardIdentityType shardIdentity2;
+ shardIdentity2.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity2.setShardName("b");
+ shardIdentity2.setClusterId(clusterID);
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::InternalError, "should not reach here"};
+ });
+
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity2);
+ ASSERT_EQ(ErrorCodes::InconsistentShardIdentity, status);
+
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+TEST_F(ShardingStateTest, InitializeAgainWithPreviouslyUnsetClusterIdSucceeds) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(OID());
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+
+ ShardIdentityType shardIdentity2;
+ shardIdentity2.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity2.setShardName("a");
+ shardIdentity2.setClusterId(OID::gen());
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::InternalError, "should not reach here"};
+ });
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity2));
+
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+TEST_F(ShardingStateTest, InitializeAgainWithDifferentClusterIdFails) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity.setShardName("a");
+ shardIdentity.setClusterId(OID::gen());
+
+ ASSERT_OK(shardingState()->initializeFromShardIdentity(txn(), shardIdentity));
+
+ ShardIdentityType shardIdentity2;
+ shardIdentity2.setConfigsvrConnString("config/a:1,b:2");
+ shardIdentity2.setShardName("a");
+ shardIdentity2.setClusterId(OID::gen());
+
+ shardingState()->setGlobalInitMethodForTest(
+ [](OperationContext* txn, const ConnectionString& connStr) {
+ return Status{ErrorCodes::InternalError, "should not reach here"};
+ });
+
+ auto status = shardingState()->initializeFromShardIdentity(txn(), shardIdentity2);
+ ASSERT_EQ(ErrorCodes::InconsistentShardIdentity, status);
+
+ ASSERT_TRUE(shardingState()->enabled());
+ ASSERT_EQ("a", shardingState()->getShardName());
+ ASSERT_EQ("config/a:1,b:2", shardingState()->getConfigServer(txn()).toString());
+}
+
+} // unnamed namespace
+} // namespace mongo
diff --git a/src/mongo/db/service_context_noop.h b/src/mongo/db/service_context_noop.h
index 62e6a169896..a5dc54909f8 100644
--- a/src/mongo/db/service_context_noop.h
+++ b/src/mongo/db/service_context_noop.h
@@ -26,6 +26,8 @@
* it in the license file.
*/
+#pragma once
+
#include "mongo/db/service_context.h"
#include "mongo/platform/atomic_word.h"
diff --git a/src/mongo/s/grid.cpp b/src/mongo/s/grid.cpp
index b2d98d25f6a..d584b87c0c5 100644
--- a/src/mongo/s/grid.cpp
+++ b/src/mongo/s/grid.cpp
@@ -76,7 +76,6 @@ void Grid::advanceConfigOpTime(repl::OpTime opTime) {
}
}
-// Note: shardRegistry->shutdown() must be called before this method is called.
void Grid::clearForUnitTests() {
_catalogManager.reset();
_catalogCache.reset();
diff --git a/src/mongo/s/grid.h b/src/mongo/s/grid.h
index 4e0fa38728b..1db22f630e8 100644
--- a/src/mongo/s/grid.h
+++ b/src/mongo/s/grid.h
@@ -102,6 +102,8 @@ public:
* be necessary if grid is hanging off the global ServiceContext and each test gets its
* own service context.
*
+ * Note: shardRegistry()->shutdown() must be called before this method is called.
+ *
* NOTE: Do not use this outside of unit-tests.
*/
void clearForUnitTests();
diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js
index 9fc699a1ca1..147d5204b53 100644
--- a/src/mongo/shell/replsettest.js
+++ b/src/mongo/shell/replsettest.js
@@ -47,7 +47,6 @@
* useSeedList {boolean}: Use the connection string format of this set
* as the replica set name (overrides the name property). Default: false
* keyFile {string}
- * shardSvr {boolean}: Whether this replica set serves as a shard in a cluster. Default: false.
* protocolVersion {number}: protocol version of replset used by the replset initiation.
*
* useBridge {boolean}: If true, then a mongobridge process is started for each node in the
@@ -1173,7 +1172,6 @@ var ReplSetTest = function(opts) {
self.oplogSize = opts.oplogSize || 40;
self.useSeedList = opts.useSeedList || false;
self.keyFile = opts.keyFile;
- self.shardSvr = opts.shardSvr || false;
self.protocolVersion = opts.protocolVersion;
_useBridge = opts.useBridge || false;
diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js
index 7f264dded30..f2526b0b709 100644
--- a/src/mongo/shell/shardingtest.js
+++ b/src/mongo/shell/shardingtest.js
@@ -1053,6 +1053,7 @@ var ShardingTest = function(params) {
useHostname: otherParams.useHostname,
noJournalPrealloc: otherParams.nopreallocj,
oplogSize: 16,
+ shardsvr: '',
pathOpts: Object.merge(pathOpts, {shard: i})
};
@@ -1076,8 +1077,7 @@ var ShardingTest = function(params) {
useBridge: otherParams.useBridge,
bridgeOptions: otherParams.bridgeOptions,
keyFile: keyFile,
- protocolVersion: protocolVersion,
- shardSvr: true
+ protocolVersion: protocolVersion
});
this._rs[i] = {
@@ -1104,6 +1104,7 @@ var ShardingTest = function(params) {
noJournalPrealloc: otherParams.nopreallocj,
pathOpts: Object.merge(pathOpts, {shard: i}),
dbpath: "$testName$shard",
+ shardsvr: '',
keyFile: keyFile
};