From 7a2217a54d59c5d97e9e79cc40639c2589a18deb Mon Sep 17 00:00:00 2001 From: Maria van Keulen Date: Tue, 24 Apr 2018 14:38:23 -0400 Subject: SERVER-34482 Drop MMAP-specific system collections on wiredTiger It is possible for a user to explicitly create MMAP-specific system collections when using wiredTiger. The presence of these collections may cause UUID checks to fail. --- .../drop_mmap_system_collections_on_wt.js | 73 ++++++++++++++++++++++ src/mongo/db/repair_database_and_check_version.cpp | 38 +++++++++-- 2 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 jstests/multiVersion/drop_mmap_system_collections_on_wt.js diff --git a/jstests/multiVersion/drop_mmap_system_collections_on_wt.js b/jstests/multiVersion/drop_mmap_system_collections_on_wt.js new file mode 100644 index 00000000000..4335ef2650e --- /dev/null +++ b/jstests/multiVersion/drop_mmap_system_collections_on_wt.js @@ -0,0 +1,73 @@ +// Ensure system.indexes created on wiredTiger 3.4 does not cause mongodb 4.0 to fail to start up +// (see SERVER-34482). This test is to be removed after mongodb 4.0. +(function() { + "use strict"; + + load("jstests/libs/feature_compatibility_version.js"); + load("jstests/libs/check_uuids.js"); + load("jstests/multiVersion/libs/multi_rs.js"); + + const UUIDCheckBinary = "latest"; + const UUIDBinary = "3.6"; + const noUUIDBinary = "3.4"; + const systemIndexesDB = "systemIndexesDB"; + const UUIDFCV = "3.6"; + + // Create system.indexes on wiredTiger, using a version of mongod that does not assign UUIDs. + let rst = new ReplSetTest({ + nodes: 3, + nodeOptions: {binVersion: noUUIDBinary}, + }); + rst.startSet(); + rst.initiate(); + let primaryTestDB = rst.getPrimary().getDB(systemIndexesDB); + primaryTestDB.dropDatabase(); + const systemIndexesColl = "system.indexes"; + const createCmd = {create: systemIndexesColl, writeConcern: {w: "majority"}}; + assert.commandWorked(primaryTestDB.runCommand(createCmd), + "expected " + tojson(createCmd) + " to succeed"); + rst.awaitReplication(); + assert(primaryTestDB.getCollectionInfos().length == 1); + assert(primaryTestDB.getCollectionInfos()[0].name == systemIndexesColl); + let secondaries = rst.getSecondaries(); + for (let j = 0; j < secondaries.length; j++) { + let secondaryTestDB = secondaries[j].getDB(systemIndexesDB); + assert(secondaryTestDB.getCollectionInfos().length == 1); + assert(secondaryTestDB.getCollectionInfos()[0].name == systemIndexesColl); + } + + // Restart with mongodb 3.6 and set the FCV to 3.6, which will assign UUIDs to all + // collections except for system.indexes and system.namespaces. + rst.upgradeSet({binVersion: UUIDBinary}); + + let primaryAdminDB = rst.getPrimary().getDB("admin"); + assert.commandWorked(primaryAdminDB.runCommand({setFeatureCompatibilityVersion: UUIDFCV})); + rst.awaitReplication(); + checkFCV(primaryAdminDB, UUIDFCV); + secondaries = rst.getSecondaries(); + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + checkFCV(secondaryAdminDB, UUIDFCV); + } + + primaryTestDB = rst.getPrimary().getDB(systemIndexesDB); + assert(!primaryTestDB.getCollectionInfos()[0].info.uuid); + + // Restart with mongodb 4.0. This will drop system.indexes and system.namespaces if they + // exist, allowing the UUID check on start up to pass. + rst.upgradeSet({binVersion: UUIDCheckBinary}); + + primaryTestDB = rst.getPrimary().getDB(systemIndexesDB); + assert(primaryTestDB.getCollectionInfos().length == 0); + + primaryAdminDB = rst.getPrimary().getDB("admin"); + secondaries = rst.getSecondaries(); + checkCollectionUUIDs(primaryAdminDB); + for (let j = 0; j < secondaries.length; j++) { + let secondaryTestDB = secondaries[j].getDB(systemIndexesDB); + assert(secondaryTestDB.getCollectionInfos().length == 0); + let secondaryAdminDB = secondaries[j].getDB("admin"); + checkCollectionUUIDs(secondaryAdminDB); + } + rst.stopSet(); +})(); diff --git a/src/mongo/db/repair_database_and_check_version.cpp b/src/mongo/db/repair_database_and_check_version.cpp index 37baffa3ab4..90f5872adc6 100644 --- a/src/mongo/db/repair_database_and_check_version.cpp +++ b/src/mongo/db/repair_database_and_check_version.cpp @@ -36,6 +36,7 @@ #include "mongo/db/catalog/database.h" #include "mongo/db/catalog/database_catalog_entry.h" #include "mongo/db/catalog/database_holder.h" +#include "mongo/db/catalog/drop_collection.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/commands/feature_compatibility_version.h" #include "mongo/db/commands/feature_compatibility_version_documentation.h" @@ -50,6 +51,7 @@ #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/server_options.h" #include "mongo/db/storage/mmap_v1/mmap_v1_options.h" +#include "mongo/util/exit.h" #include "mongo/util/log.h" #include "mongo/util/quick_exit.h" #include "mongo/util/version.h" @@ -140,14 +142,40 @@ Status ensureAllCollectionsHaveUUIDs(OperationContext* opCtx, invariant(db); for (auto collectionIt = db->begin(); collectionIt != db->end(); ++collectionIt) { Collection* coll = *collectionIt; - if (!coll->uuid()) { - // system.indexes and system.namespaces don't currently have UUIDs in MMAP. - // SERVER-29926 and SERVER-30095 will address this problem. - if (isMmapV1 && (coll->ns().coll() == "system.indexes" || - coll->ns().coll() == "system.namespaces")) { + // The presence of system.indexes or system.namespaces on wiredTiger may + // have undesirable results (see SERVER-32894, SERVER-34482). It is okay to + // drop these collections on wiredTiger because users are not permitted to + // store data in them. + if (coll->ns().coll() == "system.indexes" || coll->ns().coll() == "system.namespaces") { + if (isMmapV1) { + // system.indexes and system.namespaces don't currently have UUIDs in MMAP. + // SERVER-29926 and SERVER-30095 will address this problem. continue; } + const auto nssToDrop = coll->ns(); + LOG(1) << "Attempting to drop invalid system collection " << nssToDrop; + if (coll->numRecords(opCtx)) { + severe(LogComponent::kControl) << "Cannot drop non-empty collection " + << nssToDrop.ns(); + exitCleanly(EXIT_NEED_DOWNGRADE); + } + repl::UnreplicatedWritesBlock uwb(opCtx); + writeConflictRetry(opCtx, "dropSystemIndexes", nssToDrop.ns(), [&] { + WriteUnitOfWork wunit(opCtx); + BSONObjBuilder unusedResult; + fassert(50837, + dropCollection( + opCtx, + nssToDrop, + unusedResult, + {}, + DropCollectionSystemCollectionMode::kAllowSystemCollectionDrops)); + wunit.commit(); + }); + continue; + } + if (!coll->uuid()) { if (!coll->ns().isReplicated()) { nonReplicatedCollNSSsWithoutUUIDs.push_back(coll->ns()); continue; -- cgit v1.2.1