diff options
author | Haley Connelly <haley.connelly@mongodb.com> | 2021-08-09 18:52:51 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-08-17 23:10:55 +0000 |
commit | 7853d994db8831e1f91e6c2a59cb01d26f1e6e45 (patch) | |
tree | 8d67c097599795b0df4c173cc790925b1eb1a9c9 | |
parent | 1ddb121d46d2fa14b2ec4c5a151f3f3ff0771a02 (diff) | |
download | mongo-7853d994db8831e1f91e6c2a59cb01d26f1e6e45.tar.gz |
SERVER-52728 Upgrade path from mongoDB 2.4 to 4.2 requires dropping ping_ index
-rw-r--r-- | jstests/multiVersion/upgrade_from_v24_ping_index_conflict.js | 92 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_initialization_mongod.cpp | 35 | ||||
-rw-r--r-- | src/mongo/shell/servers.js | 1 |
3 files changed, 128 insertions, 0 deletions
diff --git a/jstests/multiVersion/upgrade_from_v24_ping_index_conflict.js b/jstests/multiVersion/upgrade_from_v24_ping_index_conflict.js new file mode 100644 index 00000000000..3cc48b0155b --- /dev/null +++ b/jstests/multiVersion/upgrade_from_v24_ping_index_conflict.js @@ -0,0 +1,92 @@ +/** + * In v2.4, an index {ping: 1} named "ping_" was created on the config.lockpings collection. + * Starting in 4.2, creating an index identical to an existing index, but with a different name, is + * explicitly disallowed. + * + * Internally, modern mongods implicitly create an index on {ping: 1} named "ping_1" when stepping + * up to primary - conflicting with index naming restrictions that there cannot be 2 identical + * indexes with different names. + * + * Tests that upgrading a config server to v4.2 fails to start up and relays a message to drop the + * "ping_" index introduced in v2.4 before upgrade. + */ +(function() { +"use strict"; + +const cluster = new ShardingTest({ + shards: 2, + other: { + mongosOptions: {binVersion: "last-stable"}, + configOptions: { + binVersion: "last-stable", + }, + rsOptions: {binVersion: "last-stable"}, + }, + rs: {nodes: 3} +}); +const configRS = cluster.configRS; + +// Returns the 'config' database from the cluster's current primary config server. +const getConfigDB = function() { + return configRS.getPrimary().getDB("config"); +}; + +// Asserts that an index with indexName exists in on the config.lockpings collection. +const assertLockpingsHasIndex = function(indexName, configDB) { + const listIndexesResult = assert.commandWorked(configDB.runCommand({listIndexes: "lockpings"})); + + const containsIndex = listIndexesResult.cursor.firstBatch.reduce((acc, indexSpec) => { + return acc || indexSpec.name == indexName; + }, false); + + assert.eq(true, + containsIndex, + `Index with name ${indexName} does not exist: ${tojson(listIndexesResult)}`); +}; + +jsTest.log("Setting up collection to contain index 'ping_'"); +// Drop the implicitly created "ping_1" index to allow for the creation of the "ping_" +// index. +let configDB = getConfigDB(); +assert.commandWorked(configDB["lockpings"].dropIndex({ping: 1})); +assert.commandWorked( + configDB.runCommand({createIndexes: "lockpings", indexes: [{key: {ping: 1}, name: "ping_"}]})); +assertLockpingsHasIndex("ping_", configDB); + +jsTest.log("Testing secondary crashes on upgrade to 'latest' due to 'ping_' index"); +const secondary = configRS.getSecondary(); +try { + configRS.restart(secondary, {binVersion: "latest"}); +} catch (error) { + // Catch the error thrown when the secondary crashes during restart. +} +assert.soon(() => { + // Confirm the secondary crashed with the fatal assertion with instructions to drop the "ping_" + // index. + return rawMongoProgramOutput().search(/Fatal assertion 5272800/) != -1; +}); + +jsTest.log("Restarting secondary as 'last-stable' to drop 'ping_' index"); +// Before upgrading, user must drop the "ping_" index and await replication. +configRS.restart(secondary, {binVersion: "last-stable", allowedExitCode: MongoRunner.EXIT_ABORT}); +assert.commandWorked(configDB["lockpings"].dropIndex("ping_")); +configRS.awaitReplication(); + +jsTest.log("Testing rolling upgrade succeeds in absence of 'ping_' index"); +// First upgrade both secondaries. +const secondaries = configRS.getSecondaries(); +configRS.restart(secondaries[0], {binVersion: "latest"}); +configRS.restart(secondaries[1], {binVersion: "latest"}); + +// Step up a new primary before upgrading the existing primary. +const originalPrimary = configRS.getPrimary(); +configRS.getSecondary().adminCommand({replSetStepUp: 1}); +configRS.restart(originalPrimary, {binVersion: "latest"}); + +configRS.awaitNodesAgreeOnPrimary(); + +// The "ping_1" index should exist once an upgraded (v4.2) config server steps up to primary. +assertLockpingsHasIndex("ping_1", getConfigDB()); + +cluster.stop(); +})(); diff --git a/src/mongo/db/s/sharding_initialization_mongod.cpp b/src/mongo/db/s/sharding_initialization_mongod.cpp index 659997e7dc3..06617f93b2c 100644 --- a/src/mongo/db/s/sharding_initialization_mongod.cpp +++ b/src/mongo/db/s/sharding_initialization_mongod.cpp @@ -38,6 +38,7 @@ #include "mongo/client/remote_command_targeter.h" #include "mongo/client/remote_command_targeter_factory_impl.h" #include "mongo/client/replica_set_monitor.h" +#include "mongo/db/catalog/index_catalog.h" #include "mongo/db/catalog_raii.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/dbhelpers.h" @@ -55,6 +56,7 @@ #include "mongo/db/server_options.h" #include "mongo/executor/task_executor_pool.h" #include "mongo/rpc/metadata/egress_metadata_hook_list.h" +#include "mongo/s/catalog/type_lockpings.h" #include "mongo/s/catalog_cache.h" #include "mongo/s/client/shard_connection.h" #include "mongo/s/client/shard_factory.h" @@ -138,6 +140,35 @@ private: ServiceContext* _serviceContext; }; +// In v2.4, an index on {ping: 1} with index name "ping_" was created on the config.lockpings +// collection due to a bug. The existence of "ping_" clashes with an identical index with a +// different name, "ping_1", that is created internally when a secondary steps up to primary. +// +// If the "ping_" index exists, fatally prevent nodes from upgrading until the index is dropped. +void assertLegacyPingIndexDoesNotExist(OperationContext* opCtx) { + if (!serverGlobalParams.featureCompatibility.isVersionInitialized() || + serverGlobalParams.featureCompatibility.getVersion() != + ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo40) { + // The server is not upgrading to 4.2, bypass the check. + return; + } + + AutoGetDb autoDb(opCtx, LockpingsType::ConfigNS.db(), MODE_IS); + Collection* collection = autoDb.getDb()->getCollection(opCtx, LockpingsType::ConfigNS); + if (collection) { + IndexCatalog* indexCatalog = collection->getIndexCatalog(); + invariant(indexCatalog); + + auto desc = indexCatalog->findIndexByName(opCtx, "ping_"); + if (desc) { + auto status = Status(ErrorCodes::IndexOptionsConflict, + "Must drop index 'ping_' on config.lockpings and await " + "replication before upgrading"); + fassertFailedWithStatus(5272800, status); + } + } +} + } // namespace void ShardingInitializationMongoD::initializeShardingEnvironmentOnShardServer( @@ -279,6 +310,10 @@ bool ShardingInitializationMongoD::initializeShardingAwarenessIfNeeded(Operation return true; } else { + if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) { + assertLegacyPingIndexDoesNotExist(opCtx); + } + // Warn if a shardIdentity document is found on disk but *not* started with --shardsvr. if (!shardIdentityBSON.isEmpty()) { warning() << "Not started with --shardsvr, but a shardIdentity document was found " diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js index 01f725e7159..349f698579d 100644 --- a/src/mongo/shell/servers.js +++ b/src/mongo/shell/servers.js @@ -241,6 +241,7 @@ MongoRunner.logicalOptions = { waitForConnect: true, bridgeOptions: true, skipValidation: true, + allowedExitCode: true, }; MongoRunner.toRealPath = function(path, pathOpts) { |