diff options
-rw-r--r-- | buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml | 1 | ||||
-rw-r--r-- | buildscripts/resmokeconfig/suites/sharding_last_stable_mongos.yml | 2 | ||||
-rw-r--r-- | jstests/sharding/min_optime_recovery.js | 94 | ||||
-rw-r--r-- | jstests/sharding/shard_aware_on_add_shard.js | 56 | ||||
-rw-r--r-- | jstests/sharding/shard_identity_config_update.js | 15 | ||||
-rw-r--r-- | jstests/sharding/sharding_state_after_stepdown.js | 160 | ||||
-rw-r--r-- | jstests/sharding/startup_with_all_configs_down.js | 9 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/s/type_shard_identity.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/s/type_shard_identity.h | 10 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp | 95 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set.h | 8 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set_add_shard_test.cpp | 120 | ||||
-rw-r--r-- | src/mongo/s/client/shard_registry.cpp | 10 | ||||
-rw-r--r-- | src/mongo/s/client/shard_registry.h | 11 |
16 files changed, 288 insertions, 338 deletions
diff --git a/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml b/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml index d7c91283678..ef52c8a5ea7 100644 --- a/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml +++ b/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml @@ -96,6 +96,7 @@ selector: - jstests/sharding/startup_with_all_configs_down.js - jstests/sharding/lagged_config_secondary.js - jstests/sharding/autodiscover_config_rs_from_secondary.js + - jstests/sharding/sharding_state_after_stepdown.js - jstests/sharding/rs_stepdown_and_pooling.js - jstests/sharding/mongos_no_replica_set_refresh.js - jstests/sharding/primary_config_server_blackholed_from_mongos.js diff --git a/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos.yml b/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos.yml index 0e8c3f150ff..e92c1d84fbc 100644 --- a/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos.yml +++ b/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos.yml @@ -7,9 +7,7 @@ selector: - jstests/sharding/error_propagation.js # New features for v3.4 - jstests/sharding/shard_aware_init.js - - jstests/sharding/shard_aware_on_add_shard.js - jstests/sharding/shard_aware_primary_failover.js - - jstests/sharding/shard_identity_config_update.js # v3.4 changes $in shard key extraction. - jstests/sharding/upsert_sharded.js - jstests/sharding/update_sharded.js diff --git a/jstests/sharding/min_optime_recovery.js b/jstests/sharding/min_optime_recovery.js index 4f8595feb69..69ccc78f02c 100644 --- a/jstests/sharding/min_optime_recovery.js +++ b/jstests/sharding/min_optime_recovery.js @@ -1,37 +1,85 @@ /** - * Tests that the minOpTimeRecovery document will be created after a migration. + * Basic testing for minOpTimeRecovery document. Tests that it will be created after a migration + * only if the config server is a replica set and recovery will not run when disabled. + * + * This test restarts a shard and the shard will attempt to read a document that was saved before + * the restart, so it cannot be run on ephemeral storage engines. + * @tags: [requires_persistence] */ (function() { "use strict"; - var st = new ShardingTest({shards: 2}); + var runTest = function(withRecovery) { + var st = new ShardingTest({shards: 2}); - var testDB = st.s.getDB('test'); - testDB.adminCommand({enableSharding: 'test'}); - st.ensurePrimaryShard('test', 'shard0000'); - testDB.adminCommand({shardCollection: 'test.user', key: {x: 1}}); + var testDB = st.s.getDB('test'); + testDB.adminCommand({enableSharding: 'test'}); + st.ensurePrimaryShard('test', 'shard0000'); + testDB.adminCommand({shardCollection: 'test.user', key: {x: 1}}); - var priConn = st.configRS.getPrimary(); - var replStatus = priConn.getDB('admin').runCommand({replSetGetStatus: 1}); - replStatus.members.forEach(function(memberState) { - if (memberState.state == 1) { // if primary - assert.neq(null, memberState.optime); - assert.neq(null, memberState.optime.ts); - assert.neq(null, memberState.optime.t); + var opTimeBeforeMigrate = null; + if (st.configRS) { + var priConn = st.configRS.getPrimary(); + var replStatus = priConn.getDB('admin').runCommand({replSetGetStatus: 1}); + replStatus.members.forEach(function(memberState) { + if (memberState.state == 1) { // if primary + opTimeBeforeMigrate = memberState.optime; + + assert.neq(null, opTimeBeforeMigrate); + assert.neq(null, opTimeBeforeMigrate.ts); + assert.neq(null, opTimeBeforeMigrate.t); + } + }); + } + + testDB.adminCommand({moveChunk: 'test.user', find: {x: 0}, to: 'shard0001'}); + + var shardAdmin = st.d0.getDB('admin'); + var doc = shardAdmin.system.version.findOne(); + + if (st.configRS) { + assert.neq(null, doc); + assert.eq('minOpTimeRecovery', doc._id); + assert.eq(st.configRS.getURL(), doc.configsvrConnectionString); + assert.eq('shard0000', doc.shardName); + assert.gt(doc.minOpTime.ts.getTime(), 0); + } else { + assert.eq(null, doc); } - }); - testDB.adminCommand({moveChunk: 'test.user', find: {x: 0}, to: 'shard0001'}); + var restartCmdLineOptions = Object.merge(st.d0.fullOptions, { + setParameter: 'recoverShardingState=' + (withRecovery ? 'true' : 'false'), + restart: true + }); - var shardAdmin = st.d0.getDB('admin'); - var minOpTimeRecoveryDoc = shardAdmin.system.version.findOne({_id: 'minOpTimeRecovery'}); + // Restart the shard that donated a chunk to trigger the optime recovery logic. + st.stopMongod(0); + var newMongod = MongoRunner.runMongod(restartCmdLineOptions); + var shardingSection = newMongod.getDB('admin').runCommand({serverStatus: 1}).sharding; + + if (st.configRS && withRecovery) { + assert.neq(null, shardingSection); + + // Confirm that the config server string points to an actual config server replica set. + var configConnStr = shardingSection.configsvrConnectionString; + var configConn = new Mongo(configConnStr); + var configIsMaster = configConn.getDB('admin').runCommand({isMaster: 1}); + assert.gt(configConnStr.indexOf('/'), 0); + assert.eq(1, configIsMaster.configsvr); // If it's a shard, this field won't exist. + + var configOpTimeObj = shardingSection.lastSeenConfigServerOpTime; + assert.neq(null, configOpTimeObj); + assert.gte(configOpTimeObj.ts.getTime(), opTimeBeforeMigrate.ts.getTime()); + assert.gte(configOpTimeObj.t, opTimeBeforeMigrate.t); + } else { + assert.eq(null, shardingSection); + } - assert.neq(null, minOpTimeRecoveryDoc); - assert.eq('minOpTimeRecovery', minOpTimeRecoveryDoc._id); - assert.eq(st.configRS.getURL(), minOpTimeRecoveryDoc.configsvrConnectionString); - assert.eq('shard0000', minOpTimeRecoveryDoc.shardName); - assert.gt(minOpTimeRecoveryDoc.minOpTime.ts.getTime(), 0); + MongoRunner.stopMongod(newMongod.port); + st.stop(); + }; - st.stop(); + runTest(true); + runTest(false); })(); diff --git a/jstests/sharding/shard_aware_on_add_shard.js b/jstests/sharding/shard_aware_on_add_shard.js deleted file mode 100644 index a616f03bcc3..00000000000 --- a/jstests/sharding/shard_aware_on_add_shard.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Tests that the addShard process initializes sharding awareness on an added standalone or - * replica set shard that was started with --shardsvr. - */ - -(function() { - "use strict"; - - var waitForIsMaster = function(conn) { - assert.soon(function() { - var res = conn.getDB('admin').runCommand({isMaster: 1}); - return res.ismaster; - }); - }; - - var checkShardingStateInitialized = function(conn, configConnStr, shardName) { - var res = conn.getDB('admin').runCommand({shardingState: 1}); - assert.commandWorked(res); - assert(res.enabled); - assert.eq(configConnStr, res.configServer); - assert.eq(shardName, res.shardName); - // TODO SERVER-23096: How should the clusterId be obtained externally? - // assert.eq(clusterId, res.clusterId); - }; - - // Create the cluster to test adding shards to. - var st = new ShardingTest({shards: 1}); - - // Add a shard that is a standalone mongod. - - var standaloneConn = MongoRunner.runMongod({shardsvr: ''}); - waitForIsMaster(standaloneConn); - - jsTest.log("Going to add standalone as shard: " + standaloneConn); - var newShardName = "newShard"; - assert.commandWorked(st.s.adminCommand({addShard: standaloneConn.name, name: newShardName})); - checkShardingStateInitialized(standaloneConn, st.configRS.getURL(), newShardName); - - MongoRunner.stopMongod(standaloneConn.port); - - // Add a shard that is a replica set. - - var replTest = new ReplSetTest({nodes: 1}); - replTest.startSet({shardsvr: ''}); - replTest.initiate(); - waitForIsMaster(replTest.getPrimary()); - - jsTest.log("Going to add replica set as shard: " + replTest); - assert.commandWorked(st.s.adminCommand({addShard: replTest.getURL(), name: replTest.getURL()})); - checkShardingStateInitialized(replTest.getPrimary(), st.configRS.getURL(), replTest.getURL()); - - replTest.stopSet(); - - st.stop(); - -})(); diff --git a/jstests/sharding/shard_identity_config_update.js b/jstests/sharding/shard_identity_config_update.js index 6d3b01deb41..678a04c79fa 100644 --- a/jstests/sharding/shard_identity_config_update.js +++ b/jstests/sharding/shard_identity_config_update.js @@ -10,7 +10,22 @@ var st = new ShardingTest({shards: {rs0: {nodes: 2}}}); + // TODO: remove crutch once all node shard aware is complete. + var setupShardIdentity = function(conn, configConnStr) { + var shardIdentityDoc = { + _id: 'shardIdentity', + configsvrConnectionString: configConnStr, + shardName: 'newShard', + clusterId: ObjectId() + }; + + var res = conn.getDB('admin').system.version.update( + {_id: 'shardIdentity'}, shardIdentityDoc, true); + assert.eq(1, res.nUpserted); + }; + var shardPri = st.rs0.getPrimary(); + setupShardIdentity(st.rs0.getPrimary(), st.configRS.getURL()); // Note: Adding new replica set member by hand because of SERVER-24011. diff --git a/jstests/sharding/sharding_state_after_stepdown.js b/jstests/sharding/sharding_state_after_stepdown.js new file mode 100644 index 00000000000..6bd2f4927cc --- /dev/null +++ b/jstests/sharding/sharding_state_after_stepdown.js @@ -0,0 +1,160 @@ +// Tests the state of sharding data after a replica set reconfig +// +// This test involves restarting a single-node replica set, so cannot be run on ephemeral storage +// engines. A single node replica set that is using an ephemeral engine will have no knowledge of +// the replica set configuration once restarted, so will not elect itself as primary. +// @tags: [requires_persistence] + +(function() { + 'use strict'; + + var st = new ShardingTest({shards: 2, mongos: 1, other: {rs: true, rsOptions: {nodes: 1}}}); + + var mongos = st.s0; + var admin = mongos.getDB("admin"); + var shards = mongos.getCollection("config.shards").find().toArray(); + + var coll = mongos.getCollection("foo.bar"); + var collSharded = mongos.getCollection("foo.barSharded"); + + assert.commandWorked(admin.runCommand({enableSharding: coll.getDB() + ""})); + st.ensurePrimaryShard(coll.getDB() + "", shards[0]._id); + assert.commandWorked( + admin.runCommand({shardCollection: collSharded.toString(), key: {_id: 1}})); + assert.commandWorked( + admin.runCommand({moveChunk: collSharded.toString(), find: {_id: 0}, to: shards[1]._id})); + + assert.writeOK(coll.insert({some: "data"})); + assert.writeOK(collSharded.insert({some: "data"})); + assert.eq(2, mongos.adminCommand({getShardVersion: collSharded.toString()}).version.t); + + st.printShardingStatus(); + + // Restart both primaries to reset our sharding data + var restartPrimaries = function() { + var rs0Primary = st.rs0.getPrimary(); + var rs1Primary = st.rs1.getPrimary(); + + st.rs0.stop(rs0Primary); + st.rs1.stop(rs1Primary); + + ReplSetTest.awaitRSClientHosts(mongos, [rs0Primary, rs1Primary], {ok: false}); + + 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], {ismaster: true}); + }; + + restartPrimaries(); + + // Sharding data gets initialized either when shards are hit by an unsharded query or if some + // metadata operation was run before the step down, which wrote a minOpTime recovery record + // (CSRS + // only). In this case we did a moveChunk above from shard0 to shard1, so we will have this + // record + // on shard0. + if (st.configRS) { + assert.neq( + "", st.rs0.getPrimary().adminCommand({getShardVersion: coll.toString()}).configServer); + } else { + assert.eq( + "", st.rs0.getPrimary().adminCommand({getShardVersion: coll.toString()}).configServer); + } + assert.eq("", + st.rs1.getPrimary().adminCommand({getShardVersion: coll.toString()}).configServer); + + // Doing a find only accesses the primary (rs0), which is already recovered. Ensure that the + // secondary still has no sharding knowledge. + assert.neq(null, coll.findOne({})); + assert.eq("", + st.rs1.getPrimary().adminCommand({getShardVersion: coll.toString()}).configServer); + + // + // + // Sharding data initialized when shards are hit by a sharded query + assert.neq(null, collSharded.findOne({})); + assert.neq("", + st.rs0.getPrimary().adminCommand({getShardVersion: coll.toString()}).configServer); + assert.neq("", + st.rs1.getPrimary().adminCommand({getShardVersion: coll.toString()}).configServer); + + // Stepdown both primaries to reset our sharding data + var stepDownPrimaries = function() { + + var rs0Primary = st.rs0.getPrimary(); + var rs1Primary = st.rs1.getPrimary(); + + try { + rs0Primary.adminCommand({replSetStepDown: 1000 * 1000, force: true}); + assert(false); + } catch (ex) { + // Expected connection exception, will check for stepdown later + } + + try { + rs1Primary.adminCommand({replSetStepDown: 1000 * 1000, force: true}); + assert(false); + } catch (ex) { + // Expected connection exception, will check for stepdown later + } + + ReplSetTest.awaitRSClientHosts(mongos, [rs0Primary, rs1Primary], {secondary: true}); + + assert.commandWorked(new Mongo(rs0Primary.host).adminCommand({replSetFreeze: 0})); + assert.commandWorked(new Mongo(rs1Primary.host).adminCommand({replSetFreeze: 0})); + + rs0Primary = st.rs0.getPrimary(); + rs1Primary = st.rs1.getPrimary(); + + // Flush connections to avoid transient issues with conn pooling + assert.commandWorked(rs0Primary.adminCommand({connPoolSync: true})); + assert.commandWorked(rs1Primary.adminCommand({connPoolSync: true})); + + ReplSetTest.awaitRSClientHosts(mongos, [rs0Primary, rs1Primary], {ismaster: true}); + }; + + stepDownPrimaries(); + + // + // + // No sharding metadata until shards are hit by a metadata operation + assert.eq({}, + st.rs0.getPrimary() + .adminCommand({getShardVersion: collSharded.toString(), fullMetadata: true}) + .metadata); + assert.eq({}, + st.rs1.getPrimary() + .adminCommand({getShardVersion: collSharded.toString(), fullMetadata: true}) + .metadata); + + // + // + // Metadata commands should enable sharding data implicitly + assert.commandWorked(mongos.adminCommand({split: collSharded.toString(), middle: {_id: 0}})); + assert.eq({}, + st.rs0.getPrimary() + .adminCommand({getShardVersion: collSharded.toString(), fullMetadata: true}) + .metadata); + assert.neq({}, + st.rs1.getPrimary() + .adminCommand({getShardVersion: collSharded.toString(), fullMetadata: true}) + .metadata); + + // + // + // MoveChunk command should enable sharding data implicitly on TO-shard + assert.commandWorked(mongos.adminCommand( + {moveChunk: collSharded.toString(), find: {_id: 0}, to: shards[0]._id})); + assert.neq({}, + st.rs0.getPrimary() + .adminCommand({getShardVersion: collSharded.toString(), fullMetadata: true}) + .metadata); + assert.neq({}, + st.rs1.getPrimary() + .adminCommand({getShardVersion: collSharded.toString(), fullMetadata: true}) + .metadata); + + st.stop(); + +})(); diff --git a/jstests/sharding/startup_with_all_configs_down.js b/jstests/sharding/startup_with_all_configs_down.js index a85c9595bea..32609a04484 100644 --- a/jstests/sharding/startup_with_all_configs_down.js +++ b/jstests/sharding/startup_with_all_configs_down.js @@ -11,10 +11,9 @@ /** * Restarts the mongod backing the specified shard instance, without restarting the mongobridge. */ - function restartShard(shard, waitForConnect) { + function restartShard(shard) { MongoRunner.stopMongod(shard); shard.restart = true; - shard.waitForConnect = waitForConnect; MongoRunner.runMongod(shard); } @@ -51,7 +50,7 @@ }); jsTestLog("Restarting a shard while there are no config servers up"); - restartShard(st.shard1, false); + restartShard(st.shard1); jsTestLog("Queries should fail because the shard can't initialize sharding state"); var error = assert.throws(function() { @@ -68,8 +67,8 @@ // TODO: SERVER-23192 - restart all shards and mongos because their replica set monitor has // deemed the CSRS config server set as unusable. - restartShard(st.shard0, true); - restartShard(st.shard1, true); + restartShard(st.shard0); + restartShard(st.shard1); st.restartMongos(0); jsTestLog("Queries against the original mongos should work again"); diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index 6252977d62e..c622e482fc7 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -64,7 +64,6 @@ env.Library( '$BUILD_DIR/mongo/bson/util/bson_extract', '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/s/sharding_initialization', - '$BUILD_DIR/mongo/s/write_ops/batch_write_types', 'metadata', 'migration_types', 'type_shard_identity', @@ -124,7 +123,6 @@ env.CppUnitTest( 'type_shard_identity_test.cpp' ], LIBDEPS=[ - '$BUILD_DIR/mongo/s/write_ops/batch_write_types', 'type_shard_identity', ] ) diff --git a/src/mongo/db/s/type_shard_identity.cpp b/src/mongo/db/s/type_shard_identity.cpp index d34f4975cfa..7ef675ad334 100644 --- a/src/mongo/db/s/type_shard_identity.cpp +++ b/src/mongo/db/s/type_shard_identity.cpp @@ -32,8 +32,6 @@ #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/util/bson_extract.h" -#include "mongo/s/write_ops/batched_update_document.h" -#include "mongo/s/write_ops/batched_update_request.h" #include "mongo/util/assert_util.h" namespace mongo { @@ -136,10 +134,7 @@ Status ShardIdentityType::validate() const { return {ErrorCodes::NoSuchKey, str::stream() << "missing " << shardName() << " field"}; } - // TODO SERVER-23096: Once ShardRegistry::_clusterId is loaded from the config servers rather - // than initialized in the ShardRegistry constructor in each process, the isSet() check can - // be re-added. - if (!_clusterId /*|| !_clusterId->isSet()*/) { + if (!_clusterId || _clusterId->isSet()) { return {ErrorCodes::NoSuchKey, str::stream() << "missing " << clusterId() << " field"}; } @@ -209,31 +204,6 @@ void ShardIdentityType::setClusterId(OID clusterId) { _clusterId = std::move(clusterId); } -std::unique_ptr<BatchedUpdateRequest> ShardIdentityType::createUpsertForAddShard() const { - invariant(validate().isOK()); - - std::unique_ptr<BatchedUpdateDocument> updateDoc(new BatchedUpdateDocument()); - - BSONObjBuilder query; - query.append("_id", "shardIdentity"); - query.append("shardName", getShardName()); - query.append("clusterId", getClusterId()); - updateDoc->setQuery(query.obj()); - - BSONObjBuilder update; - BSONObjBuilder setConfigBuilder(update.subobjStart("$set")); - setConfigBuilder.append(configsvrConnString(), getConfigsvrConnString().toString()); - setConfigBuilder.doneFast(); - updateDoc->setUpdateExpr(update.obj()); - - updateDoc->setUpsert(true); - - std::unique_ptr<BatchedUpdateRequest> updateRequest(new BatchedUpdateRequest()); - updateRequest->addToUpdates(updateDoc.release()); - - return updateRequest; -} - BSONObj ShardIdentityType::createConfigServerUpdateObject(const std::string& newConnString) { BSONObjBuilder builder; BSONObjBuilder setConfigBuilder(builder.subobjStart("$set")); diff --git a/src/mongo/db/s/type_shard_identity.h b/src/mongo/db/s/type_shard_identity.h index 9c51913fe0f..30e2c832dff 100644 --- a/src/mongo/db/s/type_shard_identity.h +++ b/src/mongo/db/s/type_shard_identity.h @@ -32,7 +32,6 @@ #include "mongo/client/connection_string.h" #include "mongo/db/jsobj.h" -#include "mongo/s/write_ops/batched_update_request.h" namespace mongo { @@ -41,8 +40,6 @@ namespace mongo { */ class ShardIdentityType { public: - ShardIdentityType() = default; - // The _id value for this document type. static const std::string IdName; @@ -81,13 +78,6 @@ public: void setClusterId(OID clusterId); /** - * Returns an update object that can be used to insert a shardIdentity doc on a shard or update - * the existing shardIdentity doc's configsvrConnString (if the _id, shardName, and clusterId - * match those in this ShardIdentityType instance). - */ - std::unique_ptr<BatchedUpdateRequest> createUpsertForAddShard() const; - - /** * Returns an update object that can be used to update the config server field of the * shardIdentity document with the new connection string. */ diff --git a/src/mongo/s/catalog/replset/SConscript b/src/mongo/s/catalog/replset/SConscript index 3d482b50403..582b9a26aea 100644 --- a/src/mongo/s/catalog/replset/SConscript +++ b/src/mongo/s/catalog/replset/SConscript @@ -66,7 +66,6 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/repl/read_concern_args', - '$BUILD_DIR/mongo/db/s/type_shard_identity', '$BUILD_DIR/mongo/executor/network_interface', '$BUILD_DIR/mongo/s/catalog/dist_lock_manager', '$BUILD_DIR/mongo/s/client/sharding_client', diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp index 8237359140e..3c9b7ce9809 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp @@ -49,7 +49,6 @@ #include "mongo/db/operation_context.h" #include "mongo/db/repl/optime.h" #include "mongo/db/repl/read_concern_args.h" -#include "mongo/db/s/type_shard_identity.h" #include "mongo/executor/network_interface.h" #include "mongo/executor/task_executor.h" #include "mongo/rpc/get_status_from_command_result.h" @@ -198,10 +197,9 @@ StatusWith<ShardType> CatalogManagerReplicaSet::_validateHostAsShard( // Check for mongos and older version mongod connections, and whether the hosts // can be found for the user specified replset. - auto swCommandResponse = - _runCommandForAddShard(txn, targeter.get(), "admin", BSON("isMaster" << 1)); - if (!swCommandResponse.isOK()) { - if (swCommandResponse.getStatus() == ErrorCodes::RPCProtocolNegotiationFailed) { + auto cmdStatus = _runCommandForAddShard(txn, targeter.get(), "admin", BSON("isMaster" << 1)); + if (!cmdStatus.isOK()) { + if (cmdStatus == ErrorCodes::RPCProtocolNegotiationFailed) { // Mongos to mongos commands are no longer supported in the wire protocol // (because mongos does not support OP_COMMAND), similarly for a new mongos // and an old mongod. So the call will fail in such cases. @@ -213,20 +211,19 @@ StatusWith<ShardType> CatalogManagerReplicaSet::_validateHostAsShard( << " likely because it contains a node that is a mongos or an old" << " version of mongod."}; } else { - return swCommandResponse.getStatus(); + return cmdStatus.getStatus(); } } // Check for a command response error - auto resIsMasterStatus = std::move(swCommandResponse.getValue().commandStatus); + BSONObj resIsMaster = cmdStatus.getValue(); + Status resIsMasterStatus = getStatusFromCommandResult(resIsMaster); if (!resIsMasterStatus.isOK()) { return {resIsMasterStatus.code(), str::stream() << "Error running isMaster against " << shardConn->toString() << ": " << causedBy(resIsMasterStatus)}; } - auto resIsMaster = std::move(swCommandResponse.getValue().response); - // Check whether there is a master. If there isn't, the replica set may not have been // initiated. If the connection is a standalone, it will return true for isMaster. bool isMaster; @@ -353,18 +350,18 @@ StatusWith<std::vector<std::string>> CatalogManagerReplicaSet::_getDBNamesListFr shardRegistry->createConnection(connectionString).release()}; invariant(shardConn); - auto swCommandResponse = _runCommandForAddShard( + auto cmdStatus = _runCommandForAddShard( txn, shardConn->getTargeter().get(), "admin", BSON("listDatabases" << 1)); - if (!swCommandResponse.isOK()) { - return swCommandResponse.getStatus(); - } - - auto cmdStatus = std::move(swCommandResponse.getValue().commandStatus); if (!cmdStatus.isOK()) { - return cmdStatus; + return cmdStatus.getStatus(); } - auto cmdResult = std::move(swCommandResponse.getValue().response); + const BSONObj& cmdResult = cmdStatus.getValue(); + + Status cmdResultStatus = getStatusFromCommandResult(cmdResult); + if (!cmdResultStatus.isOK()) { + return cmdResultStatus; + } vector<string> dbNames; @@ -411,7 +408,7 @@ void CatalogManagerReplicaSet::shutDown(OperationContext* txn) { _executorForAddShard->join(); } -StatusWith<Shard::CommandResponse> CatalogManagerReplicaSet::_runCommandForAddShard( +StatusWith<BSONObj> CatalogManagerReplicaSet::_runCommandForAddShard( OperationContext* txn, RemoteCommandTargeter* targeter, const std::string& dbName, @@ -424,12 +421,12 @@ StatusWith<Shard::CommandResponse> CatalogManagerReplicaSet::_runCommandForAddSh executor::RemoteCommandRequest request( host.getValue(), dbName, cmdObj, rpc::makeEmptyMetadata(), Seconds(30)); - StatusWith<executor::RemoteCommandResponse> swResponse = + StatusWith<executor::RemoteCommandResponse> responseStatus = Status(ErrorCodes::InternalError, "Internal error running command"); auto callStatus = _executorForAddShard->scheduleRemoteCommand( - request, [&swResponse](const executor::TaskExecutor::RemoteCommandCallbackArgs& args) { - swResponse = args.response; + request, [&responseStatus](const executor::TaskExecutor::RemoteCommandCallbackArgs& args) { + responseStatus = args.response; }); if (!callStatus.isOK()) { return callStatus.getStatus(); @@ -438,22 +435,11 @@ StatusWith<Shard::CommandResponse> CatalogManagerReplicaSet::_runCommandForAddSh // Block until the command is carried out _executorForAddShard->wait(callStatus.getValue()); - if (!swResponse.isOK()) { - if (swResponse.getStatus().compareCode(ErrorCodes::ExceededTimeLimit)) { - LOG(0) << "Operation for addShard timed out with status " << swResponse.getStatus(); - } - return swResponse.getStatus(); + if (!responseStatus.isOK()) { + return responseStatus.getStatus(); } - BSONObj responseObj = swResponse.getValue().data.getOwned(); - BSONObj responseMetadata = swResponse.getValue().metadata.getOwned(); - Status commandStatus = getStatusFromCommandResult(responseObj); - Status writeConcernStatus = getWriteConcernStatusFromCommandResult(responseObj); - - return Shard::CommandResponse(std::move(responseObj), - std::move(responseMetadata), - std::move(commandStatus), - std::move(writeConcernStatus)); + return responseStatus.getValue().data.getOwned(); } StatusWith<string> CatalogManagerReplicaSet::addShard(OperationContext* txn, @@ -511,44 +497,7 @@ StatusWith<string> CatalogManagerReplicaSet::addShard(OperationContext* txn, shardType.setMaxSizeMB(maxSize); } - ShardIdentityType shardIdentity; - shardIdentity.setConfigsvrConnString( - Grid::get(txn)->shardRegistry()->getConfigServerConnectionString()); - shardIdentity.setShardName(shardType.getName()); - shardIdentity.setClusterId(Grid::get(txn)->shardRegistry()->getClusterId()); - auto validateStatus = shardIdentity.validate(); - if (!validateStatus.isOK()) { - return validateStatus; - } - - log() << "going to insert shardIdentity document into shard: " << shardIdentity.toString(); - - auto updateRequest = shardIdentity.createUpsertForAddShard(); - BatchedCommandRequest commandRequest(updateRequest.release()); - commandRequest.setNS(NamespaceString::kConfigCollectionNamespace); - commandRequest.setWriteConcern(kMajorityWriteConcern.toBSON()); - - const std::shared_ptr<Shard> shardConn{ - Grid::get(txn)->shardRegistry()->createConnection(shardConnectionString)}; - invariant(shardConn); - auto targeter = shardConn->getTargeter(); - - auto swCommandResponse = - _runCommandForAddShard(txn, targeter.get(), "admin", commandRequest.toBSON()); - - if (!swCommandResponse.isOK()) { - return swCommandResponse.getStatus(); - } - - auto commandResponse = std::move(swCommandResponse.getValue()); - - BatchedCommandResponse batchResponse; - auto batchResponseStatus = _processBatchWriteResponse(commandResponse, &batchResponse); - if (!batchResponseStatus.isOK()) { - return batchResponseStatus; - } - - log() << "going to insert new entry for shard into config.shards: " << shardType.toString(); + log() << "going to add shard: " << shardType.toString(); Status result = insertConfigDocument(txn, ShardType::ConfigNS, shardType.toBSON()); if (!result.isOK()) { diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set.h b/src/mongo/s/catalog/replset/catalog_manager_replica_set.h index a26bf941ab2..b7251dc2a37 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set.h +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set.h @@ -276,10 +276,10 @@ private: * Runs a command against a "shard" that is not yet in the cluster and thus not present in the * ShardRegistry. */ - StatusWith<Shard::CommandResponse> _runCommandForAddShard(OperationContext* txn, - RemoteCommandTargeter* targeter, - const std::string& dbName, - const BSONObj& cmdObj); + StatusWith<BSONObj> _runCommandForAddShard(OperationContext* txn, + RemoteCommandTargeter* targeter, + const std::string& dbName, + const BSONObj& cmdObj); StatusWith<repl::OpTimeWith<std::vector<BSONObj>>> _exhaustiveFindOnConfig( OperationContext* txn, diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set_add_shard_test.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set_add_shard_test.cpp index 5c3e1ccfb06..54f414c79cb 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set_add_shard_test.cpp +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set_add_shard_test.cpp @@ -32,12 +32,10 @@ #include <vector> -#include "mongo/client/connection_string.h" #include "mongo/client/remote_command_targeter_factory_mock.h" #include "mongo/client/remote_command_targeter_mock.h" #include "mongo/db/commands.h" #include "mongo/db/query/query_request.h" -#include "mongo/db/s/type_shard_identity.h" #include "mongo/rpc/metadata/repl_set_metadata.h" #include "mongo/rpc/metadata/server_selection_metadata.h" #include "mongo/s/catalog/replset/catalog_manager_replica_set.h" @@ -77,16 +75,7 @@ protected: CatalogManagerReplSetTestFixture::setUp(); getMessagingPort()->setRemote(HostAndPort("FakeRemoteClient:34567")); - - configTargeter()->setConnectionStringReturnValue(_configConnStr); - - _configHost = _configConnStr.getServers().front(); - configTargeter()->setFindHostReturnValue(_configHost); - - // TODO SERVER-23096: Change this to OID::gen() once clusterId is loaded from the config - // servers into the ShardRegistry instead of created by the ShardRegistry within each - // process. - _clusterId = OID(); + configTargeter()->setFindHostReturnValue(configHost); } /** @@ -138,77 +127,12 @@ protected: } /** - * Waits for a request for the shardIdentity document to be upserted into a shard from the - * config server on addShard. - */ - void expectShardIdentityUpsert(const HostAndPort& expectedHost, - const std::string& expectedShardName) { - - ShardIdentityType expectedShardIdentity; - expectedShardIdentity.setShardName(expectedShardName); - expectedShardIdentity.setClusterId(_clusterId); - expectedShardIdentity.setConfigsvrConnString(_configConnStr); - invariant(expectedShardIdentity.validate().isOK()); - - auto updateRequest = expectedShardIdentity.createUpsertForAddShard(); - expectUpdates(expectedHost, - NamespaceString(NamespaceString::kConfigCollectionNamespace), - updateRequest.get()); - } - - /** - * Waits for a set of batched updates and ensures that the host, namespace, and updates exactly - * match what's expected. Responds with a success status. - */ - void expectUpdates(const HostAndPort& expectedHost, - const NamespaceString& expectedNss, - BatchedUpdateRequest* expectedBatchedUpdates) { - onCommandForAddShard([&](const RemoteCommandRequest& request) { - - ASSERT_EQUALS(expectedHost, request.target); - - // Check that the db name in the request matches the expected db name. - ASSERT_EQUALS(expectedNss.db(), request.dbname); - - BatchedUpdateRequest actualBatchedUpdates; - std::string errmsg; - ASSERT_TRUE(actualBatchedUpdates.parseBSON(request.dbname, request.cmdObj, &errmsg)); - - // Check that the db and collection names in the BatchedUpdateRequest match the - // expected. - ASSERT_EQUALS(expectedNss, actualBatchedUpdates.getNS()); - - auto expectedUpdates = expectedBatchedUpdates->getUpdates(); - auto actualUpdates = actualBatchedUpdates.getUpdates(); - - ASSERT_EQUALS(expectedUpdates.size(), actualUpdates.size()); - - auto itExpected = expectedUpdates.begin(); - auto itActual = actualUpdates.begin(); - - for (; itActual != actualUpdates.end(); itActual++, itExpected++) { - ASSERT_EQ((*itExpected)->getUpsert(), (*itActual)->getUpsert()); - ASSERT_EQ((*itExpected)->getMulti(), (*itActual)->getMulti()); - ASSERT_EQ((*itExpected)->getQuery(), (*itActual)->getQuery()); - ASSERT_EQ((*itExpected)->getUpdateExpr(), (*itActual)->getUpdateExpr()); - } - - BatchedCommandResponse response; - response.setOk(true); - response.setNModified(1); - - return response.toBSON(); - }); - } - - - /** * Wait for a single update request and ensure that the items being updated exactly match the * expected items. Responds with a success status. */ void expectDatabaseUpdate(const DatabaseType& dbtExpected) { onCommand([this, &dbtExpected](const RemoteCommandRequest& request) { - ASSERT_EQ(request.target, _configHost); + ASSERT_EQ(request.target, configHost); ASSERT_EQUALS(BSON(rpc::kReplSetMetadataFieldName << 1), request.metadata); BatchedUpdateRequest actualBatchedUpdate; @@ -238,10 +162,10 @@ protected: */ void expectAddShardChangeLog(const std::string& shardName, const std::string& shardHost) { // Expect the change log collection to be created - expectChangeLogCreate(_configHost, BSON("ok" << 1)); + expectChangeLogCreate(configHost, BSON("ok" << 1)); // Expect the change log operation - expectChangeLogInsert(_configHost, + expectChangeLogInsert(configHost, network()->now(), "addShard", "", @@ -253,7 +177,7 @@ protected: // Do it twice when there is no response set because getDatabase retries if it can't // find a database onFindCommand([&](const RemoteCommandRequest& request) { - ASSERT_EQ(request.target, _configHost); + ASSERT_EQ(request.target, configHost); if (i == 0) { ASSERT_EQUALS(kReplSecondaryOkMetadata, request.metadata); } else if (i == 1) { @@ -281,11 +205,7 @@ protected: } } - const ConnectionString _configConnStr{ConnectionString::forReplicaSet( - "configRS", - {HostAndPort("host1:23456"), HostAndPort("host2:23456"), HostAndPort("host3:23456")})}; - HostAndPort _configHost; - OID _clusterId; + const HostAndPort configHost{HostAndPort("ConfigHost:23456")}; }; TEST_F(AddShardTest, Standalone) { @@ -330,10 +250,7 @@ TEST_F(AddShardTest, Standalone) { expectGetDatabase("TestDB1", boost::none); expectGetDatabase("TestDB2", boost::none); - // The shardIdentity doc inserted into the config.version collection on the shard. - expectShardIdentityUpsert(shardTarget, expectedShardName); - - // The shard doc inserted into the config.shards collection on the config server. + // The new shard is being inserted ShardType expectedShard; expectedShard.setName(expectedShardName); expectedShard.setHost("StandaloneHost:12345"); @@ -430,10 +347,7 @@ TEST_F(AddShardTest, StandaloneGenerateName) { return vector<BSONObj>{existingShard.toBSON()}; }); - // The shardIdentity doc inserted into the config.version collection on the shard. - expectShardIdentityUpsert(shardTarget, expectedShardName); - - // The shard doc inserted into the config.shards collection on the config server. + // The new shard is being inserted ShardType expectedShard; expectedShard.setName(expectedShardName); expectedShard.setHost(shardTarget.toString()); @@ -870,10 +784,6 @@ TEST_F(AddShardTest, ReAddExistingShard) { expectGetDatabase("shardDB", boost::none); - // The shardIdentity doc inserted into the config.version collection on the shard. - expectShardIdentityUpsert(shardTarget, expectedShardName); - - // The shard doc inserted into the config.shards collection on the config server. ShardType newShard; newShard.setName(expectedShardName); newShard.setMaxSizeMB(100); @@ -939,10 +849,6 @@ TEST_F(AddShardTest, SuccessfullyAddReplicaSet) { expectGetDatabase("shardDB", boost::none); - // The shardIdentity doc inserted into the config.version collection on the shard. - expectShardIdentityUpsert(shardTarget, expectedShardName); - - // The shard doc inserted into the config.shards collection on the config server. ShardType newShard; newShard.setName(expectedShardName); newShard.setMaxSizeMB(100); @@ -1000,10 +906,6 @@ TEST_F(AddShardTest, AddShardSucceedsEvenIfAddingDBsFromNewShardFails) { expectGetDatabase("shardDB", boost::none); - // The shardIdentity doc inserted into the config.version collection on the shard. - expectShardIdentityUpsert(shardTarget, expectedShardName); - - // The shard doc inserted into the config.shards collection on the config server. ShardType newShard; newShard.setName(expectedShardName); newShard.setMaxSizeMB(100); @@ -1020,7 +922,7 @@ TEST_F(AddShardTest, AddShardSucceedsEvenIfAddingDBsFromNewShardFails) { // Ensure that even if upserting the database discovered on the shard fails, the addShard // operation succeeds. onCommand([this, &shardDB](const RemoteCommandRequest& request) { - ASSERT_EQ(request.target, _configHost); + ASSERT_EQ(request.target, configHost); ASSERT_EQUALS(BSON(rpc::kReplSetMetadataFieldName << 1), request.metadata); BatchedUpdateRequest actualBatchedUpdate; @@ -1081,10 +983,6 @@ TEST_F(AddShardTest, ReplicaSetExtraHostsDiscovered) { expectListDatabases(shardTarget, {}); - // The shardIdentity doc inserted into the config.version collection on the shard. - expectShardIdentityUpsert(shardTarget, expectedShardName); - - // The shard doc inserted into the config.shards collection on the config server. ShardType newShard; newShard.setName(expectedShardName); newShard.setMaxSizeMB(100); diff --git a/src/mongo/s/client/shard_registry.cpp b/src/mongo/s/client/shard_registry.cpp index 11f0e7e7c2c..fb9339b660c 100644 --- a/src/mongo/s/client/shard_registry.cpp +++ b/src/mongo/s/client/shard_registry.cpp @@ -39,7 +39,6 @@ #include "mongo/client/connection_string.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/s/catalog/catalog_manager.h" -#include "mongo/s/catalog/type_config_version.h" #include "mongo/s/catalog/type_shard.h" #include "mongo/s/client/shard.h" #include "mongo/s/client/shard_connection.h" @@ -60,12 +59,9 @@ using std::string; using std::unique_ptr; using std::vector; -// TODO SERVER-23096: Initializing an empty _clusterId is a temporary hack. The _clusterId should -// be queried from the config servers on sharding initialization and passed to the ShardRegistry -// constructor. ShardRegistry::ShardRegistry(std::unique_ptr<ShardFactory> shardFactory, const ConnectionString& configServerCS) - : _shardFactory(std::move(shardFactory)), _clusterId(), _data() { + : _shardFactory(std::move(shardFactory)), _data() { _initConfigServerCS = configServerCS; } @@ -73,10 +69,6 @@ ConnectionString ShardRegistry::getConfigServerConnectionString() const { return getConfigShard()->getConnString(); } -const OID& ShardRegistry::getClusterId() const { - return _clusterId; -} - void ShardRegistry::rebuildConfigShard() { _data.rebuildConfigShard(_shardFactory.get()); invariant(_data.getConfigShard()); diff --git a/src/mongo/s/client/shard_registry.h b/src/mongo/s/client/shard_registry.h index df6605b5e73..89502ff507a 100644 --- a/src/mongo/s/client/shard_registry.h +++ b/src/mongo/s/client/shard_registry.h @@ -158,11 +158,6 @@ public: ConnectionString getConfigServerConnectionString() const; /** - * Returns the cluster id from the config shard. - */ - const OID& getClusterId() const; - - /** * Reloads the ShardRegistry based on the contents of the config server's config.shards * collection. Returns true if this call performed a reload and false if this call only waited * for another thread to perform the reload and did not actually reload. Because of this, it is @@ -246,12 +241,6 @@ private: */ ConnectionString _initConfigServerCS; - /** - * The id for the cluster, obtained from the config servers on sharding initialization. The - * config servers are the authority on the clusterId. - */ - const OID _clusterId; - ShardRegistryData _data; // Protects the _reloadState and _initConfigServerCS during startup. |