diff --git a/jstests/noPassthrough/index_version_autoupgrade.js b/jstests/noPassthrough/index_version_autoupgrade.js index 6895304217a00..b7dcd5c7f35d6 100644 --- a/jstests/noPassthrough/index_version_autoupgrade.js +++ b/jstests/noPassthrough/index_version_autoupgrade.js @@ -42,9 +42,18 @@ testDB.dropDatabase(); var coll = testDB.index_version_autoupgrade; - assert.commandWorked(coll.createIndex({withoutAnyOptions: 1})); + // Create a v=1 _id index. This requires setting featureCompatibilityVersion to 3.2. + assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.2"})); + assert.commandWorked(testDB.createCollection("index_version_autoupgrade")); + assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.4"})); var allIndexes = coll.getIndexes(); - var spec = GetIndexHelpers.findByKeyPattern(allIndexes, {withoutAnyOptions: 1}); + var spec = GetIndexHelpers.findByKeyPattern(allIndexes, {_id: 1}); + assert.neq(null, spec, "Index with key pattern {_id: 1} not found: " + tojson(allIndexes)); + assert.eq(1, spec.v, "Expected a v=1 index to be built: " + tojson(spec)); + + assert.commandWorked(coll.createIndex({withoutAnyOptions: 1})); + allIndexes = coll.getIndexes(); + spec = GetIndexHelpers.findByKeyPattern(allIndexes, {withoutAnyOptions: 1}); assert.neq( null, spec, @@ -72,6 +81,7 @@ if (doesAutoUpgrade) { expectedResults = [ + {keyPattern: {_id: 1}, version: defaultIndexVersion}, {keyPattern: {withoutAnyOptions: 1}, version: defaultIndexVersion}, {keyPattern: {withV1: 1}, version: defaultIndexVersion}, {keyPattern: {withV2: 1}, version: defaultIndexVersion}, @@ -79,6 +89,7 @@ } else { expectedResults = [ + {keyPattern: {_id: 1}, version: 1}, {keyPattern: {withoutAnyOptions: 1}, version: defaultIndexVersion}, {keyPattern: {withV1: 1}, version: 1}, {keyPattern: {withV2: 1}, version: 2}, @@ -86,7 +97,7 @@ } expectedResults.forEach(function(expected) { - var allIndexes = coll.getIndexes(); + var allIndexes = collToVerify.getIndexes(); var spec = GetIndexHelpers.findByKeyPattern(allIndexes, expected.keyPattern); assert.neq(null, spec, @@ -151,5 +162,19 @@ }, false); MongoRunner.stopMongod(cloneConn); + // Test that the "clone" command doesn't upgrade existing indexes to the latest version. + cloneConn = MongoRunner.runMongod({}); + assert.neq(null, cloneConn, "mongod was unable to start up"); + assert.eq("3.4", getFeatureCompatibilityVersion(cloneConn)); + testIndexVersionAutoUpgrades(function(coll) { + var cloneDB = cloneConn.getDB(coll.getDB().getName()); + assert.commandWorked(cloneDB.runCommand({ + clone: conn.host, + fromDB: coll.getDB().getName(), + })); + return cloneDB[coll.getName()]; + }, false); + MongoRunner.stopMongod(cloneConn); + MongoRunner.stopMongod(conn); })(); diff --git a/jstests/repl/initial_sync_id_index.js b/jstests/repl/initial_sync_id_index.js new file mode 100644 index 0000000000000..5871f68f3232e --- /dev/null +++ b/jstests/repl/initial_sync_id_index.js @@ -0,0 +1,46 @@ +// Tests that the _id index spec is copied exactly during initial sync. +(function() { + "use strict"; + + load("jstests/libs/get_index_helpers.js"); + + const rt = new ReplTest(); + const master = rt.start(true); + const masterDB = master.getDB("test"); + + // Initially, featureCompatibilityVersion is 3.4, so we will create v=2 indexes. + let res = master.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.commandWorked(masterDB.createCollection("collV2")); + let spec = GetIndexHelpers.findByName(masterDB.collV2.getIndexes(), "_id_"); + assert.neq(spec, null); + assert.eq(spec.v, 2); + + // Set featureCompatibilityVersion to 3.2, so we create v=1 indexes. + assert.commandWorked(master.adminCommand({setFeatureCompatibilityVersion: "3.2"})); + res = master.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.2"); + assert.commandWorked(masterDB.createCollection("collV1")); + spec = GetIndexHelpers.findByName(masterDB.collV1.getIndexes(), "_id_"); + assert.neq(spec, null); + assert.eq(spec.v, 1); + + // Initial sync a slave. + const slave = rt.start(false); + const slaveDB = slave.getDB("test"); + + // Perform a w=2 write to ensure that slave can be read from, and initial sync is complete. + assert.writeOK(masterDB.coll.insert({}, {writeConcern: {w: 2}})); + + // Check _id index versions on slave. + spec = GetIndexHelpers.findByName(slaveDB.collV2.getIndexes(), "_id_"); + assert.neq(spec, null); + assert.eq(spec.v, 2); + spec = GetIndexHelpers.findByName(slaveDB.collV1.getIndexes(), "_id_"); + assert.neq(spec, null); + assert.eq(spec.v, 1); + + rt.stop(); +})(); \ No newline at end of file diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 9d854b8e705f2..c45ed237c44e1 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -674,10 +674,36 @@ Status Cloner::copyDb(OperationContext* txn, MultiIndexBlock indexer(txn, c); indexer.allowInterruption(); - const auto featureCompatibilityVersion = - serverGlobalParams.featureCompatibility.version.load(); - auto indexInfoObjs = uassertStatusOK(indexer.init( - c->getIndexCatalog()->getDefaultIdIndexSpec(featureCompatibilityVersion))); + BSONObj idIndexSpec; + { + Lock::TempRelease tempRelease(txn->lockState()); + auto sourceIndexes = _conn->getIndexSpecs( + from_name.ns(), opts.slaveOk ? QueryOption_SlaveOk : 0); + for (auto&& indexSpec : sourceIndexes) { + if ("_id_"_sd == indexSpec["name"].String()) { + idIndexSpec = indexSpec; + break; + } + } + } + + uassert(ErrorCodes::NotMaster, + str::stream() << "Not primary while cloning database " << opts.fromDB + << " (after getting _id index spec for collection " + << from_name.ns() + << ")", + !txn->writesAreReplicated() || + repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase( + toDBName)); + + uassert(40332, + str::stream() << "_id index spec not found for collection " + << from_name.ns() + << " during clone", + !idIndexSpec.isEmpty()); + + auto indexInfoObjs = uassertStatusOK( + indexer.init(fixIndexSpec(to_name.db().toString(), idIndexSpec))); invariant(indexInfoObjs.size() == 1); uassertStatusOK(indexer.insertAllDocumentsInCollection(&dups));