diff options
author | Randolph Tan <randolph@10gen.com> | 2016-03-23 17:32:02 -0400 |
---|---|---|
committer | Randolph Tan <randolph@10gen.com> | 2016-04-08 13:50:53 -0400 |
commit | bbaf069f100e86664b7795d097f0c802fe3965df (patch) | |
tree | 150693d456180395fa99672115417b48ca7485e9 | |
parent | 11132f69c93a279ebe7f0ccb71929d4cd2b8675d (diff) | |
download | mongo-bbaf069f100e86664b7795d097f0c802fe3965df.tar.gz |
SERVER-22661 Require --shardsvr for shard aware initialization
-rw-r--r-- | jstests/sharding/shard_aware_init.js | 58 | ||||
-rw-r--r-- | jstests/sharding/shard_aware_primary_failover.js | 2 | ||||
-rw-r--r-- | jstests/sharding/sharding_state_after_stepdown.js | 4 | ||||
-rw-r--r-- | src/mongo/client/replica_set_monitor.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 18 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state.h | 12 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state_recovery.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state_test.cpp | 359 | ||||
-rw-r--r-- | src/mongo/db/service_context_noop.h | 2 | ||||
-rw-r--r-- | src/mongo/s/grid.cpp | 1 | ||||
-rw-r--r-- | src/mongo/s/grid.h | 2 | ||||
-rw-r--r-- | src/mongo/shell/replsettest.js | 2 | ||||
-rw-r--r-- | src/mongo/shell/shardingtest.js | 5 |
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 }; |