diff options
71 files changed, 820 insertions, 1530 deletions
diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz.yml b/buildscripts/resmokeconfig/suites/jstestfuzz.yml index b72c0457ec8..ea890e97fd9 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz.yml @@ -14,7 +14,6 @@ executor: global_vars: TestData: skipValidationOnInvalidViewDefinitions: true - forceValidationWithFeatureCompatibilityVersion: "3.4" fixture: class: MongoDFixture mongod_options: diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml b/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml index 8c96d9a5608..f0a124dd315 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml @@ -23,7 +23,6 @@ executor: global_vars: TestData: skipValidationOnInvalidViewDefinitions: true - forceValidationWithFeatureCompatibilityVersion: "3.4" fixture: class: ReplicaSetFixture mongod_options: diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz_replication_initsync.yml b/buildscripts/resmokeconfig/suites/jstestfuzz_replication_initsync.yml index 9c9bc152bce..c9c9ad25fb9 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz_replication_initsync.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz_replication_initsync.yml @@ -18,7 +18,6 @@ executor: global_vars: TestData: skipValidationOnInvalidViewDefinitions: true - forceValidationWithFeatureCompatibilityVersion: "3.4" fixture: class: ReplicaSetFixture mongod_options: diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz_replication_resync.yml b/buildscripts/resmokeconfig/suites/jstestfuzz_replication_resync.yml index 95ffc352da8..1a39d00cd77 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz_replication_resync.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz_replication_resync.yml @@ -19,7 +19,6 @@ executor: global_vars: TestData: skipValidationOnInvalidViewDefinitions: true - forceValidationWithFeatureCompatibilityVersion: "3.4" fixture: class: ReplicaSetFixture mongod_options: diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml b/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml index a5c31b21582..4f95e982852 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml @@ -14,7 +14,6 @@ executor: global_vars: TestData: skipValidationOnInvalidViewDefinitions: true - forceValidationWithFeatureCompatibilityVersion: "3.4" fixture: class: ShardedClusterFixture mongos_options: diff --git a/jstests/decimal/decimal_feature_compatibility_version.js b/jstests/decimal/decimal_feature_compatibility_version.js deleted file mode 100644 index 7123c28e0fc..00000000000 --- a/jstests/decimal/decimal_feature_compatibility_version.js +++ /dev/null @@ -1,58 +0,0 @@ -// Test that decimal usage is restricted when the featureCompatibilityVersion is 3.2. - -(function() { - "use strict"; - - // Decimal data with feature compatibility version 3.2 causes collection - // validation failure. - // TODO: SERVER-29350 Remove this code when feature compatibility version 3.2 is removed. - TestData.skipCollectionAndIndexValidation = true; - - const conn = MongoRunner.runMongod({}); - assert.neq(null, conn, "mongod was unable to start up"); - - const decimalDB = conn.getDB("decimal_feature_compatibility_version"); - assert.commandWorked(decimalDB.dropDatabase()); - assert.commandWorked(decimalDB.runCommand({create: "collection"})); - - const adminDB = conn.getDB("admin"); - - // Ensure the featureCompatibilityVersion is 3.4. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); - let res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq("3.4", res.featureCompatibilityVersion); - - // Decimals can be inserted when the featureCompatibilityVersion is 3.4. - assert.writeOK(decimalDB.collection.insert({a: NumberDecimal(2.0)})); - - // Collection containing decimals is valid when the featureCompatibilityVersion is 3.4. - res = decimalDB.collection.validate({full: true}); - assert.commandWorked(res); - assert.eq(true, res.valid, tojson(res)); - - // Ensure the featureCompatibilityVersion is 3.2. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); - res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); - - // Decimals cannot be inserted when the featureCompatibilityVersion is 3.2. - assert.writeErrorWithCode(decimalDB.collection.insert({a: NumberDecimal(2.0)}), - ErrorCodes.InvalidBSON); - - // Decimals cannot be used in queries when the featureCompatibilityVersion is 3.2. - assert.throws(function() { - decimalDB.collection.findOne({a: NumberDecimal(2.0)}); - }); - - // Decimals can be read when the featureCompatibilityVersion is 3.2. - assert.eq(decimalDB.collection.findOne().a, NumberDecimal(2.0)); - - // Collection containing decimals is invalid when the featureCompatibilityVersion is 3.2. - res = decimalDB.collection.validate({full: true}); - assert.commandWorked(res); - assert.eq(false, res.valid, tojson(res)); - - MongoRunner.stopMongod(conn); -}()); diff --git a/jstests/hooks/validate_collections.js b/jstests/hooks/validate_collections.js index bf2b7b06709..ac2382ae838 100644 --- a/jstests/hooks/validate_collections.js +++ b/jstests/hooks/validate_collections.js @@ -13,24 +13,6 @@ function validateCollections(db, obj) { } } - function getFeatureCompatibilityVersion(adminDB) { - var res = adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}); - if (res === null) { - return "3.2"; - } - return res.version; - } - - function setFeatureCompatibilityVersion(adminDB, version) { - var res = adminDB.runCommand({setFeatureCompatibilityVersion: version}); - if (!res.ok) { - return res; - } - - assert.eq(version, getFeatureCompatibilityVersion(adminDB)); - return res; - } - assert.eq(typeof db, 'object', 'Invalid `db` object, is the shell connected to a mongod?'); assert.eq(typeof obj, 'object', 'The `obj` argument must be an object'); assert(obj.hasOwnProperty('full'), 'Please specify whether to use full validation'); @@ -41,43 +23,6 @@ function validateCollections(db, obj) { var adminDB = db.getSiblingDB("admin"); - // Set the featureCompatibilityVersion to its required value for performing validation. Save the - // original value. - var originalFeatureCompatibilityVersion; - if (jsTest.options().forceValidationWithFeatureCompatibilityVersion) { - try { - originalFeatureCompatibilityVersion = getFeatureCompatibilityVersion(adminDB); - } catch (e) { - if (jsTest.options().skipValidationOnInvalidViewDefinitions && - e.code === ErrorCodes.InvalidViewDefinition) { - print("Reading the featureCompatibilityVersion from the admin.system.version" + - " collection failed due to an invalid view definition on the admin database"); - // The view catalog would only have been resolved if the namespace doesn't exist as - // a collection. The absence of the admin.system.version collection is equivalent to - // having featureCompatibilityVersion=3.2. - originalFeatureCompatibilityVersion = "3.2"; - } else { - throw e; - } - } - - var res = setFeatureCompatibilityVersion( - adminDB, jsTest.options().forceValidationWithFeatureCompatibilityVersion); - // Bypass collections validation when setFeatureCompatibilityVersion fails with KeyTooLong - // while forcing feature compatibility version. The KeyTooLong error response occurs as a - // result of having a document with a large "version" field in the admin.system.version - // collection. - if (!res.ok && jsTest.options().forceValidationWithFeatureCompatibilityVersion === "3.4") { - print("Skipping collection validation since forcing the featureCompatibilityVersion" + - " to 3.4 failed"); - assert.commandFailedWithCode(res, ErrorCodes.KeyTooLong); - success = true; - return success; - } else { - assert.commandWorked(res); - } - } - // Don't run validate on view namespaces. let filter = {type: "collection"}; if (jsTest.options().skipValidationOnInvalidViewDefinitions) { @@ -111,11 +56,5 @@ function validateCollections(db, obj) { } } - // Restore the original value for featureCompatibilityVersion. - if (jsTest.options().forceValidationWithFeatureCompatibilityVersion) { - assert.commandWorked( - setFeatureCompatibilityVersion(adminDB, originalFeatureCompatibilityVersion)); - } - return success; } diff --git a/jstests/master_slave/initial_sync_id_index.js b/jstests/master_slave/initial_sync_id_index.js index 0159809ed8a..0b15a04be71 100644 --- a/jstests/master_slave/initial_sync_id_index.js +++ b/jstests/master_slave/initial_sync_id_index.js @@ -8,21 +8,16 @@ 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")); + // Create a collection with a v=2 _id index. + assert.commandWorked( + masterDB.createCollection("collV2", {idIndex: {key: {_id: 1}, name: "_id_", v: 2}})); 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")); + // Create a collection with a v=1 _id index. + assert.commandWorked( + masterDB.createCollection("collV1", {idIndex: {key: {_id: 1}, name: "_id_", v: 1}})); spec = GetIndexHelpers.findByName(masterDB.collV1.getIndexes(), "_id_"); assert.neq(spec, null); assert.eq(spec.v, 1); diff --git a/jstests/master_slave/slave_sync_decimal.js b/jstests/master_slave/slave_sync_decimal.js deleted file mode 100644 index dba3792cf1a..00000000000 --- a/jstests/master_slave/slave_sync_decimal.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Tests that we can initial sync decimal128 data to a slave, even when the cluster is in 3.2 - * feature compatibility mode. - */ -(function() { - "use strict"; - - var replTest = new ReplTest("slave_sync_decimal"); - - var master = replTest.start(true); - var masterDB = master.getDB("test"); - var masterColl = masterDB.slave_sync_decimal; - - // Since the master started fresh, it should be in 3.4 feature compatibility mode. - var fcv = assert.commandWorked( - masterDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - assert.eq(fcv.featureCompatibilityVersion, "3.4"); - - // Make sure we can insert decimal data in 3.4 mode. - assert.writeOK(masterColl.insert({a: 1, b: NumberDecimal(1)})); - - // Set 3.2 feature compatibility mode. - assert.commandWorked(masterDB.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - fcv = assert.commandWorked( - masterDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - assert.eq(fcv.featureCompatibilityVersion, "3.2"); - - // We shouldn't be able to insert decimal data in 3.2 mode. - assert.writeError(masterColl.insert({a: 1, b: NumberDecimal(1)})); - - var slave = replTest.start(false); - var slaveDB = slave.getDB("test"); - var slaveColl = slaveDB.slave_sync_decimal; - - fcv = assert.commandWorked( - slaveDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - assert.eq(fcv.featureCompatibilityVersion, "3.2"); - - slave.setSlaveOk(true); - - assert.soon(function() { - return slaveColl.find({b: NumberDecimal(1)}).itcount() === 1; - }, 5 * 60 * 1000, "Slave failed to sync document containing NumberDecimal"); - - replTest.stop(); -})(); diff --git a/jstests/multiVersion/downgrade_replset.js b/jstests/multiVersion/downgrade_replset.js index 022471410a1..3e324a69ad6 100644 --- a/jstests/multiVersion/downgrade_replset.js +++ b/jstests/multiVersion/downgrade_replset.js @@ -26,6 +26,13 @@ function runDowngradeTest(protocolVersion) { var primary = rst.getPrimary(); var coll = "test.foo"; + // We wait for the feature compatibility version to be set to "3.4" on all nodes of the replica + // set in order to ensure that all nodes can be successfully downgraded. This effectively allows + // us to emulate upgrading to the latest version with existing data files and then trying to + // downgrade back to 3.4. + assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: "3.4"})); + rst.awaitReplication(); + jsTest.log("Inserting documents into collection."); for (var i = 0; i < 10; i++) { primary.getCollection(coll).insert({_id: i, str: "hello world"}); diff --git a/jstests/multiVersion/initialsync.js b/jstests/multiVersion/initialsync.js index a36d538a6f8..494d50e86a5 100644 --- a/jstests/multiVersion/initialsync.js +++ b/jstests/multiVersion/initialsync.js @@ -20,6 +20,9 @@ var multitest = function(replSetVersion, newNodeVersion, configSettings) { // Wait for a primary node. var primary = rst.getPrimary(); + // The featureCompatibilityVersion must be 3.4 to have a mixed-version replica set. + assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: "3.4"})); + // Insert some data and wait for replication. for (var i = 0; i < 25; i++) { primary.getDB("foo").foo.insert({_id: i}); diff --git a/jstests/multiVersion/major_version_upgrade.js b/jstests/multiVersion/major_version_upgrade.js index bc46e191a33..1365fac361c 100644 --- a/jstests/multiVersion/major_version_upgrade.js +++ b/jstests/multiVersion/major_version_upgrade.js @@ -73,8 +73,14 @@ // repairDatabase should similarly succeed. assert.commandWorked(testDB.runCommand({repairDatabase: 1})); - // reIndex should succeed. - assert.commandWorked(testDB[collName].reIndex()); + // reIndex will fail because when featureCompatibilityVersion>=3.4, reIndex + // automatically upgrades v=1 indexes to v=2. + assert.commandFailed(testDB[collName].reIndex()); + + // reIndex should not drop the index. + indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); + assert.neq(null, indexSpec, 'could not find index "badkp" after reIndex'); + assert.eq(1, indexSpec.v, tojson(indexSpec)); // A query that hints the index should succeed. assert.commandWorked(testDB.runCommand({find: collName, hint: "badkp"})); diff --git a/jstests/multiVersion/mixed_storage_version_replication.js b/jstests/multiVersion/mixed_storage_version_replication.js index 88e732b00da..103586f7fa8 100644 --- a/jstests/multiVersion/mixed_storage_version_replication.js +++ b/jstests/multiVersion/mixed_storage_version_replication.js @@ -676,6 +676,13 @@ function doMultiThreadedWork(primary, numThreads) { config.settings = {catchUpTimeoutMillis: 2000}; replTest.initiate(config); + // We set the featureCompatibilityVersion to 3.4 so that 3.4 secondaries can successfully + // initial sync from a 3.6 primary. We do this prior to adding any other members to the replica + // set. This effectively allows us to emulate upgrading some of our nodes to the latest version + // while different 3.6 and 3.4 mongod processes are being elected primary. + assert.commandWorked( + replTest.getPrimary().adminCommand({setFeatureCompatibilityVersion: "3.4"})); + for (let i = 1; i < setups.length; ++i) { replTest.add(setups[i]); } diff --git a/jstests/multiVersion/set_feature_compatibility_version.js b/jstests/multiVersion/set_feature_compatibility_version.js new file mode 100644 index 00000000000..d3ff69c67b3 --- /dev/null +++ b/jstests/multiVersion/set_feature_compatibility_version.js @@ -0,0 +1,429 @@ +// Tests for setFeatureCompatibilityVersion. +(function() { + "use strict"; + + load("jstests/replsets/rslib.js"); + load("jstests/libs/get_index_helpers.js"); + + let res; + const latest = "latest"; + const downgrade = "3.4"; + + // + // Standalone tests. + // + + let dbpath = MongoRunner.dataPath + "feature_compatibility_version"; + resetDbpath(dbpath); + let conn; + let adminDB; + + // New 3.6 standalone. + conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); + assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); + adminDB = conn.getDB("admin"); + + // Initially featureCompatibilityVersion is 3.6. + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, "3.6"); + + // featureCompatibilityVersion cannot be set to invalid value. + assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: 5})); + assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); + assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.8"})); + + // setFeatureCompatibilityVersion rejects unknown fields. + assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4", unknown: 1})); + + // setFeatureCompatibilityVersion can only be run on the admin database. + assert.commandFailed(conn.getDB("test").runCommand({setFeatureCompatibilityVersion: "3.4"})); + + // featureCompatibilityVersion cannot be set via setParameter. + assert.commandFailed(adminDB.runCommand({setParameter: 1, featureCompatibilityVersion: "3.4"})); + + // featureCompatibilityVersion can be set to 3.4. + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, "3.4"); + + // featureCompatibilityVersion can be set to 3.6. + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.6"})); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, "3.6"); + + MongoRunner.stopMongod(conn); + + // featureCompatibilityVersion is durable. + conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); + assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); + adminDB = conn.getDB("admin"); + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + MongoRunner.stopMongod(conn); + + conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); + assert.neq(null, + conn, + "mongod was unable to start up with version=" + latest + + " and featureCompatibilityVersion=3.4"); + adminDB = conn.getDB("admin"); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, "3.4"); + MongoRunner.stopMongod(conn); + + // If you upgrade from 3.4 to 3.6 and have non-local databases, featureCompatibilityVersion is + // 3.4. + conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: downgrade}); + assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); + assert.writeOK(conn.getDB("test").coll.insert({a: 5})); + adminDB = conn.getDB("admin"); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, "3.4"); + MongoRunner.stopMongod(conn); + + conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); + assert.neq(null, + conn, + "mongod was unable to start up with version=" + latest + + " and featureCompatibilityVersion=3.4"); + adminDB = conn.getDB("admin"); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + MongoRunner.stopMongod(conn); + + // + // Replica set tests. + // + + let rst; + let rstConns; + let replSetConfig; + let primaryAdminDB; + let secondaryAdminDB; + + // New 3.6 replica set. + rst = new ReplSetTest({nodes: 2, nodeOpts: {binVersion: latest}}); + rst.startSet(); + rst.initiate(); + primaryAdminDB = rst.getPrimary().getDB("admin"); + secondaryAdminDB = rst.getSecondary().getDB("admin"); + + // Initially featureCompatibilityVersion is 3.6 on primary and secondary. + res = primaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq(primaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + rst.awaitReplication(); + res = secondaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq(secondaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + + // featureCompatibilityVersion propagates to secondary. + assert.commandWorked(primaryAdminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + res = primaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq(primaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + rst.awaitReplication(); + res = secondaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq(secondaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + + // setFeatureCompatibilityVersion cannot be run on secondary. + assert.commandFailed(secondaryAdminDB.runCommand({setFeatureCompatibilityVersion: "3.6"})); + + rst.stopSet(); + + // A 3.6 secondary with a 3.4 primary will have featureCompatibilityVersion=3.4. + rst = new ReplSetTest({nodes: [{binVersion: downgrade}, {binVersion: latest}]}); + rstConns = rst.startSet(); + replSetConfig = rst.getReplSetConfig(); + replSetConfig.members[1].priority = 0; + replSetConfig.members[1].votes = 0; + rst.initiate(replSetConfig); + rst.waitForState(rstConns[0], ReplSetTest.State.PRIMARY); + secondaryAdminDB = rst.getSecondary().getDB("admin"); + res = secondaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + rst.stopSet(); + + // Test that a 3.4 secondary can successfully perform initial sync from a 3.6 primary with + // featureCompatibilityVersion=3.4. + rst = new ReplSetTest({nodes: [{binVersion: latest}]}); + rst.startSet(); + rst.initiate(); + + primaryAdminDB = rst.getPrimary().getDB("admin"); + assert.commandWorked(primaryAdminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + let secondary = rst.add({binVersion: downgrade}); + secondaryAdminDB = secondary.getDB("admin"); + + // Rig the election so that the first node running latest version remains the primary after the + // 3.4 secondary is added to the replica set. + replSetConfig = rst.getReplSetConfig(); + replSetConfig.version = 3; + replSetConfig.members[1].priority = 0; + replSetConfig.members[1].votes = 0; + + // The default value for 'catchUpTimeoutMillis' on 3.6 is -1. A 3.4 secondary will refuse to + // join a replica set with catchUpTimeoutMillis=-1. + replSetConfig.settings = {catchUpTimeoutMillis: 2000}; + reconfig(rst, replSetConfig); + + // Verify that the 3.4 secondary successfully performed its initial sync. + assert.writeOK( + primaryAdminDB.getSiblingDB("test").coll.insert({awaitRepl: true}, {writeConcern: {w: 2}})); + + // Test that a 3.4 secondary crashes when syncing from a 3.6 primary and the + // featureCompatibilityVersion is set to 3.6. + assert.commandWorked(primaryAdminDB.runCommand({setFeatureCompatibilityVersion: "3.6"})); + rst.stop(secondary, undefined, {allowedExitCode: MongoRunner.EXIT_ABRUPT}); + rst.stopSet(); + + // A mixed 3.4/3.6 replica set without a featureCompatibilityVersion document unfortunately + // reports mixed 3.2/3.4 featureCompatibilityVersion. + rst = new ReplSetTest({nodes: [{binVersion: downgrade}, {binVersion: latest}]}); + rstConns = rst.startSet(); + replSetConfig = rst.getReplSetConfig(); + replSetConfig.members[1].priority = 0; + replSetConfig.members[1].votes = 0; + rst.initiate(replSetConfig); + primaryAdminDB = rst.getPrimary().getDB("admin"); + secondaryAdminDB = rst.getSecondary().getDB("admin"); + assert.writeOK(primaryAdminDB.system.version.remove({_id: "featureCompatibilityVersion"}, + {writeConcern: {w: 2}})); + res = primaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.2"); + res = secondaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + rst.stopSet(); + + // + // Sharding tests. + // + + let st; + let mongosAdminDB; + let configPrimaryAdminDB; + let shardPrimaryAdminDB; + + // New 3.6 cluster. + st = new ShardingTest({ + shards: {rs0: {nodes: [{binVersion: latest}, {binVersion: latest}]}}, + other: {useBridge: true} + }); + mongosAdminDB = st.s.getDB("admin"); + configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); + shardPrimaryAdminDB = st.rs0.getPrimary().getDB("admin"); + + // Initially featureCompatibilityVersion is 3.6 on config and shard. + res = configPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq( + configPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + res = shardPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq( + shardPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + + // featureCompatibilityVersion cannot be set to invalid value on mongos. + assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: 5})); + assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); + assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.8"})); + + // setFeatureCompatibilityVersion rejects unknown fields on mongos. + assert.commandFailed( + mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.4", unknown: 1})); + + // setFeatureCompatibilityVersion can only be run on the admin database on mongos. + assert.commandFailed(st.s.getDB("test").runCommand({setFeatureCompatibilityVersion: "3.4"})); + + // featureCompatibilityVersion cannot be set via setParameter on mongos. + assert.commandFailed( + mongosAdminDB.runCommand({setParameter: 1, featureCompatibilityVersion: "3.4"})); + + // Prevent the shard primary from receiving messages from the config server primary. When we try + // to set the featureCompatibilityVersion to "3.4", it should fail because the shard cannot be + // contacted. The config server primary should still report "3.6", since setting the version to + // "3.4" did not succeed. + st.rs0.getPrimary().discardMessagesFrom(st.configRS.getPrimary(), 1.0); + assert.commandFailed( + mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.4", maxTimeMS: 1000})); + res = configPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + st.rs0.getPrimary().discardMessagesFrom(st.configRS.getPrimary(), 0.0); + + // featureCompatibilityVersion can be set to 3.4 on mongos. + // This is run through assert.soon() because we've just caused a network interruption + // by discarding messages in the bridge. + assert.soon(function() { + res = mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.4"}); + if (res.ok == 0) { + print("Failed to set feature compatibility version: " + tojson(res)); + return false; + } + return true; + }); + + // featureCompatibilityVersion propagates to config and shard. + res = configPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq( + configPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + res = shardPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq( + shardPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + + // A 3.6 shard added to a cluster with featureCompatibilityVersion=3.4 gets + // featureCompatibilityVersion=3.4. + let latestShard = new ReplSetTest({ + name: "latestShard", + nodes: [{binVersion: latest}, {binVersion: latest}], + nodeOptions: {shardsvr: ""}, + useHostName: true + }); + latestShard.startSet(); + latestShard.initiate(); + assert.commandWorked(mongosAdminDB.runCommand({addShard: latestShard.getURL()})); + let latestShardPrimaryAdminDB = latestShard.getPrimary().getDB("admin"); + res = latestShardPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + + // featureCompatibilityVersion can be set to 3.6 on mongos. + assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.6"})); + res = st.configRS.getPrimary().getDB("admin").runCommand( + {getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq( + configPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + res = shardPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq( + shardPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + + latestShard.stopSet(); + st.stop(); + + // Create cluster with 3.4 mongos so that we can add 3.4 shards. + st = new ShardingTest({shards: 0, other: {mongosOptions: {binVersion: downgrade}}}); + mongosAdminDB = st.s.getDB("admin"); + configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); + + // Adding a 3.4 shard to a cluster with featureCompatibilityVersion=3.4 succeeds. + res = configPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq( + configPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + let downgradeShard = new ReplSetTest({ + name: "downgradeShard", + nodes: [{binVersion: downgrade}, {binVersion: downgrade}], + nodeOptions: {shardsvr: ""}, + useHostName: true + }); + downgradeShard.startSet(); + downgradeShard.initiate(); + assert.commandWorked(mongosAdminDB.runCommand({addShard: downgradeShard.getURL()})); + res = + downgradeShard.getPrimary().adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + + downgradeShard.stopSet(); + st.stop(); + + // Create a cluster running with featureCompatibilityVersion=3.6. + st = new ShardingTest({shards: 1, mongos: 1}); + mongosAdminDB = st.s.getDB("admin"); + configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); + shardPrimaryAdminDB = st.shard0.getDB("admin"); + res = configPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq( + configPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + res = shardPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.6"); + assert.eq( + shardPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.6"); + + // Ensure that a 3.4 mongos can be added to a featureCompatibilityVersion=3.4 cluster. + assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + res = configPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq( + configPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + st.configRS.awaitReplication(); + res = shardPrimaryAdminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq(res.featureCompatibilityVersion, "3.4"); + assert.eq( + shardPrimaryAdminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + "3.4"); + let downgradeMongos = + MongoRunner.runMongos({configdb: st.configRS.getURL(), binVersion: downgrade}); + assert.neq(null, + downgradeMongos, + "mongos was unable to start up with version=" + latest + + " and connect to featureCompatibilityVersion=3.4 cluster"); + + // Ensure that the 3.4 mongos can perform reads and writes to the shards in the cluster. + assert.writeOK(downgradeMongos.getDB("test").foo.insert({x: 1})); + let foundDoc = downgradeMongos.getDB("test").foo.findOne({x: 1}); + assert.neq(null, foundDoc); + assert.eq(1, foundDoc.x, tojson(foundDoc)); + + // The 3.4 mongos can no longer perform reads and writes after the featureCompatibilityVersion + // is set to 3.6. + assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.6"})); + assert.writeError(downgradeMongos.getDB("test").foo.insert({x: 1})); + + // The 3.6 mongos can still perform reads and writes after the featureCompatibilityVersion is + // set to 3.6. + assert.writeOK(st.s.getDB("test").foo.insert({x: 1})); + + st.stop(); +})(); diff --git a/jstests/multiVersion/upgrade_cluster.js b/jstests/multiVersion/upgrade_cluster.js index 153413f828b..c1634d00ab5 100644 --- a/jstests/multiVersion/upgrade_cluster.js +++ b/jstests/multiVersion/upgrade_cluster.js @@ -56,16 +56,6 @@ load('./jstests/multiVersion/libs/multi_cluster.js'); assert.commandWorked(st.s.adminCommand({enableSharding: 'sharded'})); st.ensurePrimaryShard('sharded', st.shard0.shardName); - // We explicitly create an index on the shard key to avoid having mongos attempt to - // implicitly create one. This is necessary because mongos would otherwise explicitly - // include the "collation" option in the requested index to prevent potentially inheriting - // the collation-default collation. However, specifying the "collation" option requires a - // v=2 index and that may not be possible if the server has featureCompatibilityVersion=3.2. - // - // TODO SERVER-25955: Allow mongos to implicitly create the shard key index when sharding a - // collection with a "simple" default collation and update this test case to not explicitly - // create it. - assert.commandWorked(st.s.getDB('sharded').foo.createIndex({x: 1})); assert.commandWorked(st.s.adminCommand({shardCollection: 'sharded.foo', key: {x: 1}})); assert.commandWorked(st.s.adminCommand({split: 'sharded.foo', middle: {x: 0}})); assert.commandWorked( diff --git a/jstests/noPassthrough/collation_feature_compatibility_version.js b/jstests/noPassthrough/collation_feature_compatibility_version.js deleted file mode 100644 index 2f393c2a99a..00000000000 --- a/jstests/noPassthrough/collation_feature_compatibility_version.js +++ /dev/null @@ -1,217 +0,0 @@ -// Test that collation usage is restricted when the featureCompatibilityVersion is 3.2. - -(function() { - "use strict"; - - // - // Test correct behavior of operations with collation against a mongod when the - // featureCompatibilityVersion is 3.2. - // - - const conn = MongoRunner.runMongod({}); - assert.neq(null, conn, "mongod was unable to start up"); - - let collationDB = conn.getDB("collation_operations_feature_compatibility_version"); - assert.commandWorked(collationDB.dropDatabase()); - - let adminDB = conn.getDB("admin"); - - // Create a collection with a case-insensitive default collation. - assert.commandWorked(collationDB.createCollection("caseInsensitive", - {collation: {locale: "en_US", strength: 2}})); - let caseInsensitive = collationDB.caseInsensitive; - assert.commandWorked(caseInsensitive.createIndex({geo: "2dsphere"})); - assert.writeOK(caseInsensitive.insert({str: "foo", geo: {type: "Point", coordinates: [0, 0]}})); - - // Ensure the featureCompatibilityVersion is 3.2. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); - let res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); - - // We cannot create a collection with a default collation when the featureCompatibilityVersion - // is 3.2. - assert.commandFailed( - collationDB.createCollection("collection", {collation: {locale: "fr_CA"}})); - - // We cannot explicitly give a collection the simple collation as its default when the - // featureCompatibilityVersion is 3.2. - assert.commandFailed( - collationDB.createCollection("collection", {collation: {locale: "simple"}})); - - // We cannot create a view with a default collation when the featureCompatibilityVersion is 3.2. - assert.commandFailed(collationDB.runCommand( - {create: "view", viewOn: "caseInsensitive", collation: {locale: "fr_CA"}})); - - // We cannot explicitly give a view the simple collation as its default when the - // featureCompatibilityVersion is 3.2. - assert.commandFailed(collationDB.runCommand( - {create: "view", viewOn: "caseInsensitive", collation: {locale: "simple"}})); - - // All operations reject the collation parameter when the featureCompatibilityVersion is 3.2. - assert.throws(function() { - caseInsensitive.aggregate([], {collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.aggregate([], {explain: true, collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.find().collation({locale: "en_US"}).count(); - }); - assert.throws(function() { - caseInsensitive.explain().find().collation({locale: "en_US"}).count(); - }); - assert.throws(function() { - caseInsensitive.distinct("str", {}, {collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.explain().distinct("str", {}, {collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.find().collation({locale: "en_US"}).itcount(); - }); - assert.throws(function() { - caseInsensitive.find().collation({locale: "en_US"}).explain(); - }); - assert.throws(function() { - caseInsensitive.findAndModify({update: {$set: {a: 1}}, collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.explain().findAndModify( - {update: {$set: {a: 1}}, collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.findAndModify({remove: true, collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.explain().findAndModify({remove: true, collation: {locale: "en_US"}}); - }); - assert.commandFailed(collationDB.runCommand({ - geoNear: caseInsensitive.getName(), - near: {type: "Point", coordinates: [0, 0]}, - spherical: true, - collation: {locale: "en_US"} - })); - assert.throws(function() { - caseInsensitive.group( - {initial: {}, reduce: function(curr, result) {}, collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.explain().group( - {initial: {}, reduce: function(curr, result) {}, collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.mapReduce( - function() { - emit(this, 1); - }, - function(key, values) { - return 0; - }, - {out: {inline: 1}, collation: {locale: "en_US"}}); - }); - assert.writeError(caseInsensitive.update({}, {$set: {a: 1}}, {collation: {locale: "en_US"}})); - assert.throws(function() { - caseInsensitive.explain().update({}, {$set: {a: 1}}, {collation: {locale: "en_US"}}); - }); - assert.writeError(caseInsensitive.remove({}, {collation: {locale: "en_US"}})); - assert.throws(function() { - caseInsensitive.explain().remove({}, {collation: {locale: "en_US"}}); - }); - - // All operations respect the collection default collation when the featureCompatibilityVersion - // is 3.2. - assert.eq(1, caseInsensitive.aggregate([{$match: {str: "FOO"}}]).itcount()); - assert.eq(1, caseInsensitive.find({str: "FOO"}).count()); - assert.eq(1, caseInsensitive.distinct("str", {str: "FOO"}).length); - assert.eq(1, caseInsensitive.find({str: "FOO"}).itcount()); - assert.eq("foo", - caseInsensitive.findAndModify({query: {str: "FOO"}, update: {$set: {a: 1}}}).str); - assert.eq(1, - assert - .commandWorked(collationDB.runCommand({ - geoNear: caseInsensitive.getName(), - near: {type: "Point", coordinates: [0, 0]}, - spherical: true, - query: {str: "FOO"} - })) - .results.length); - assert.eq([{count: 1}], caseInsensitive.group({ - cond: {str: "FOO"}, - initial: {count: 0}, - reduce: function(curr, result) { - result.count += 1; - } - })); - assert.eq(1, - assert - .commandWorked(caseInsensitive.mapReduce( - function() { - emit(this.str, 1); - }, - function(key, values) { - return Array.sum(values); - }, - {out: {inline: 1}, query: {str: "FOO"}})) - .results.length); - assert.eq(1, caseInsensitive.update({str: "FOO"}, {$set: {a: 1}}).nMatched); - assert.eq(1, caseInsensitive.remove({str: "FOO"}).nRemoved); - - MongoRunner.stopMongod(conn); - - // - // Test correct behavior of aggregation with collation against a sharded cluster when the - // featureCompatibilityVersion is 3.2. - // - - const st = new ShardingTest({shards: 2}); - collationDB = st.s.getDB("collation_operations_feature_compatibility_version"); - assert.commandWorked(collationDB.dropDatabase()); - assert.commandWorked(collationDB.adminCommand({enableSharding: collationDB.getName()})); - - adminDB = st.s.getDB("admin"); - - // Create a collection with a case-insensitive default collation. - assert.commandWorked(collationDB.createCollection("caseInsensitive", - {collation: {locale: "en_US", strength: 2}})); - caseInsensitive = collationDB.caseInsensitive; - assert.commandWorked(collationDB.adminCommand({ - shardCollection: caseInsensitive.getFullName(), - key: {str: 1}, - collation: {locale: "simple"} - })); - - // Split the collection. Ensure {str: "foo"} and {str: "FOO"} are on separate shards. - assert.commandWorked( - collationDB.adminCommand({split: caseInsensitive.getFullName(), middle: {str: "a"}})); - assert.commandWorked(collationDB.adminCommand( - {moveChunk: caseInsensitive.getFullName(), find: {str: "FOO"}, to: "shard0000"})); - assert.commandWorked(collationDB.adminCommand( - {moveChunk: caseInsensitive.getFullName(), find: {str: "foo"}, to: "shard0001"})); - assert.writeOK(caseInsensitive.insert({str: "FOO"})); - assert.writeOK(caseInsensitive.insert({str: "foo"})); - - // Ensure the featureCompatibilityVersion is 3.2. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); - - // Aggregate rejects the collation parameter when the featureCompatibilityVersion is 3.2. - assert.throws(function() { - caseInsensitive.aggregate([], {collation: {locale: "en_US"}}); - }); - assert.throws(function() { - caseInsensitive.aggregate([], {explain: true, collation: {locale: "en_US"}}); - }); - - // Aggregate respects the collection default collation in both halves of the pipeline when the - // featureCompatibilityVersion is 3.2. - assert.eq([{count: 2}], - caseInsensitive - .aggregate([ - {$match: {str: "foo"}}, - {$group: {_id: "$str", count: {$sum: 1}}}, - {$project: {_id: 0, count: 1}} - ]) - .toArray()); - - st.stop(); -}()); diff --git a/jstests/noPassthrough/feature_compatibility_version.js b/jstests/noPassthrough/feature_compatibility_version.js index d9c1368b15b..9645ed79163 100644 --- a/jstests/noPassthrough/feature_compatibility_version.js +++ b/jstests/noPassthrough/feature_compatibility_version.js @@ -9,72 +9,79 @@ let adminDB = conn.getDB("admin"); - // Initially the featureCompatibilityVersion is 3.4. + // Initially the featureCompatibilityVersion is 3.6. let res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.4", res.featureCompatibilityVersion); + assert.eq("3.6", res.featureCompatibilityVersion); // Updating the featureCompatibilityVersion document changes the featureCompatibilityVersion // server parameter. assert.writeOK(adminDB.system.version.update({_id: "featureCompatibilityVersion"}, - {$set: {version: "3.2"}})); + {$set: {version: "3.4"}})); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); + assert.eq("3.4", res.featureCompatibilityVersion); assert.writeOK(adminDB.system.version.update({_id: "featureCompatibilityVersion"}, - {$set: {version: "3.4"}})); + {$set: {version: "3.6"}})); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.4", res.featureCompatibilityVersion); + assert.eq("3.6", res.featureCompatibilityVersion); // Updating the featureCompatibilityVersion document with an invalid version fails. assert.writeErrorWithCode(adminDB.system.version.update({_id: "featureCompatibilityVersion"}, - {$set: {version: "3.6"}}), + {$set: {version: "3.2"}}), ErrorCodes.BadValue); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.4", res.featureCompatibilityVersion); + assert.eq("3.6", res.featureCompatibilityVersion); // Deleting the featureCompatibilityVersion document changes the featureCompatibilityVersion - // server parameter to 3.2. + // server parameter to 3.4. assert.writeOK(adminDB.system.version.remove({_id: "featureCompatibilityVersion"})); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); + assert.eq("3.4", res.featureCompatibilityVersion); // Inserting a featureCompatibilityVersion document with an invalid version fails. assert.writeErrorWithCode( - adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.6"}), + adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.2"}), + ErrorCodes.BadValue); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq("3.4", res.featureCompatibilityVersion); + + assert.writeErrorWithCode( + adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.8"}), ErrorCodes.BadValue); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); + assert.eq("3.4", res.featureCompatibilityVersion); // Inserting the featureCompatibilityVersion document changes the featureCompatibilityVersion // server parameter. assert.writeOK( - adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.2"})); + adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.4"})); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); + assert.eq("3.4", res.featureCompatibilityVersion); assert.writeOK(adminDB.system.version.remove({_id: "featureCompatibilityVersion"})); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); + assert.eq("3.4", res.featureCompatibilityVersion); assert.writeOK( - adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.4"})); + adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.6"})); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.4", res.featureCompatibilityVersion); + assert.eq("3.6", res.featureCompatibilityVersion); - // Dropping the admin database changes the featureCompatibilityVersion server parameter to 3.2. + // Dropping the admin database changes the featureCompatibilityVersion server parameter to 3.4. adminDB.dropDatabase(); res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); + assert.eq("3.4", res.featureCompatibilityVersion); MongoRunner.stopMongod(conn); }()); diff --git a/jstests/noPassthrough/index_version_autoupgrade.js b/jstests/noPassthrough/index_version_autoupgrade.js index b7dcd5c7f35..c9b4e523448 100644 --- a/jstests/noPassthrough/index_version_autoupgrade.js +++ b/jstests/noPassthrough/index_version_autoupgrade.js @@ -7,15 +7,8 @@ load("jstests/libs/get_index_helpers.js"); - function getFeatureCompatibilityVersion(conn) { - const res = assert.commandWorked( - conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - return res.featureCompatibilityVersion; - } - var conn = MongoRunner.runMongod({}); assert.neq(null, conn, "mongod was unable to start up"); - assert.eq("3.4", getFeatureCompatibilityVersion(conn)); var testDB = conn.getDB("test"); assert.commandWorked(testDB.runCommand({create: "index_version_autoupgrade"})); @@ -42,10 +35,9 @@ testDB.dropDatabase(); var coll = testDB.index_version_autoupgrade; - // 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"})); + // Create a v=1 _id index. + assert.commandWorked(testDB.createCollection( + "index_version_autoupgrade", {idIndex: {key: {_id: 1}, name: "_id_", v: 1}})); var allIndexes = coll.getIndexes(); var spec = GetIndexHelpers.findByKeyPattern(allIndexes, {_id: 1}); assert.neq(null, spec, "Index with key pattern {_id: 1} not found: " + tojson(allIndexes)); @@ -151,7 +143,6 @@ // version. var 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({ @@ -165,7 +156,6 @@ // 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({ diff --git a/jstests/noPassthrough/index_version_v2.js b/jstests/noPassthrough/index_version_v2.js index 3b90b24109d..e84f206394a 100644 --- a/jstests/noPassthrough/index_version_v2.js +++ b/jstests/noPassthrough/index_version_v2.js @@ -1,7 +1,5 @@ /** - * Tests the interaction of the default index version and the featureCompatibilityVersion: - * - Index version v=2 is the default when the featureCompatibilityVersion is 3.4 - * - Index version v=1 is the default when the featureCompatibilityVersion is 3.2 + * Tests that index version v=2 is the default. * * Additionally, this file tests that index version v=2 is required to create an index with a * collation and that index version v=2 is required to index decimal data on storage engines using @@ -12,12 +10,6 @@ const storageEnginesUsingKeyString = new Set(["wiredTiger", "inMemory", "rocksdb"]); - function getFeatureCompatibilityVersion(conn) { - const res = assert.commandWorked( - conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - return res.featureCompatibilityVersion; - } - function getIndexSpecByName(coll, indexName) { const indexes = coll.getIndexes(); const indexesFilteredByName = indexes.filter(spec => spec.name === indexName); @@ -29,57 +21,52 @@ const conn = MongoRunner.runMongod({}); assert.neq(null, conn, "mongod was unable to start up"); - assert.eq("3.4", getFeatureCompatibilityVersion(conn)); const testDB = conn.getDB("test"); const storageEngine = testDB.serverStatus().storageEngine.name; // - // Index version v=2 and featureCompatibilityVersion=3.4 + // Index version v=2 // testDB.dropDatabase(); - // Test that the _id index of a collection is created with v=2 when the - // featureCompatibilityVersion is 3.4. + // Test that the _id index of a collection is created with v=2 by default. assert.commandWorked(testDB.runCommand({create: "index_version"})); let indexSpec = getIndexSpecByName(testDB.index_version, "_id_"); assert.eq(2, indexSpec.v, tojson(indexSpec)); - // Test that an index created on an existing collection is created with v=2 when the - // featureCompatibilityVersion is 3.4. + // Test that an index created on an existing collection is created with v=2 by default. assert.commandWorked(testDB.index_version.createIndex({defaultToV2: 1}, {name: "defaultToV2"})); indexSpec = getIndexSpecByName(testDB.index_version, "defaultToV2"); assert.eq(2, indexSpec.v, tojson(indexSpec)); - // Test that creating an index with v=2 succeeds when the featureCompatibilityVersion is 3.4. + // Test that creating an index with v=2 succeeds. assert.commandWorked(testDB.index_version.createIndex({withV2: 1}, {v: 2, name: "withV2"})); indexSpec = getIndexSpecByName(testDB.index_version, "withV2"); assert.eq(2, indexSpec.v, tojson(indexSpec)); - // Test that creating a collection with a non-simple default collation succeeds when the - // featureCompatibilityVersion is 3.4. + // Test that creating a collection with a non-simple default collation succeeds. assert.commandWorked(testDB.runCommand({create: "collation", collation: {locale: "en"}})); indexSpec = getIndexSpecByName(testDB.collation, "_id_"); assert.eq(2, indexSpec.v, tojson(indexSpec)); - // Test that creating an index with a non-simple collation succeeds when the - // featureCompatibilityVersion is 3.4. + // Test that creating an index with a non-simple collation succeeds. assert.commandWorked( testDB.collation.createIndex({str: 1}, {name: "withCollation", collation: {locale: "fr"}})); indexSpec = getIndexSpecByName(testDB.collation, "withCollation"); assert.eq(2, indexSpec.v, tojson(indexSpec)); - // Test that indexing decimal data succeeds when the featureCompatibilityVersion is 3.4. + // Test that indexing decimal data succeeds. assert.writeOK(testDB.decimal.insert({_id: new NumberDecimal("42")})); // - // Index version v=1 and featureCompatibilityVersion=3.4 + // Index version v=1 // testDB.dropDatabase(); - // Test that creating an index with v=1 succeeds when the featureCompatibilityVersion is 3.4. + // Test that creating an index with v=1 succeeds. assert.commandWorked(testDB.index_version.createIndex({withV1: 1}, {v: 1, name: "withV1"})); indexSpec = getIndexSpecByName(testDB.index_version, "withV1"); assert.eq(1, indexSpec.v, tojson(indexSpec)); @@ -117,113 +104,7 @@ } // - // Index version v=0 and featureCompatibilityVersion=3.4 - // - - testDB.dropDatabase(); - - // Test that attempting to create an index with v=0 returns an error. - assert.commandFailed(testDB.index_version.createIndex({withV0: 1}, {v: 0})); - - // - // Index version v=3 and featureCompatibilityVersion=3.4 - // - - testDB.dropDatabase(); - - // Test that attempting to create an index with v=3 returns an error. - assert.commandFailed(testDB.index_version.createIndex({withV3: 1}, {v: 3})); - - // - // Index version v=1 and featureCompatibilityVersion=3.2 - // - - // Set the featureCompatibilityVersion to 3.2. - assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - assert.eq("3.2", getFeatureCompatibilityVersion(conn)); - testDB.dropDatabase(); - - // Test that the _id index of a collection is created with v=1 when the - // featureCompatibilityVersion is 3.2. - assert.commandWorked(testDB.runCommand({create: "index_version"})); - indexSpec = getIndexSpecByName(testDB.index_version, "_id_"); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - - // Test that the _id index of a collection is created with v=1 when the - // featureCompatibilityVersion is 3.2 and an "idIndex" spec is provided without a version. - testDB.index_version.drop(); - assert.commandWorked( - testDB.runCommand({create: "index_version", idIndex: {key: {_id: 1}, name: "_id_"}})); - indexSpec = getIndexSpecByName(testDB.index_version, "_id_"); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - - // Test that an index created on an existing collection is created with v=1 when the - // featureCompatibilityVersion is 3.2. - assert.commandWorked(testDB.index_version.createIndex({defaultToV1: 1}, {name: "defaultToV1"})); - indexSpec = getIndexSpecByName(testDB.index_version, "defaultToV1"); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - - // Test that creating an index with v=1 succeeds when the featureCompatibilityVersion is 3.2. - assert.commandWorked(testDB.index_version.createIndex({withV1: 1}, {v: 1, name: "withV1"})); - indexSpec = getIndexSpecByName(testDB.index_version, "withV1"); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - - // Test that creating a collection with a non-simple default collation returns an error when the - // featureCompatibilityVersion is 3.2. - assert.commandFailed(testDB.runCommand({create: "collation", collation: {locale: "en"}})); - - // Test that creating an index with a non-simple collation returns an error when the - // featureCompatibilityVersion is 3.2. - assert.commandFailed(testDB.collation.createIndex({str: 1}, {collation: {locale: "fr"}})); - - // Test that creating a collection with a non-simple default collation and without an _id index - // succeeds when the featureCompatibilityVersion is 3.2. - testDB.collation.drop(); - assert.commandFailed( - testDB.runCommand({create: "collation", collation: {locale: "en"}, autoIndexId: false})); - - // Test that creating a collection with a simple default collation and without an _id index - // succeeds when the featureCompatibilityVersion is 3.2. - testDB.collation.drop(); - assert.commandFailed(testDB.runCommand( - {create: "collation", collation: {locale: "simple"}, autoIndexId: false})); - - // Test that creating a collection with a simple default collation succeeds when the - // featureCompatibilityVersion is 3.2. - testDB.collation.drop(); - assert.commandFailed(testDB.runCommand({create: "collation", collation: {locale: "simple"}})); - - // Test that creating an index with a simple collation returns an error when the - // featureCompatibilityVersion is 3.2. - assert.commandFailed(testDB.collation.createIndex( - {str: 1}, {name: "withSimpleCollation", collation: {locale: "simple"}})); - - // Test that inserting decimal data (both indexed and unindexed) returns an error when the - // featureCompatibilityVersion is 3.2. - assert.writeErrorWithCode(testDB.decimal.insert({_id: new NumberDecimal("42")}), - ErrorCodes.InvalidBSON); - assert.writeErrorWithCode(testDB.decimal.insert({num: new NumberDecimal("42")}), - ErrorCodes.InvalidBSON); - - // - // Index version v=2 and featureCompatibilityVersion=3.2 - // - - testDB.dropDatabase(); - - // Test that attempting to create an index with v=2 when the featureCompatibilityVersion is 3.2 - // returns an error. - assert.commandFailed(testDB.index_version.createIndex({withV2: 1}, {v: 2, name: "withV2"})); - - testDB.dropDatabase(); - - // Test that attempting to create an _id index with v=2 when the featureCompatibilityVersion is - // 3.2 returns an error. - assert.commandFailed( - testDB.runCommand({create: "index_version", idIndex: {key: {_id: 1}, name: "_id_", v: 2}})); - - // - // Index version v=0 and featureCompatibilityVersion=3.2 + // Index version v=0 // testDB.dropDatabase(); @@ -232,7 +113,7 @@ assert.commandFailed(testDB.index_version.createIndex({withV0: 1}, {v: 0})); // - // Index version v=3 and featureCompatibilityVersion=3.2 + // Index version v=3 // testDB.dropDatabase(); diff --git a/jstests/noPassthrough/internal_validate_features_as_master.js b/jstests/noPassthrough/internal_validate_features_as_master.js index f3ea92b3bd4..1ae2a7764e2 100644 --- a/jstests/noPassthrough/internal_validate_features_as_master.js +++ b/jstests/noPassthrough/internal_validate_features_as_master.js @@ -1,5 +1,4 @@ -// Test that featureCompatibilityVersion checks are skipped when -// internalValidateFeaturesAsMaster=false. +// Tests the internalValidateFeaturesAsMaster server parameter. (function() { "use strict"; @@ -42,122 +41,4 @@ assert.commandFailed( conn.adminCommand({setParameter: 1, internalValidateFeaturesAsMaster: false})); MongoRunner.stopMongod(conn); - - // - // featureCompatibilityVersion checks are skipped for internalValidateFeaturesAsMaster=false. - // - - conn = MongoRunner.runMongod({setParameter: "internalValidateFeaturesAsMaster=0"}); - assert.neq(null, conn, "mongod was unable to start up"); - res = conn.adminCommand({getParameter: 1, internalValidateFeaturesAsMaster: 1}); - assert.commandWorked(res); - assert.eq(res.internalValidateFeaturesAsMaster, false); - - assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - res = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq(res.featureCompatibilityVersion, "3.2"); - - let testDB = conn.getDB("test"); - let coll = testDB.internalValidateFeaturesAsMaster; - testDB.dropDatabase(); - - // Decimal check is skipped. - assert.writeOK(coll.insert({a: NumberDecimal(2.0)})); - - // Even with internalValidateFeaturesAsMaster=false, the validate command should fail when it - // finds decimal data. - let validateResult = coll.validate({full: true}); - assert.commandWorked(validateResult); - assert.eq(false, validateResult.valid, tojson(validateResult)); - - coll.drop(); - - // Collection creation with collation check is skipped. - assert.commandWorked(testDB.createCollection("internalValidateFeaturesAsMaster", - {collation: {locale: "en_US"}})); - coll.drop(); - - // v=2 index check is skipped. - assert.commandWorked(coll.createIndex({a: 1}, {name: "a_1", v: 2})); - let indexSpec = GetIndexHelpers.findByName(coll.getIndexes(), "a_1"); - assert.neq(indexSpec, null); - assert.eq(indexSpec.v, 2); - coll.drop(); - - // Default index version is not affected by internalValidateFeaturesAsMaster=false. - assert.commandWorked(coll.createIndex({a: 1})); - indexSpec = GetIndexHelpers.findByName(coll.getIndexes(), "a_1"); - assert.neq(indexSpec, null); - assert.eq(indexSpec.v, 1); - indexSpec = GetIndexHelpers.findByName(coll.getIndexes(), "_id_"); - assert.neq(indexSpec, null); - assert.eq(indexSpec.v, 1); - coll.drop(); - - // View creation/modification check is skipped. - assert.commandWorked(testDB.runCommand( - {create: "view", viewOn: "internalValidateFeaturesAsMaster", pipeline: []})); - assert.commandWorked(testDB.runCommand({collMod: "view", pipeline: []})); - - // Check for dropping system.views is skipped. - assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.4"})); - res = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq(res.featureCompatibilityVersion, "3.4"); - - assert.eq(testDB.system.views.drop(), true); - - MongoRunner.stopMongod(conn); - - // - // featureCompatibilityVersion checks are enforced for internalValidateFeaturesAsMaster=true. - // - - conn = MongoRunner.runMongod({setParameter: "internalValidateFeaturesAsMaster=1"}); - assert.neq(null, conn, "mongod was unable to start up"); - res = conn.adminCommand({getParameter: 1, internalValidateFeaturesAsMaster: 1}); - assert.commandWorked(res); - assert.eq(res.internalValidateFeaturesAsMaster, true); - - assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - res = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq(res.featureCompatibilityVersion, "3.2"); - - testDB = conn.getDB("test"); - coll = testDB.internalValidateFeaturesAsMaster; - testDB.dropDatabase(); - - // Decimal check is enforced. - assert.writeError(coll.insert({a: NumberDecimal(2.0)})); - - // Collection creation with collation check is enforced. - assert.commandFailed(testDB.createCollection("internalValidateFeaturesAsMaster", - {collation: {locale: "en_US"}})); - - // v=2 index check is enforced. - assert.commandFailed(coll.createIndex({a: 1}, {name: "a_1", v: 2})); - - // View creation/modification check is enforced. - assert.commandFailed(testDB.runCommand( - {create: "view", viewOn: "internalValidateFeaturesAsMaster", pipeline: []})); - - // Set featureCompatibilityVersion=3.4 so that we can create a view to modify. - assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.4"})); - res = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq(res.featureCompatibilityVersion, "3.4"); - - assert.commandWorked(testDB.runCommand( - {create: "view", viewOn: "internalValidateFeaturesAsMaster", pipeline: []})); - - assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - res = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq(res.featureCompatibilityVersion, "3.2"); - - assert.commandFailed(testDB.runCommand({collMod: "view", pipeline: []})); - - MongoRunner.stopMongod(conn); }()); diff --git a/jstests/noPassthrough/views_feature_compatibility_version.js b/jstests/noPassthrough/views_feature_compatibility_version.js deleted file mode 100644 index ea0c609d253..00000000000 --- a/jstests/noPassthrough/views_feature_compatibility_version.js +++ /dev/null @@ -1,64 +0,0 @@ -// Test that views are only enabled if featureCompatibilityVersion is 3.4. - -(function() { - "use strict"; - - const conn = MongoRunner.runMongod({}); - assert.neq(null, conn, "mongod was unable to start up"); - - const viewsDB = conn.getDB("views_feature_compatibility_version"); - assert.commandWorked(viewsDB.dropDatabase()); - assert.commandWorked(viewsDB.runCommand({create: "collection"})); - assert.commandWorked(viewsDB.runCommand({create: "collection2"})); - - const adminDB = conn.getDB("admin"); - - // Ensure the featureCompatibilityVersion is 3.4. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); - let res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq("3.4", res.featureCompatibilityVersion); - - // We can create a view when the featureCompatibilityVersion is 3.4. - assert.commandWorked(viewsDB.runCommand({create: "view", viewOn: "collection", pipeline: []})); - - // We can update a view when the featureCompatibilityVersion is 3.4. - assert.commandWorked(viewsDB.runCommand({collMod: "view", pipeline: []})); - - // We can perform deletes on the system.views collection when the featureCompatibilityVersion is - // 3.4. - assert.writeOK(viewsDB.system.views.remove({_id: "views_feature_compatibility_version.view2"})); - - // Ensure the featureCompatibilityVersion is 3.2. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); - res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion); - - // We cannot create views when the featureCompatibilityVersion is 3.2. - assert.commandFailed(viewsDB.runCommand({create: "view2", viewOn: "collection", pipeline: []})); - - // We cannot update views when the featureCompatibilityVersion is 3.2. - assert.commandFailed(viewsDB.runCommand({collMod: "view", pipeline: []})); - - // We can read from a view when the featureCompatibilityVersion is 3.2. - assert.writeOK(viewsDB.collection.insert({a: 5})); - assert.eq(5, viewsDB.view.findOne().a); - - // We cannot create a collection with the same name as a view when the - // featureCompatibilityVersion is 3.2. - assert.commandFailed(viewsDB.runCommand({create: "view"})); - assert.writeError(viewsDB.view.insert({a: 5})); - - // We can drop a view namespace when the featureCompatibilityVersion is 3.2. - assert.eq(true, viewsDB.view.drop()); - - // We can perform deletes on the system.views collection when the featureCompatibilityVersion is - // 3.2. - assert.writeOK(viewsDB.system.views.remove({_id: "views_feature_compatibility_version.view"})); - - // We can drop the system.views collection when the featureCompatibilityVersion is 3.2. - assert.eq(true, viewsDB.system.views.drop()); - - MongoRunner.stopMongod(conn); -}()); diff --git a/jstests/replsets/id_index_replication.js b/jstests/replsets/id_index_replication.js index b7e884baf54..764619013ea 100644 --- a/jstests/replsets/id_index_replication.js +++ b/jstests/replsets/id_index_replication.js @@ -50,18 +50,6 @@ assert.eq(1, spec.v, "Expected primary to build a v=1 _id index: " + tojson(spec)); testOplogEntryIdIndexSpec("version_v1", null); - assert.commandWorked(primaryDB.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - var res = primaryDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); - assert.commandWorked(res); - assert.eq("3.2", res.featureCompatibilityVersion, tojson(res)); - - assert.commandWorked(primaryDB.createCollection("without_version_FCV32")); - allIndexes = primaryDB.without_version_FCV32.getIndexes(); - spec = GetIndexHelpers.findByKeyPattern(allIndexes, {_id: 1}); - assert.neq(null, spec, "_id index not found: " + tojson(allIndexes)); - assert.eq(1, spec.v, "Expected primary to build a v=1 _id index: " + tojson(spec)); - testOplogEntryIdIndexSpec("without_version_FCV32", null); - rst.awaitReplication(); // Verify that the secondary built _id indexes with the same version as on the primary. @@ -87,10 +75,5 @@ assert.neq(null, spec, "_id index not found: " + tojson(allIndexes)); assert.eq(1, spec.v, "Expected secondary to implicitly build a v=1 _id index: " + tojson(spec)); - allIndexes = secondaryDB.without_version_FCV32.getIndexes(); - spec = GetIndexHelpers.findByKeyPattern(allIndexes, {_id: 1}); - assert.neq(null, spec, "_id index not found: " + tojson(allIndexes)); - assert.eq(1, spec.v, "Expected secondary to implicitly build a v=1 _id index: " + tojson(spec)); - rst.stopSet(); })(); diff --git a/jstests/replsets/initial_sync_decimal.js b/jstests/replsets/initial_sync_decimal.js deleted file mode 100644 index b518f511aff..00000000000 --- a/jstests/replsets/initial_sync_decimal.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Tests that we can initial sync decimal128 data to secondaries, even when the cluster is in 3.2 - * feature compatibility mode. - */ -(function() { - "use strict"; - - // Decimal data with feature compatibility version 3.2 causes collection - // validation failure. - // TODO: SERVER-29350 Remove this code when feature compatibility version 3.2 is removed. - TestData.skipCollectionAndIndexValidation = true; - - var replTest = new ReplSetTest({name: 'testSet', nodes: 2}); - - var nodes = replTest.startSet(); - replTest.initiate(); - - var primary = replTest.getPrimary(); - var primaryDB = primary.getDB("test"); - var primaryColl = primaryDB.initial_sync_decimal; - - var secondary = replTest.getSecondary(); - - // Since we started a fresh replica set, we should be in 3.4 feature compatibility mode. - var fcv = assert.commandWorked( - primaryDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - assert.eq(fcv.featureCompatibilityVersion, "3.4"); - - // Make sure we can insert decimal data in 3.4 mode. - assert.writeOK(primaryColl.insert({a: 1, b: NumberDecimal(1)})); - - // Set 3.2 feature compatibility mode. - assert.commandWorked(primaryDB.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - fcv = assert.commandWorked( - primaryDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); - assert.eq(fcv.featureCompatibilityVersion, "3.2"); - - // Ensure 3.2 feature compatibility version has synced to admin.system.version. - fcv = secondary.getDB("admin") - .system.version.find({_id: "featureCompatibilityVersion"}) - .toArray(); - assert.eq(1, fcv.length); - assert.eq("3.2", fcv[0].version); - - // We shouldn't be able to insert decimal data in 3.2 mode. - assert.writeError(primaryColl.insert({a: 1, b: NumberDecimal(1)})); - - // We should, however, be able to initial sync decimal data. - assert.commandWorked(secondary.getDB("admin").runCommand({resync: 1})); - replTest.awaitSecondaryNodes(); - - // Ensure that secondary is still up and has the data. - var secondaryColl = secondary.getDB("test").initial_sync_decimal; - assert.eq(1, secondaryColl.find({b: NumberDecimal(1)}).itcount()); - - replTest.stopSet(); -})(); diff --git a/jstests/sharding/auth_copydb.js b/jstests/sharding/auth_copydb.js index 4c215f666f7..6c30e847f8a 100644 --- a/jstests/sharding/auth_copydb.js +++ b/jstests/sharding/auth_copydb.js @@ -10,6 +10,10 @@ var sourceMongodConn = MongoRunner.runMongod({}); var sourceTestDB = sourceMongodConn.getDB('test'); + // Ensure sourceMongodConn has featureCompatibilityVersion=3.4, so that the sharded cluster can + // communicate with it if it has featureCompatibilityVersion=3.4. + assert.commandWorked(sourceMongodConn.adminCommand({setFeatureCompatibilityVersion: "3.4"})); + sourceTestDB.foo.insert({a: 1}); destAdminDB.createUser({ diff --git a/jstests/sharding/autodiscover_config_rs_from_secondary.js b/jstests/sharding/autodiscover_config_rs_from_secondary.js index d6d9dcdeb7a..a3e2c115004 100644 --- a/jstests/sharding/autodiscover_config_rs_from_secondary.js +++ b/jstests/sharding/autodiscover_config_rs_from_secondary.js @@ -14,6 +14,10 @@ conf.writeConcernMajorityJournalDefault = true; rst.initiate(conf); + // Ensure the featureCompatibilityVersion is 3.4 so that the mongos can connect if it is version + // 3.4. + assert.commandWorked(rst.getPrimary().adminCommand({setFeatureCompatibilityVersion: "3.4"})); + var seedList = rst.name + "/" + rst.nodes[1].host; // node 1 is guaranteed to not be primary { // Ensure that mongos can start up when given the CSRS secondary, discover the primary, and diff --git a/jstests/sharding/config_rs_change.js b/jstests/sharding/config_rs_change.js index 62e6a8f99e4..219e37b751b 100644 --- a/jstests/sharding/config_rs_change.js +++ b/jstests/sharding/config_rs_change.js @@ -8,6 +8,10 @@ var replConfig = configRS.getReplSetConfig(); replConfig.configsvr = true; configRS.initiate(replConfig); +// Ensure the featureCompatibilityVersion is 3.4 so that the mongos can connect if it is version +// 3.4. +assert.commandWorked(configRS.getPrimary().adminCommand({setFeatureCompatibilityVersion: "3.4"})); + // Build a seed list for the config servers to pass to mongos that uses "localhost" for the // hostnames even though the replica set config uses the hostname. var configHosts = []; diff --git a/jstests/sharding/max_time_ms_sharded_new_commands.js b/jstests/sharding/max_time_ms_sharded_new_commands.js index 373b4c5591d..48425438266 100644 --- a/jstests/sharding/max_time_ms_sharded_new_commands.js +++ b/jstests/sharding/max_time_ms_sharded_new_commands.js @@ -25,14 +25,14 @@ // Positive test for "setFeatureCompatibilityVersion" configureMaxTimeAlwaysTimeOut("alwaysOn"); assert.commandFailedWithCode( - admin.runCommand({setFeatureCompatibilityVersion: '3.2', maxTimeMS: 1000 * 60 * 60 * 24}), + admin.runCommand({setFeatureCompatibilityVersion: '3.4', maxTimeMS: 1000 * 60 * 60 * 24}), ErrorCodes.ExceededTimeLimit, "expected setFeatureCompatibilityVersion to fail due to maxTimeAlwaysTimeOut fail point"); // Negative test for "setFeatureCompatibilityVersion" configureMaxTimeAlwaysTimeOut("off"); assert.commandWorked( - admin.runCommand({setFeatureCompatibilityVersion: '3.2', maxTimeMS: 1000 * 60 * 60 * 24}), + admin.runCommand({setFeatureCompatibilityVersion: '3.4', maxTimeMS: 1000 * 60 * 60 * 24}), "expected setFeatureCompatibilityVersion to not hit time limit in mongod"); st.stop(); diff --git a/jstests/sharding/mongos_wait_csrs_initiate.js b/jstests/sharding/mongos_wait_csrs_initiate.js index 988aa7dcb5e..fb3cde633c4 100644 --- a/jstests/sharding/mongos_wait_csrs_initiate.js +++ b/jstests/sharding/mongos_wait_csrs_initiate.js @@ -13,6 +13,10 @@ assert.throws(function() { jsTestLog("Initiating CSRS"); configRS.initiate(replConfig); +// Ensure the featureCompatibilityVersion is 3.4 so that the mongos can connect if it is version +// 3.4. +assert.commandWorked(configRS.getPrimary().adminCommand({setFeatureCompatibilityVersion: "3.4"})); + jsTestLog("getting mongos"); var e; assert.soon( diff --git a/jstests/sharding/shard_collection_basic.js b/jstests/sharding/shard_collection_basic.js index a17336eb99e..e9786c5bb4e 100644 --- a/jstests/sharding/shard_collection_basic.js +++ b/jstests/sharding/shard_collection_basic.js @@ -233,41 +233,19 @@ assert.commandFailed(mongos.adminCommand( {shardCollection: kDbName + '.foo', key: {a: 1}, collation: {locale: 'simple'}})); - // - // Feature compatibility version collation tests. - // - - // shardCollection should succeed on an empty collection with a non-simple default collation - // if feature compatibility version is 3.4. + // shardCollection should succeed on an empty collection with a non-simple default collation. mongos.getDB(kDbName).foo.drop(); assert.commandWorked( mongos.getDB(kDbName).createCollection('foo', {collation: {locale: 'en_US'}})); assert.commandWorked(mongos.adminCommand( {shardCollection: kDbName + '.foo', key: {a: 1}, collation: {locale: 'simple'}})); - // shardCollection should succeed on an empty collection with no default collation if feature - // compatibility version is 3.4. - mongos.getDB(kDbName).foo.drop(); - assert.commandWorked(mongos.getDB(kDbName).createCollection('foo')); - assert.commandWorked(mongos.adminCommand({shardCollection: kDbName + '.foo', key: {a: 1}})); - - // shardCollection should fail on a collection with a non-simple default collation if feature - // compatibility version is 3.2. - mongos.getDB(kDbName).foo.drop(); - assert.commandWorked( - mongos.getDB(kDbName).createCollection('foo', {collation: {locale: 'en_US'}})); - assert.commandWorked(mongos.adminCommand({setFeatureCompatibilityVersion: "3.2"})); - assert.commandFailed(mongos.adminCommand( - {shardCollection: kDbName + '.foo', key: {a: 1}, collation: {locale: 'simple'}})); - - // shardCollection should succeed on an empty collection with no default collation if feature - // compatibility version is 3.2. + // shardCollection should succeed on an empty collection with no default collation. mongos.getDB(kDbName).foo.drop(); assert.commandWorked(mongos.getDB(kDbName).createCollection('foo')); assert.commandWorked(mongos.adminCommand({shardCollection: kDbName + '.foo', key: {a: 1}})); mongos.getDB(kDbName).dropDatabase(); - assert.commandWorked(mongos.adminCommand({setFeatureCompatibilityVersion: "3.4"})); // // Tests for the shell helper sh.shardCollection(). diff --git a/src/mongo/bson/bson_validate.cpp b/src/mongo/bson/bson_validate.cpp index c2d97a6496e..efde629c8e2 100644 --- a/src/mongo/bson/bson_validate.cpp +++ b/src/mongo/bson/bson_validate.cpp @@ -253,18 +253,9 @@ Status validateElementInfo(Buffer* buffer, return Status::OK(); case NumberDecimal: - if (buffer->version() != BSONVersion::kV1_0) { - if (!buffer->skip(sizeof(Decimal128::Value))) - return makeError("Invalid bson", idElem, *elemName); - return Status::OK(); - } else { - return makeError( - "Cannot use decimal BSON type when the featureCompatibilityVersion " - "is 3.2. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility. Found decimal", - idElem, - *elemName); - } + if (!buffer->skip(sizeof(Decimal128::Value))) + return makeError("Invalid bson", idElem, *elemName); + return Status::OK(); case DBRef: status = buffer->readUTF8String(*elemName, nullptr); diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index 20180689ef7..ab20e3dd984 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -178,7 +178,6 @@ env.Library( '$BUILD_DIR/mongo/db/query/query', '$BUILD_DIR/mongo/db/repl/drop_pending_collection_reaper', '$BUILD_DIR/mongo/db/repl/serveronly', - '$BUILD_DIR/mongo/db/server_options_core', '$BUILD_DIR/mongo/db/service_context', '$BUILD_DIR/mongo/db/storage/mmap_v1/storage_mmapv1', '$BUILD_DIR/mongo/db/storage/key_string', diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index e6a0c2b64b6..04fdfc57442 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -1005,16 +1005,8 @@ public: virtual Status validate(const RecordId& recordId, const RecordData& record, size_t* dataSize) { BSONObj recordBson = record.toBson(); - // Secondaries are configured to always validate using the latest enabled BSON version. But - // users should be able to run collection validation on a secondary in "3.2" - // featureCompatibilityVersion in order to be alerted to the presence of NumberDecimal. - auto bsonValidationVersion = (serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) - ? BSONVersion::kV1_0 - : Validator<BSONObj>::enabledBSONVersion(); - - const Status status = - validateBSON(recordBson.objdata(), recordBson.objsize(), bsonValidationVersion); + const Status status = validateBSON( + recordBson.objdata(), recordBson.objsize(), Validator<BSONObj>::enabledBSONVersion()); if (status.isOK()) { *dataSize = recordBson.objsize(); } else { diff --git a/src/mongo/db/catalog/index_spec_validate_test.cpp b/src/mongo/db/catalog/index_spec_validate_test.cpp index 45e65b00d6f..bb4cc4c1c1f 100644 --- a/src/mongo/db/catalog/index_spec_validate_test.cpp +++ b/src/mongo/db/catalog/index_spec_validate_test.cpp @@ -65,7 +65,7 @@ BSONObj sorted(const BSONObj& obj) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotAnObject) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::TypeMismatch, @@ -89,7 +89,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotAnObject) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfFieldRepeatedInKeyPattern) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::BadValue, @@ -108,7 +108,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfFieldRepeatedInKeyPattern) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotPresent) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::FailedToParse, @@ -120,7 +120,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotPresent) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotAString) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::TypeMismatch, @@ -131,7 +131,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotAString) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotPresent) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ( @@ -141,7 +141,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotPresent) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsNotAString) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::TypeMismatch, @@ -162,7 +162,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsNotAString) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsEmptyString) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::BadValue, @@ -176,7 +176,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsEmptyString) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceDoesNotMatch) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::BadValue, @@ -200,7 +200,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceDoesNotMatch) { TEST(IndexSpecValidateTest, ReturnsIndexSpecWithNamespaceFilledInIfItIsNotPresent) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -226,7 +226,7 @@ TEST(IndexSpecValidateTest, ReturnsIndexSpecWithNamespaceFilledInIfItIsNotPresen TEST(IndexSpecValidateTest, ReturnsIndexSpecUnchangedIfNamespaceAndVersionArePresent) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -251,7 +251,7 @@ TEST(IndexSpecValidateTest, ReturnsIndexSpecUnchangedIfNamespaceAndVersionArePre TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotANumber) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::TypeMismatch, @@ -272,7 +272,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotANumber) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::BadValue, @@ -307,7 +307,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsV0) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::CannotCreateIndex, @@ -321,7 +321,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsV0) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsUnsupported) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::CannotCreateIndex, @@ -344,46 +344,9 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsUnsupported) { featureCompatibility)); } -TEST(IndexSpecValidateTest, ReturnsAnErrorIfIndexVersionIsV2AndFeatureCompatibilityVersionIs32) { - ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k32); - featureCompatibility.validateFeaturesAsMaster.store(true); - - ASSERT_EQ(ErrorCodes::CannotCreateIndex, - validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "v" - << 2), - kTestNamespace, - featureCompatibility)); -} - -TEST(IndexSpecValidateTest, AcceptsIndexVersionV2WhenValidateFeaturesAsMasterFalse) { - ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k32); - featureCompatibility.validateFeaturesAsMaster.store(false); - - auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "v" - << 2), - kTestNamespace, - featureCompatibility); - ASSERT_OK(result.getStatus()); - - // We don't care about the order of the fields in the resulting index specification. - ASSERT_BSONOBJ_EQ(sorted(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "ns" - << kTestNamespace.ns() - << "v" - << 2)), - sorted(result.getValue())); -} - TEST(IndexSpecValidateTest, AcceptsIndexVersionsThatAreAllowedForCreation) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -421,62 +384,9 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionsThatAreAllowedForCreation) { sorted(result.getValue())); } -TEST(IndexSpecValidateTest, DefaultIndexVersionIsV1IfFeatureCompatibilityVersionIs32) { - ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k32); - featureCompatibility.validateFeaturesAsMaster.store(true); - - auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "ns" - << kTestNamespace.ns()), - kTestNamespace, - featureCompatibility); - ASSERT_OK(result.getStatus()); - - // We don't care about the order of the fields in the resulting index specification. - ASSERT_BSONOBJ_EQ(sorted(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "ns" - << kTestNamespace.ns() - << "v" - << 1)), - sorted(result.getValue())); - - // Verify that the index specification we returned is still considered valid. - ASSERT_OK(validateIndexSpec(result.getValue(), kTestNamespace, featureCompatibility)); -} - -TEST(IndexSpecValidateTest, - DefaultIndexVersionIsV1IfFeatureCompatibilityVersionIs32AndValidateFeaturesAsMasterFalse) { - ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k32); - featureCompatibility.validateFeaturesAsMaster.store(false); - - auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "ns" - << kTestNamespace.ns()), - kTestNamespace, - featureCompatibility); - ASSERT_OK(result.getStatus()); - - // We don't care about the order of the fields in the resulting index specification. - ASSERT_BSONOBJ_EQ(sorted(BSON("key" << BSON("field" << 1) << "name" - << "indexName" - << "ns" - << kTestNamespace.ns() - << "v" - << 1)), - sorted(result.getValue())); - - // Verify that the index specification we returned is still considered valid. - ASSERT_OK(validateIndexSpec(result.getValue(), kTestNamespace, featureCompatibility)); -} - -TEST(IndexSpecValidateTest, DefaultIndexVersionIsV2IfFeatureCompatibilityVersionIs34) { +TEST(IndexSpecValidateTest, DefaultIndexVersionIsV2) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -500,9 +410,9 @@ TEST(IndexSpecValidateTest, DefaultIndexVersionIsV2IfFeatureCompatibilityVersion ASSERT_OK(validateIndexSpec(result.getValue(), kTestNamespace, featureCompatibility)); } -TEST(IndexSpecValidateTest, AcceptsIndexVersionV1WhenFeatureCompatibilityVersionIs34) { +TEST(IndexSpecValidateTest, AcceptsIndexVersionV1) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -525,7 +435,7 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionV1WhenFeatureCompatibilityVersion TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsNotAnObject) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::TypeMismatch, @@ -553,7 +463,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsNotAnObject) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsEmpty) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::BadValue, @@ -567,7 +477,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsEmpty) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsPresentAndVersionIsLessThanV2) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); ASSERT_EQ(ErrorCodes::CannotCreateIndex, @@ -584,7 +494,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsPresentAndVersionIsLessTh TEST(IndexSpecValidateTest, AcceptsAnyNonEmptyObjectValueForCollation) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -634,7 +544,7 @@ TEST(IndexSpecValidateTest, AcceptsAnyNonEmptyObjectValueForCollation) { TEST(IndexSpecValidateTest, AcceptsIndexSpecIfCollationIsPresentAndVersionIsEqualToV2) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -663,7 +573,7 @@ TEST(IndexSpecValidateTest, AcceptsIndexSpecIfCollationIsPresentAndVersionIsEqua TEST(IndexSpecValidateTest, ReturnsAnErrorIfUnknownFieldIsPresentInSpecV2) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" @@ -679,7 +589,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfUnknownFieldIsPresentInSpecV2) { TEST(IndexSpecValidateTest, ReturnsAnErrorIfUnknownFieldIsPresentInSpecV1) { ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k34); + featureCompatibility.version.store(ServerGlobalParams::FeatureCompatibility::Version::k36); featureCompatibility.validateFeaturesAsMaster.store(true); auto result = validateIndexSpec(BSON("key" << BSON("field" << 1) << "name" diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index a48936a12d6..ddd8fbcfb5d 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -115,7 +115,6 @@ env.Library( 'core', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/db_raii', - '$BUILD_DIR/mongo/db/index_d', ], ) diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index bb836ace5dd..b34eb049b0b 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -41,7 +41,6 @@ #include "mongo/db/query/plan_summary_stats.h" #include "mongo/db/query/view_response_formatter.h" #include "mongo/db/repl/replication_coordinator_global.h" -#include "mongo/db/server_options.h" #include "mongo/db/views/resolved_view.h" #include "mongo/util/log.h" @@ -111,14 +110,6 @@ public: return request.getStatus(); } - if (!request.getValue().getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - // Acquire the db read lock. AutoGetCollectionOrViewForReadCommand ctx(opCtx, request.getValue().getNs()); Collection* collection = ctx.getCollection(); @@ -175,16 +166,6 @@ public: return appendCommandStatus(result, request.getStatus()); } - if (!request.getValue().getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return appendCommandStatus( - result, - Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); - } - AutoGetCollectionOrViewForReadCommand ctx(opCtx, request.getValue().getNs()); Collection* collection = ctx.getCollection(); diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index f2760314ed7..bb59ebe0ba3 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -545,19 +545,6 @@ public: result.append("note", deprecationWarning); } - auto featureCompatibilityVersion = serverGlobalParams.featureCompatibility.version.load(); - auto validateFeaturesAsMaster = - serverGlobalParams.featureCompatibility.validateFeaturesAsMaster.load(); - if (ServerGlobalParams::FeatureCompatibility::Version::k32 == featureCompatibilityVersion && - validateFeaturesAsMaster && cmdObj.hasField("collation")) { - return appendCommandStatus( - result, - {ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to create a collection or " - "view with a default collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."}); - } - // Validate _id index spec and fill in missing fields. if (auto idIndexElem = cmdObj["idIndex"]) { if (cmdObj["viewOn"]) { diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index 6643c952395..521862f0ccf 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -59,7 +59,6 @@ #include "mongo/db/query/plan_summary_stats.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/db/query/view_response_formatter.h" -#include "mongo/db/server_options.h" #include "mongo/db/views/resolved_view.h" #include "mongo/stdx/memory.h" #include "mongo/util/log.h" @@ -125,14 +124,6 @@ public: return parsedDistinct.getStatus(); } - if (!parsedDistinct.getValue().getQuery()->getQueryRequest().getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); @@ -177,16 +168,6 @@ public: return appendCommandStatus(result, parsedDistinct.getStatus()); } - if (!parsedDistinct.getValue().getQuery()->getQueryRequest().getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return appendCommandStatus( - result, - Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); - } - AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp index 4fd5a6573e6..9184c309049 100644 --- a/src/mongo/db/commands/feature_compatibility_version.cpp +++ b/src/mongo/db/commands/feature_compatibility_version.cpp @@ -33,28 +33,21 @@ #include "mongo/db/commands/feature_compatibility_version.h" #include "mongo/base/status.h" -#include "mongo/db/catalog/collection_options.h" -#include "mongo/db/commands/feature_compatibility_version_command_parser.h" -#include "mongo/db/concurrency/write_conflict_exception.h" -#include "mongo/db/curop.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" -#include "mongo/db/index/index_descriptor.h" -#include "mongo/db/index_builder.h" #include "mongo/db/operation_context.h" -#include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/db/write_concern_options.h" #include "mongo/rpc/get_status_from_command_result.h" +#include "mongo/transport/transport_layer.h" #include "mongo/util/log.h" namespace mongo { using repl::UnreplicatedWritesBlock; -constexpr StringData FeatureCompatibilityVersion::k32IncompatibleIndexName; constexpr StringData FeatureCompatibilityVersion::kCollection; constexpr StringData FeatureCompatibilityVersion::kCommandName; constexpr StringData FeatureCompatibilityVersion::kDatabase; @@ -62,16 +55,6 @@ constexpr StringData FeatureCompatibilityVersion::kParameterName; constexpr StringData FeatureCompatibilityVersion::kVersionField; namespace { -const BSONObj k32IncompatibleIndexSpec = - BSON(IndexDescriptor::kIndexVersionFieldName - << static_cast<int>(IndexDescriptor::IndexVersion::kV2) - << IndexDescriptor::kKeyPatternFieldName - << BSON(FeatureCompatibilityVersion::kVersionField << 1) - << IndexDescriptor::kNamespaceFieldName - << FeatureCompatibilityVersion::kCollection - << IndexDescriptor::kIndexNameFieldName - << FeatureCompatibilityVersion::k32IncompatibleIndexName); - BSONObj makeUpdateCommand(StringData newVersion, BSONObj writeConcern) { BSONObjBuilder updateCmd; @@ -99,18 +82,6 @@ BSONObj makeUpdateCommand(StringData newVersion, BSONObj writeConcern) { return updateCmd.obj(); } - -StringData getFeatureCompatibilityVersionString( - ServerGlobalParams::FeatureCompatibility::Version version) { - switch (version) { - case ServerGlobalParams::FeatureCompatibility::Version::k34: - return FeatureCompatibilityVersionCommandParser::kVersion34; - case ServerGlobalParams::FeatureCompatibility::Version::k32: - return FeatureCompatibilityVersionCommandParser::kVersion32; - default: - MONGO_UNREACHABLE; - } -} } // namespace StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibilityVersion::parse( @@ -137,12 +108,12 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili << FeatureCompatibilityVersion::kCollection << ": " << featureCompatibilityVersionDoc - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); + << ". See http://dochub.mongodb.org/core/3.6-feature-compatibility."); } - if (elem.String() == FeatureCompatibilityVersionCommandParser::kVersion34) { + if (elem.String() == FeatureCompatibilityVersionCommandParser::kVersion36) { + version = ServerGlobalParams::FeatureCompatibility::Version::k36; + } else if (elem.String() == FeatureCompatibilityVersionCommandParser::kVersion34) { version = ServerGlobalParams::FeatureCompatibility::Version::k34; - } else if (elem.String() == FeatureCompatibilityVersionCommandParser::kVersion32) { - version = ServerGlobalParams::FeatureCompatibility::Version::k32; } else { return Status( ErrorCodes::BadValue, @@ -152,16 +123,16 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili << ", found " << elem.String() << ", expected '" - << FeatureCompatibilityVersionCommandParser::kVersion34 + << FeatureCompatibilityVersionCommandParser::kVersion36 << "' or '" - << FeatureCompatibilityVersionCommandParser::kVersion32 + << FeatureCompatibilityVersionCommandParser::kVersion34 << "'. Contents of " << FeatureCompatibilityVersion::kParameterName << " document in " << FeatureCompatibilityVersion::kCollection << ": " << featureCompatibilityVersionDoc - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); + << ". See http://dochub.mongodb.org/core/3.6-feature-compatibility."); } } else { return Status( @@ -172,7 +143,7 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili << FeatureCompatibilityVersion::kCollection << ": " << featureCompatibilityVersionDoc - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); + << ". See http://dochub.mongodb.org/core/3.6-feature-compatibility."); } } @@ -187,7 +158,7 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili << FeatureCompatibilityVersion::kCollection << ": " << featureCompatibilityVersionDoc - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); + << ". See http://dochub.mongodb.org/core/3.6-feature-compatibility."); } return version; @@ -195,96 +166,35 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili void FeatureCompatibilityVersion::set(OperationContext* opCtx, StringData version) { uassert(40284, - "featureCompatibilityVersion must be '3.4' or '3.2'. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.", - version == FeatureCompatibilityVersionCommandParser::kVersion34 || - version == FeatureCompatibilityVersionCommandParser::kVersion32); + "featureCompatibilityVersion must be '3.6' or '3.4'. See " + "http://dochub.mongodb.org/core/3.6-feature-compatibility.", + version == FeatureCompatibilityVersionCommandParser::kVersion36 || + version == FeatureCompatibilityVersionCommandParser::kVersion34); DBDirectClient client(opCtx); NamespaceString nss(FeatureCompatibilityVersion::kCollection); - if (version == FeatureCompatibilityVersionCommandParser::kVersion34) { - // We build a v=2 index on the "admin.system.version" collection as part of setting the - // featureCompatibilityVersion to 3.4. This is a new index version that isn't supported by - // versions of MongoDB earlier than 3.4 that will cause 3.2 secondaries to crash when it is - // replicated. - std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec}; - - { - AutoGetOrCreateDb autoDB(opCtx, nss.db(), MODE_X); - - uassert(ErrorCodes::NotMaster, - str::stream() << "Cannot set featureCompatibilityVersion to '" << version - << "'. Not primary while attempting to create index on: " - << nss.ns(), - repl::ReplicationCoordinator::get(opCtx->getServiceContext()) - ->canAcceptWritesFor(opCtx, nss)); - - // If the "admin.system.version" collection has not been created yet, explicitly create - // it to hold the v=2 index. - if (!autoDB.getDb()->getCollection(opCtx, nss)) { - uassertStatusOK( - repl::StorageInterface::get(opCtx)->createCollection(opCtx, nss, {})); - } - - IndexBuilder builder(k32IncompatibleIndexSpec, false); - auto status = builder.buildInForeground(opCtx, autoDB.getDb()); - uassertStatusOK(status); - - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - WriteUnitOfWork wuow(opCtx); - auto uuid = autoDB.getDb()->getCollection(opCtx, nss)->uuid(); - getGlobalServiceContext()->getOpObserver()->onCreateIndex( - opCtx, nss, uuid, k32IncompatibleIndexSpec, false); - wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "FeatureCompatibilityVersion::set", nss.ns()); - } - - // We then update the featureCompatibilityVersion document stored in the - // "admin.system.version" collection. We do this after creating the v=2 index in order to - // maintain the invariant that if the featureCompatibilityVersion is 3.4, then - // 'k32IncompatibleIndexSpec' index exists on the "admin.system.version" collection. - BSONObj updateResult; - client.runCommand(nss.db().toString(), - makeUpdateCommand(version, WriteConcernOptions::Majority), - updateResult); - uassertStatusOK(getStatusFromCommandResult(updateResult)); - uassertStatusOK(getWriteConcernStatusFromCommandResult(updateResult)); - - // We then update the value of the featureCompatibilityVersion server parameter. - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - } else if (version == FeatureCompatibilityVersionCommandParser::kVersion32) { - // We update the featureCompatibilityVersion document stored in the "admin.system.version" - // collection. We do this before dropping the v=2 index in order to maintain the invariant - // that if the featureCompatibilityVersion is 3.4, then 'k32IncompatibleIndexSpec' index - // exists on the "admin.system.version" collection. We don't attach a "majority" write - // concern to this update because we're going to do so anyway for the "dropIndexes" command. - BSONObj updateResult; - client.runCommand(nss.db().toString(), makeUpdateCommand(version, BSONObj()), updateResult); - uassertStatusOK(getStatusFromCommandResult(updateResult)); - - // We then drop the v=2 index on the "admin.system.version" collection to enable 3.2 - // secondaries to sync from this mongod. - BSONObjBuilder dropIndexesCmd; - dropIndexesCmd.append("dropIndexes", nss.coll()); - dropIndexesCmd.append("index", FeatureCompatibilityVersion::k32IncompatibleIndexName); - dropIndexesCmd.append("writeConcern", WriteConcernOptions::Majority); - - BSONObj dropIndexesResult; - client.runCommand(nss.db().toString(), dropIndexesCmd.done(), dropIndexesResult); - auto status = getStatusFromCommandResult(dropIndexesResult); - if (status != ErrorCodes::IndexNotFound) { - uassertStatusOK(status); - } - uassertStatusOK(getWriteConcernStatusFromCommandResult(dropIndexesResult)); - - // We then update the value of the featureCompatibilityVersion server parameter. - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k32); + // Update the featureCompatibilityVersion document stored in the "admin.system.version" + // collection. + BSONObj updateResult; + client.runCommand(nss.db().toString(), + makeUpdateCommand(version, WriteConcernOptions::Majority), + updateResult); + uassertStatusOK(getStatusFromCommandResult(updateResult)); + uassertStatusOK(getWriteConcernStatusFromCommandResult(updateResult)); + + // Close all internal connections to versions lower than 3.6. + if (version == FeatureCompatibilityVersionCommandParser::kVersion36) { + opCtx->getServiceContext()->getTransportLayer()->endAllSessions( + transport::Session::kLatestVersionInternalClientKeepOpen | + transport::Session::kExternalClientKeepOpen); } + + // Update the value of the featureCompatibilityVersion server parameter. + serverGlobalParams.featureCompatibility.version.store( + version == FeatureCompatibilityVersionCommandParser::kVersion36 + ? ServerGlobalParams::FeatureCompatibility::Version::k36 + : ServerGlobalParams::FeatureCompatibility::Version::k34); } void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* opCtx, @@ -303,42 +213,28 @@ void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* opCtx, UnreplicatedWritesBlock unreplicatedWritesBlock(opCtx); NamespaceString nss(FeatureCompatibilityVersion::kCollection); - // We build a v=2 index on the "admin.system.version" collection as part of setting the - // featureCompatibilityVersion to 3.4. This is a new index version that isn't supported by - // versions of MongoDB earlier than 3.4 that will cause 3.2 secondaries to crash when it is - // cloned. - std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec}; - { AutoGetOrCreateDb autoDB(opCtx, nss.db(), MODE_X); // We reached this point because the only database that exists on the server is "local" - // and we have just created an empty "admin" database. - // Therefore, it is safe to create the "admin.system.version" collection. + // and we have just created an empty "admin" database. Therefore, it is safe to create + // the "admin.system.version" collection. invariant(autoDB.justCreated()); uassertStatusOK(storageInterface->createCollection(opCtx, nss, {})); - - IndexBuilder builder(k32IncompatibleIndexSpec, false); - auto status = builder.buildInForeground(opCtx, autoDB.getDb()); - uassertStatusOK(status); } // We then insert the featureCompatibilityVersion document into the "admin.system.version" - // collection. We do this after creating the v=2 index in order to maintain the invariant - // that if the featureCompatibilityVersion is 3.4, then 'k32IncompatibleIndexSpec' index - // exists on the "admin.system.version" collection. If we happened to fail to insert the - // document when starting up, then on a subsequent start-up we'd no longer consider the data - // files "clean" and would instead be in featureCompatibilityVersion=3.2. + // collection. uassertStatusOK(storageInterface->insertDocument( opCtx, nss, BSON("_id" << FeatureCompatibilityVersion::kParameterName << FeatureCompatibilityVersion::kVersionField - << FeatureCompatibilityVersionCommandParser::kVersion34))); + << FeatureCompatibilityVersionCommandParser::kVersion36))); // We then update the value of the featureCompatibilityVersion server parameter. serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); + ServerGlobalParams::FeatureCompatibility::Version::k36); } } @@ -349,8 +245,7 @@ void FeatureCompatibilityVersion::onInsertOrUpdate(const BSONObj& doc) { return; } auto newVersion = uassertStatusOK(FeatureCompatibilityVersion::parse(doc)); - log() << "setting featureCompatibilityVersion to " - << getFeatureCompatibilityVersionString(newVersion); + log() << "setting featureCompatibilityVersion to " << toString(newVersion); serverGlobalParams.featureCompatibility.version.store(newVersion); } @@ -361,16 +256,16 @@ void FeatureCompatibilityVersion::onDelete(const BSONObj& doc) { return; } log() << "setting featureCompatibilityVersion to " - << FeatureCompatibilityVersionCommandParser::kVersion32; + << FeatureCompatibilityVersionCommandParser::kVersion34; serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k32); + ServerGlobalParams::FeatureCompatibility::Version::k34); } void FeatureCompatibilityVersion::onDropCollection() { log() << "setting featureCompatibilityVersion to " - << FeatureCompatibilityVersionCommandParser::kVersion32; + << FeatureCompatibilityVersionCommandParser::kVersion34; serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k32); + ServerGlobalParams::FeatureCompatibility::Version::k34); } /** @@ -387,7 +282,7 @@ public: virtual void append(OperationContext* opCtx, BSONObjBuilder& b, const std::string& name) { b.append(name, - getFeatureCompatibilityVersionString( + FeatureCompatibilityVersion::toString( serverGlobalParams.featureCompatibility.version.load())); } @@ -395,14 +290,14 @@ public: return Status(ErrorCodes::IllegalOperation, str::stream() << FeatureCompatibilityVersion::kParameterName << " cannot be set via setParameter. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); + "http://dochub.mongodb.org/core/3.6-feature-compatibility."); } virtual Status setFromString(const std::string& str) { return Status(ErrorCodes::IllegalOperation, str::stream() << FeatureCompatibilityVersion::kParameterName << " cannot be set via setParameter. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); + "http://dochub.mongodb.org/core/3.6-feature-compatibility."); } } featureCompatibilityVersionParameter; diff --git a/src/mongo/db/commands/feature_compatibility_version.h b/src/mongo/db/commands/feature_compatibility_version.h index 44029c72e21..ba28ceced17 100644 --- a/src/mongo/db/commands/feature_compatibility_version.h +++ b/src/mongo/db/commands/feature_compatibility_version.h @@ -31,6 +31,7 @@ #include "mongo/base/status_with.h" #include "mongo/base/string_data.h" #include "mongo/bson/bsonobj.h" +#include "mongo/db/commands/feature_compatibility_version_command_parser.h" #include "mongo/db/repl/storage_interface.h" #include "mongo/db/server_options.h" @@ -47,7 +48,6 @@ extern bool internalValidateFeaturesAsMaster; class FeatureCompatibilityVersion { public: - static constexpr StringData k32IncompatibleIndexName = "incompatible_with_version_32"_sd; static constexpr StringData kCollection = "admin.system.version"_sd; static constexpr StringData kCommandName = "setFeatureCompatibilityVersion"_sd; static constexpr StringData kDatabase = "admin"_sd; @@ -61,16 +61,27 @@ public: static StatusWith<ServerGlobalParams::FeatureCompatibility::Version> parse( const BSONObj& featureCompatibilityVersionDoc); + static StringData toString(ServerGlobalParams::FeatureCompatibility::Version version) { + switch (version) { + case ServerGlobalParams::FeatureCompatibility::Version::k36: + return FeatureCompatibilityVersionCommandParser::kVersion36; + case ServerGlobalParams::FeatureCompatibility::Version::k34: + return FeatureCompatibilityVersionCommandParser::kVersion34; + default: + MONGO_UNREACHABLE; + } + } + /** * Sets the minimum allowed version in the cluster, which determines what features are * available. - * 'version' should be '3.4' or '3.2'. + * 'version' should be '3.4' or '3.6'. */ static void set(OperationContext* opCtx, StringData version); /** * If there are no non-local databases and we are not running with --shardsvr, set - * featureCompatibilityVersion to 3.4. + * featureCompatibilityVersion to the latest value. */ static void setIfCleanStartup(OperationContext* opCtx, repl::StorageInterface* storageInterface); @@ -84,12 +95,12 @@ public: /** * Examines the _id of a document removed from admin.system.version. If it is the - * featureCompatibilityVersion document, resets the server parameter to its default value (3.2). + * featureCompatibilityVersion document, resets the server parameter to its default value. */ static void onDelete(const BSONObj& doc); /** - * Resets the server parameter to its default value (3.2). + * Resets the server parameter to its default value. */ static void onDropCollection(); }; diff --git a/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp b/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp index 551ac40a758..5f80382e0f3 100644 --- a/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp +++ b/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp @@ -38,8 +38,9 @@ namespace mongo { -constexpr StringData FeatureCompatibilityVersionCommandParser::kVersion34; constexpr StringData FeatureCompatibilityVersionCommandParser::kVersion32; +constexpr StringData FeatureCompatibilityVersionCommandParser::kVersion34; +constexpr StringData FeatureCompatibilityVersionCommandParser::kVersion36; StatusWith<std::string> FeatureCompatibilityVersionCommandParser::extractVersionFromCommand( StringData commandName, const BSONObj& cmdObj) { @@ -58,7 +59,7 @@ StatusWith<std::string> FeatureCompatibilityVersionCommandParser::extractVersion << typeName(versionElem.type()) << " in: " << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."}; + << ". See http://dochub.mongodb.org/core/3.6-feature-compatibility."}; } // Ensure that the command does not contain any unrecognized parameters @@ -72,23 +73,30 @@ StatusWith<std::string> FeatureCompatibilityVersionCommandParser::extractVersion ErrorCodes::InvalidOptions, str::stream() << "Unrecognized field found " << cmdElem.fieldNameStringData() << " in " << cmdObj - << ". See http ://dochub.mongodb.org/core/3.4-feature-compatibility."); + << ". See http ://dochub.mongodb.org/core/3.6-feature-compatibility."); } const std::string version = versionElem.String(); - if (version != FeatureCompatibilityVersionCommandParser::kVersion34 && - version != FeatureCompatibilityVersionCommandParser::kVersion32) { + if (version == FeatureCompatibilityVersionCommandParser::kVersion32) { + return {ErrorCodes::BadValue, + "Invalid command argument: '3.2'. You must downgrade to MongoDB 3.4 to enable " + "featureCompatibilityVersion 3.2. See " + "http://dochub.mongodb.org/core/3.6-feature-compatibility."}; + } + + if (version != FeatureCompatibilityVersionCommandParser::kVersion36 && + version != FeatureCompatibilityVersionCommandParser::kVersion34) { return {ErrorCodes::BadValue, str::stream() << "Invalid command argument. Expected '" - << FeatureCompatibilityVersionCommandParser::kVersion34 + << FeatureCompatibilityVersionCommandParser::kVersion36 << "' or '" - << FeatureCompatibilityVersionCommandParser::kVersion32 + << FeatureCompatibilityVersionCommandParser::kVersion34 << "', found " << version << " in: " << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."}; + << ". See http://dochub.mongodb.org/core/3.6-feature-compatibility."}; } return version; diff --git a/src/mongo/db/commands/feature_compatibility_version_command_parser.h b/src/mongo/db/commands/feature_compatibility_version_command_parser.h index 4e17aa94cdc..3a57f2ca75b 100644 --- a/src/mongo/db/commands/feature_compatibility_version_command_parser.h +++ b/src/mongo/db/commands/feature_compatibility_version_command_parser.h @@ -43,8 +43,9 @@ public: /** * Known server release versions. */ - static constexpr StringData kVersion34 = "3.4"_sd; static constexpr StringData kVersion32 = "3.2"_sd; + static constexpr StringData kVersion34 = "3.4"_sd; + static constexpr StringData kVersion36 = "3.6"_sd; /** * Interprets the specified BSON as a command and extracts the desired compatibility version diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 4b18a6fb8cb..e7d40b08c70 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -50,7 +50,6 @@ #include "mongo/db/query/get_executor.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/s/collection_sharding_state.h" -#include "mongo/db/server_options.h" #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" #include "mongo/db/stats/counters.h" @@ -148,14 +147,6 @@ public: return qrStatus.getStatus(); } - if (!qrStatus.getValue()->getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. ExtensionsCallbackReal extensionsCallback(opCtx, &nss); @@ -251,16 +242,6 @@ public: auto& qr = qrStatus.getValue(); - if (!qr->getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return appendCommandStatus( - result, - Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); - } - // Validate term before acquiring locks, if provided. if (auto term = qr->getReplicationTerm()) { auto replCoord = repl::ReplicationCoordinator::get(opCtx); diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp index ac62769c96d..3b56d5074e3 100644 --- a/src/mongo/db/commands/geo_near_cmd.cpp +++ b/src/mongo/db/commands/geo_near_cmd.cpp @@ -52,7 +52,6 @@ #include "mongo/db/query/find_common.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/plan_summary_stats.h" -#include "mongo/db/server_options.h" #include "mongo/platform/unordered_map.h" #include "mongo/util/log.h" @@ -183,15 +182,6 @@ public: collation = collationElt.Obj(); } } - if (!collation.isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return appendCommandStatus( - result, - Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); - } long long numWanted = 100; const char* limitName = !cmdObj["num"].eoo() ? "num" : "limit"; diff --git a/src/mongo/db/commands/group_cmd.cpp b/src/mongo/db/commands/group_cmd.cpp index c0cccd56f6a..e66dc123214 100644 --- a/src/mongo/db/commands/group_cmd.cpp +++ b/src/mongo/db/commands/group_cmd.cpp @@ -45,7 +45,6 @@ #include "mongo/db/query/find_common.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/plan_summary_stats.h" -#include "mongo/db/server_options.h" #include "mongo/util/log.h" namespace mongo { @@ -273,13 +272,6 @@ private: if (collationEltStatus.isOK()) { request->collation = collationElt.embeddedObject().getOwned(); } - if (!request->collation.isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } BSONElement reduce = p["$reduce"]; if (reduce.eoo()) { diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index 3d2b5577388..bada0092be4 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -164,27 +164,6 @@ public: } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "listIndexes", ns.ns()); - if (ns.ns() == FeatureCompatibilityVersion::kCollection && - indexNames[i] == FeatureCompatibilityVersion::k32IncompatibleIndexName) { - BSONObjBuilder bob; - - for (auto&& indexSpecElem : indexSpec) { - auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData(); - if (indexSpecElemFieldName == IndexDescriptor::kIndexVersionFieldName) { - // Include the index version in the command response as a decimal type - // instead of as a 32-bit integer. This is a new BSON type that isn't - // supported by versions of MongoDB earlier than 3.4 that will cause 3.2 - // secondaries to crash when performing initial sync. - bob.append(IndexDescriptor::kIndexVersionFieldName, - indexSpecElem.numberDecimal()); - } else { - bob.append(indexSpecElem); - } - } - - indexSpec = bob.obj(); - } - WorkingSetID id = ws->allocate(); WorkingSetMember* member = ws->get(id); member->keyData.clear(); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index c00d769d41d..095bcb2cef8 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -41,6 +41,7 @@ #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/database_holder.h" #include "mongo/db/catalog/document_validation.h" +#include "mongo/db/catalog/index_key_validate.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands.h" @@ -432,15 +433,12 @@ void State::prepTempCollection() { incColl = incCtx.db()->createCollection(_opCtx, _config.incLong.ns(), options); invariant(incColl); - // We explicitly create a v=2 index on the "0" field so that it is always possible for a - // user to emit() decimal keys. Since the incremental collection is not replicated to - // any secondaries, there is no risk of inadvertently crashing an older version of - // MongoDB when the featureCompatibilityVersion of this server is 3.2. - BSONObj indexSpec = + auto rawIndexSpec = BSON("key" << BSON("0" << 1) << "ns" << _config.incLong.ns() << "name" - << "_temp_0" - << "v" - << static_cast<int>(IndexVersion::kV2)); + << "_temp_0"); + auto indexSpec = uassertStatusOK(index_key_validate::validateIndexSpec( + rawIndexSpec, _config.incLong, serverGlobalParams.featureCompatibility)); + Status status = incColl->getIndexCatalog() ->createIndexOnEmptyCollection(_opCtx, indexSpec) .getStatus(); @@ -1397,16 +1395,6 @@ public: const Config config(dbname, cmd); - if (!config.collation.isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return appendCommandStatus( - result, - Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); - } - LOG(1) << "mr ns: " << config.nss; uassert(16149, "cannot run map reduce without the js engine", getGlobalScriptEngine()); diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp index 2d9a3e9006d..3a7f1a452e1 100644 --- a/src/mongo/db/commands/pipeline_command.cpp +++ b/src/mongo/db/commands/pipeline_command.cpp @@ -33,7 +33,6 @@ #include "mongo/db/commands/run_aggregate.h" #include "mongo/db/namespace_string.h" #include "mongo/db/pipeline/pipeline.h" -#include "mongo/db/server_options.h" namespace mongo { namespace { @@ -86,8 +85,15 @@ public: const BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& result) override { + const auto aggregationRequest = + uassertStatusOK(AggregationRequest::parseFromBSON(dbname, cmdObj, boost::none)); + return appendCommandStatus(result, - _runAggCommand(opCtx, dbname, cmdObj, boost::none, &result)); + runAggregate(opCtx, + aggregationRequest.getNamespaceString(), + aggregationRequest, + cmdObj, + result)); } Status explain(OperationContext* opCtx, @@ -95,33 +101,11 @@ public: const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, BSONObjBuilder* out) const override { - return _runAggCommand(opCtx, dbname, cmdObj, verbosity, out); - } - -private: - static Status _runAggCommand(OperationContext* opCtx, - const std::string& dbname, - const BSONObj& cmdObj, - boost::optional<ExplainOptions::Verbosity> verbosity, - BSONObjBuilder* result) { const auto aggregationRequest = uassertStatusOK(AggregationRequest::parseFromBSON(dbname, cmdObj, verbosity)); - // If the featureCompatibilityVersion is 3.2, we disallow collation from the user. However, - // operations should still respect the collection default collation. The mongos attaches the - // collection default collation to the merger pipeline, since the merger may not have the - // collection metadata. So the merger needs to accept a collation, and we rely on the shards - // to reject collations from the user. - uassert(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.", - aggregationRequest.getCollation().isEmpty() || - serverGlobalParams.featureCompatibility.version.load() != - ServerGlobalParams::FeatureCompatibility::Version::k32 || - isMergePipeline(aggregationRequest.getPipeline())); - return runAggregate( - opCtx, aggregationRequest.getNamespaceString(), aggregationRequest, cmdObj, *result); + opCtx, aggregationRequest.getNamespaceString(), aggregationRequest, cmdObj, *out); } } pipelineCmd; diff --git a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp index 7f01ef9ca5a..19579ebe7cb 100644 --- a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp +++ b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp @@ -38,7 +38,7 @@ namespace mongo { namespace { /** - * Sets the minimum allowed version for the cluster. If it is 3.2, then the node should not use 3.4 + * Sets the minimum allowed version for the cluster. If it is 3.4, then the node should not use 3.6 * features. * * Format: @@ -63,10 +63,10 @@ public: } virtual void help(std::stringstream& help) const { - help << "Set the API version exposed by this node. If set to \"3.2\", then 3.4 " - "features are disabled. If \"3.4\", then 3.4 features are enabled, and all nodes " - "in the cluster must be version 3.4. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."; + help << "Set the API version exposed by this node. If set to \"3.4\", then 3.6 " + "features are disabled. If \"3.6\", then 3.6 features are enabled, and all nodes " + "in the cluster must be version 3.6. See " + "http://dochub.mongodb.org/core/3.6-feature-compatibility."; } Status checkAuthForCommand(Client* client, diff --git a/src/mongo/db/index/index_descriptor.cpp b/src/mongo/db/index/index_descriptor.cpp index 08696cd525e..5115a5edda6 100644 --- a/src/mongo/db/index/index_descriptor.cpp +++ b/src/mongo/db/index/index_descriptor.cpp @@ -116,21 +116,8 @@ Status IndexDescriptor::isIndexVersionAllowedForCreation( case IndexVersion::kV0: break; case IndexVersion::kV1: + case IndexVersion::kV2: return Status::OK(); - case IndexVersion::kV2: { - if (ServerGlobalParams::FeatureCompatibility::Version::k32 == - featureCompatibility.version.load() && - featureCompatibility.validateFeaturesAsMaster.load()) { - return {ErrorCodes::CannotCreateIndex, - str::stream() << "Invalid index specification " << indexSpec - << "; cannot create an index with v=" - << static_cast<int>(IndexVersion::kV2) - << " when the featureCompatibilityVersion is 3.2. See " - "http://dochub.mongodb.org/core/" - "3.4-feature-compatibility."}; - } - return Status::OK(); - } } return {ErrorCodes::CannotCreateIndex, str::stream() << "Invalid index specification " << indexSpec @@ -140,23 +127,6 @@ Status IndexDescriptor::isIndexVersionAllowedForCreation( IndexVersion IndexDescriptor::getDefaultIndexVersion( ServerGlobalParams::FeatureCompatibility::Version featureCompatibilityVersion) { - ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.version.store(featureCompatibilityVersion); - // We always pass validateFeaturesAsMaster=true since this flag should not affect our - // determination of the default index version. - featureCompatibility.validateFeaturesAsMaster.store(true); - // We pass in an empty object for the index specification because it is only used within the - // error reason. - if (!IndexDescriptor::isIndexVersionAllowedForCreation( - IndexVersion::kV2, featureCompatibility, BSONObj()) - .isOK()) { - // When the featureCompatibilityVersion is 3.2, we use index version v=1 as the default - // index version. - return IndexVersion::kV1; - } - - // When the featureCompatibilityVersion is 3.4, we use index version v=2 as the default index - // version. return IndexVersion::kV2; } diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index e53988ea78e..61c3fedf474 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -41,7 +41,6 @@ #include "mongo/db/query/get_executor.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/db/repl/replication_coordinator_global.h" -#include "mongo/db/server_options.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -61,14 +60,6 @@ Status ParsedDelete::parseRequest() { // DeleteStage would not return the deleted document. invariant(_request->getProj().isEmpty() || _request->shouldReturnDeleted()); - if (!_request->getCollation().isEmpty() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - if (CanonicalQuery::isSimpleIdQuery(_request->getQuery())) { return Status::OK(); } diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index a6dfb2373ac..2d3de40342a 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -35,7 +35,6 @@ #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/query/query_planner_common.h" -#include "mongo/db/server_options.h" namespace mongo { @@ -52,13 +51,6 @@ Status ParsedUpdate::parseRequest() { invariant(_request->getProj().isEmpty() || _request->shouldReturnAnyDocs()); if (!_request->getCollation().isEmpty()) { - if (serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return Status(ErrorCodes::InvalidOptions, - "The featureCompatibilityVersion must be 3.4 to use collation. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - auto collator = CollatorFactoryInterface::get(_opCtx->getServiceContext()) ->makeFromBSON(_request->getCollation()); if (!collator.isOK()) { diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp index d91a80a58d9..44ad19fda7b 100644 --- a/src/mongo/db/repl/replication_info.cpp +++ b/src/mongo/db/repl/replication_info.cpp @@ -282,16 +282,73 @@ public: opCtx->getClient(), std::move(swParseClientMetadata.getValue())); } + // Parse the optional 'internalClient' field. This is provided by incoming connections from + // mongod and mongos. + auto internalClientElement = cmdObj["internalClient"]; + if (internalClientElement) { + auto session = opCtx->getClient()->session(); + if (session) { + session->replaceTags(session->getTags() | transport::Session::kInternalClient); + } + + uassert(ErrorCodes::TypeMismatch, + str::stream() << "'internalClient' must be of type Object, but was of type " + << typeName(internalClientElement.type()), + internalClientElement.type() == BSONType::Object); + + bool foundMaxWireVersion = false; + for (auto&& elem : internalClientElement.Obj()) { + auto fieldName = elem.fieldNameStringData(); + if (fieldName == "minWireVersion") { + // We do not currently use 'internalClient.minWireVersion'. + continue; + } else if (fieldName == "maxWireVersion") { + foundMaxWireVersion = true; + + uassert(ErrorCodes::TypeMismatch, + str::stream() << "'maxWireVersion' field of 'internalClient' must be " + "of type int, but was of type " + << typeName(elem.type()), + elem.type() == BSONType::NumberInt); + + // All incoming connections from mongod/mongos of earlier versions should be + // closed if the featureCompatibilityVersion is bumped to 3.6. + if (elem.numberInt() >= WireSpec::instance().incoming.maxWireVersion) { + if (session) { + session->replaceTags( + session->getTags() | + transport::Session::kLatestVersionInternalClientKeepOpen); + } + } else { + if (session) { + session->replaceTags( + session->getTags() & + ~transport::Session::kLatestVersionInternalClientKeepOpen); + } + } + } else { + uasserted(ErrorCodes::BadValue, + str::stream() << "Unrecognized field of 'internalClient': '" + << fieldName + << "'"); + } + } + + uassert(ErrorCodes::BadValue, + "Missing required field 'maxWireVersion' of 'internalClient'", + foundMaxWireVersion); + } else { + auto session = opCtx->getClient()->session(); + if (session && !(session->getTags() & transport::Session::kInternalClient)) { + session->replaceTags(session->getTags() | + transport::Session::kExternalClientKeepOpen); + } + } + appendReplicationInfo(opCtx, result, 0); if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) { - // If we have feature compatibility version 3.4, use a config server mode that 3.2 - // mongos won't understand. This should prevent a 3.2 mongos from joining the cluster or - // making a connection to the config servers. - int configServerModeNumber = (serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k34) - ? 2 - : 1; + const int configServerModeNumber = 2; result.append("configsvr", configServerModeNumber); } @@ -300,7 +357,18 @@ public: result.appendNumber("maxWriteBatchSize", BatchedCommandRequest::kMaxWriteBatchSize); result.appendDate("localTime", jsTime()); result.append("maxWireVersion", WireSpec::instance().incoming.maxWireVersion); - result.append("minWireVersion", WireSpec::instance().incoming.minWireVersion); + + // If the featureCompatibilityVersion is 3.6, respond with minWireVersion=maxWireVersion. + // Then if the connection is from a mongod/mongos of an earlier version, it will fail to + // connect. + if (internalClientElement && + serverGlobalParams.featureCompatibility.version.load() == + ServerGlobalParams::FeatureCompatibility::Version::k36) { + result.append("minWireVersion", WireSpec::instance().incoming.maxWireVersion); + } else { + result.append("minWireVersion", WireSpec::instance().incoming.minWireVersion); + } + result.append("readOnly", storageGlobalParams.readOnly); const auto parameter = mapFindWithDefault(ServerParameterSet::getGlobal()->getMap(), diff --git a/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp b/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp index 91e5ba98f2d..a70c7406e59 100644 --- a/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp +++ b/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp @@ -56,7 +56,7 @@ public: void help(std::stringstream& help) const override { help << "Internal command, which is exported by the sharding config server. Do not call " "directly. Sets featureCompatibilityVersion on all shards. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."; + "http://dochub.mongodb.org/core/3.6-feature-compatibility."; } bool slaveOk() const override { @@ -92,7 +92,7 @@ public: uassert(ErrorCodes::IllegalOperation, str::stream() << getName() << " can only be run on config servers. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.", + "http://dochub.mongodb.org/core/3.6-feature-compatibility.", serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Forward to all shards. diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h index c858964bcd4..148c96dd0bd 100644 --- a/src/mongo/db/server_options.h +++ b/src/mongo/db/server_options.h @@ -141,21 +141,20 @@ struct ServerGlobalParams { struct FeatureCompatibility { enum class Version { /** - * In this mode, the cluster will expose a 3.2-like API. Attempts by a client to use new - * features in 3.4, such as read-only views, collation, or the decimal128 BSON type, - * will be rejected. + * In this mode, the cluster will expose a 3.4-like API. Attempts by a client to use new + * features in 3.6 will be rejected. */ - k32, + k34, /** - * In this mode, new features in 3.4 are allowed. The system should guarantee that no - * 3.2 node can participate in a cluster whose feature compatibility version is 3.4. + * In this mode, new features in 3.6 are allowed. The system should guarantee that no + * 3.4 node can participate in a cluster whose feature compatibility version is 3.6. */ - k34, + k36, }; // Read-only parameter featureCompatibilityVersion. - AtomicWord<Version> version{Version::k32}; + AtomicWord<Version> version{Version::k34}; // Feature validation differs depending on the role of a mongod in a replica set or // master/slave configuration. Masters/primaries can accept user-initiated writes and diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp index f5acb385121..9759b056264 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp @@ -207,8 +207,7 @@ StatusWith<std::string> WiredTigerIndex::generateCreateString(const std::string& } ss << ",value_format=u"; - // We build v=2 indexes when the featureCompatibilityVersion is 3.4. This means that the server - // supports new index features and we can therefore use KeyString::Version::V1. + // Index versions greater than 2 use KeyString version 1. const int keyStringVersion = desc.version() >= IndexDescriptor::IndexVersion::kV2 ? kKeyStringV1Version : kKeyStringV0Version; diff --git a/src/mongo/db/views/view_catalog.cpp b/src/mongo/db/views/view_catalog.cpp index 7f810dcaf25..7fe8d85c9d9 100644 --- a/src/mongo/db/views/view_catalog.cpp +++ b/src/mongo/db/views/view_catalog.cpp @@ -46,7 +46,6 @@ #include "mongo/db/pipeline/lite_parsed_pipeline.h" #include "mongo/db/pipeline/pipeline.h" #include "mongo/db/query/collation/collator_factory_interface.h" -#include "mongo/db/server_options.h" #include "mongo/db/server_parameters.h" #include "mongo/db/storage/recovery_unit.h" #include "mongo/db/views/resolved_view.h" @@ -262,14 +261,6 @@ Status ViewCatalog::createView(OperationContext* opCtx, const BSONObj& collation) { stdx::lock_guard<stdx::mutex> lk(_mutex); - if (serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32 && - serverGlobalParams.featureCompatibility.validateFeaturesAsMaster.load()) { - return Status(ErrorCodes::CommandNotSupported, - "Cannot create view when the featureCompatibilityVersion is 3.2. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - if (viewName.db() != viewOn.db()) return Status(ErrorCodes::BadValue, "View must be created on a view or collection in the same database"); @@ -300,14 +291,6 @@ Status ViewCatalog::modifyView(OperationContext* opCtx, const BSONArray& pipeline) { stdx::lock_guard<stdx::mutex> lk(_mutex); - if (serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32 && - serverGlobalParams.featureCompatibility.validateFeaturesAsMaster.load()) { - return Status(ErrorCodes::CommandNotSupported, - "Cannot modify view when the featureCompatibilityVersion is 3.2. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - if (viewName.db() != viewOn.db()) return Status(ErrorCodes::BadValue, "View must be created on a view or collection in the same database"); diff --git a/src/mongo/db/views/view_catalog_test.cpp b/src/mongo/db/views/view_catalog_test.cpp index f1708bef504..3e284372735 100644 --- a/src/mongo/db/views/view_catalog_test.cpp +++ b/src/mongo/db/views/view_catalog_test.cpp @@ -39,7 +39,6 @@ #include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/query_test_service_context.h" -#include "mongo/db/server_options.h" #include "mongo/db/service_context_noop.h" #include "mongo/db/views/durable_view_catalog.h" #include "mongo/db/views/view.h" @@ -68,13 +67,6 @@ constexpr auto kLargeString = const auto kOneKiBMatchStage = BSON("$match" << BSON("data" << kLargeString)); const auto kTinyMatchStage = BSON("$match" << BSONObj()); -MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersion34, ("EndStartupOptionStorage")) -(InitializerContext* context) { - mongo::serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - return Status::OK(); -} - class DurableViewCatalogDummy final : public DurableViewCatalog { public: explicit DurableViewCatalogDummy() : _upsertCount(0), _iterateCount(0) {} diff --git a/src/mongo/dbtests/dbtests.cpp b/src/mongo/dbtests/dbtests.cpp index 70222426d1b..b83d109906d 100644 --- a/src/mongo/dbtests/dbtests.cpp +++ b/src/mongo/dbtests/dbtests.cpp @@ -45,7 +45,6 @@ #include "mongo/db/logical_clock.h" #include "mongo/db/repl/replication_coordinator_global.h" #include "mongo/db/repl/replication_coordinator_mock.h" -#include "mongo/db/server_options.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_d.h" #include "mongo/db/wire_version.h" @@ -61,12 +60,6 @@ namespace mongo { namespace dbtests { namespace { const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; - -MONGO_INITIALIZER(FeatureCompatibilityVersionForTest)(InitializerContext* context) { - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - return Status::OK(); -} } // namespace void initWireSpec() { diff --git a/src/mongo/dbtests/jstests.cpp b/src/mongo/dbtests/jstests.cpp index 8ba67219d91..78ec85296f9 100644 --- a/src/mongo/dbtests/jstests.cpp +++ b/src/mongo/dbtests/jstests.cpp @@ -789,11 +789,6 @@ public: class NumberDecimal { public: void run() { - // Set the featureCompatibilityVersion to 3.4 so that BSON validation always uses - // BSONVersion::kLatest. - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - unique_ptr<Scope> s(getGlobalScriptEngine()->newScope()); BSONObjBuilder b; Decimal128 val = Decimal128("2.010"); @@ -823,11 +818,6 @@ public: class NumberDecimalGetFromScope { public: void run() { - // Set the featureCompatibilityVersion to 3.4 so that BSON validation always uses - // BSONVersion::kLatest. - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - unique_ptr<Scope> s(getGlobalScriptEngine()->newScope()); ASSERT(s->exec("a = 5;", "a", false, true, false)); ASSERT_TRUE(Decimal128(5).isEqual(s->getNumberDecimal("a"))); @@ -837,11 +827,6 @@ public: class NumberDecimalBigObject { public: void run() { - // Set the featureCompatibilityVersion to 3.4 so that BSON validation always uses - // BSONVersion::kLatest. - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - unique_ptr<Scope> s(getGlobalScriptEngine()->newScope()); BSONObj in; @@ -1136,11 +1121,6 @@ public: void run() { // Insert in Javascript -> Find using DBDirectClient - // Set the featureCompatibilityVersion to 3.4 so that BSON validation always uses - // BSONVersion::kLatest. - serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); - // Drop the collection const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; diff --git a/src/mongo/rpc/object_check.h b/src/mongo/rpc/object_check.h index 7c7741ada62..2a6e485097c 100644 --- a/src/mongo/rpc/object_check.h +++ b/src/mongo/rpc/object_check.h @@ -45,19 +45,10 @@ class Status; template <> struct Validator<BSONObj> { inline static BSONVersion enabledBSONVersion() { - // If we're in the primary/master role accepting writes, but our feature compatibility - // version is 3.2, then we want to reject insertion of the decimal data type. Therefore, we - // perform BSON 1.0 validation. - if (serverGlobalParams.featureCompatibility.validateFeaturesAsMaster.load() && - serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k32) { - return BSONVersion::kV1_0; - } - - // Except for the special case above, we want to accept any BSON version which we know - // about. For instance, if we are a slave/secondary syncing from a primary/master and we are - // in 3.2 feature compatibility mode, we still want to be able to sync NumberDecimal data. - return BSONVersion::kV1_1; + // The enabled BSON version is always the latest BSON version if no new BSON types have been + // added during the release. Otherwise, the BSON version returned should be controlled + // through the featureCompatibilityVersion. + return BSONVersion::kLatest; } inline static Status validateLoad(const char* ptr, size_t length) { diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp index 604dc708b52..ada7e8f2cee 100644 --- a/src/mongo/rpc/protocol.cpp +++ b/src/mongo/rpc/protocol.cpp @@ -174,12 +174,6 @@ StatusWith<ProtocolSetAndWireVersionInfo> parseProtocolSetFromIsMasterReply( return {{protos, version}}; } -bool supportsWireVersionForOpCommandInMongod(const WireVersionInfo version) { - // FIND_COMMAND versions support OP_COMMAND (in mongod but not mongos). - return (version.minWireVersion <= WireVersion::FIND_COMMAND) && - (version.maxWireVersion >= WireVersion::FIND_COMMAND); -} - ProtocolSet computeProtocolSet(const WireVersionInfo version) { ProtocolSet result = supports::kNone; if (version.minWireVersion <= version.maxWireVersion) { diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h index 57cb491bf5c..c7500761e98 100644 --- a/src/mongo/rpc/protocol.h +++ b/src/mongo/rpc/protocol.h @@ -138,11 +138,6 @@ StatusWith<ProtocolSetAndWireVersionInfo> parseProtocolSetFromIsMasterReply( const BSONObj& isMasterReply); /** - * Returns true if wire version supports OP_COMMAND in mongod (not mongos). - */ -bool supportsWireVersionForOpCommandInMongod(const WireVersionInfo version); - -/** * Computes supported protocols from wire versions. */ ProtocolSet computeProtocolSet(const WireVersionInfo version); diff --git a/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp b/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp index a5b77cbd5aa..1c4dbe69bc9 100644 --- a/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp +++ b/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp @@ -132,6 +132,19 @@ protected: }); } + void expectSetFeatureCompatibilityVersion(const HostAndPort& target, + StatusWith<BSONObj> response) { + onCommandForAddShard([&, target, response](const RemoteCommandRequest& request) { + ASSERT_EQ(request.target, target); + ASSERT_EQ(request.dbname, "admin"); + ASSERT_BSONOBJ_EQ(request.cmdObj, + BSON("setFeatureCompatibilityVersion" + << "3.4")); + + return response; + }); + } + /** * Waits for a request for the shardIdentity document to be upserted into a shard from the * config server on addShard. @@ -404,6 +417,9 @@ TEST_F(AddShardTest, StandaloneBasicSuccess) { BSON("name" << discoveredDB1.getName() << "sizeOnDisk" << 2000), BSON("name" << discoveredDB2.getName() << "sizeOnDisk" << 5000)}); + // The shard receives the setFeatureCompatibilityVersion command. + expectSetFeatureCompatibilityVersion(shardTarget, BSON("ok" << 1)); + // The shardIdentity doc inserted into the admin.system.version collection on the shard. expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName); @@ -483,6 +499,9 @@ TEST_F(AddShardTest, StandaloneGenerateName) { BSON("name" << discoveredDB1.getName() << "sizeOnDisk" << 2000), BSON("name" << discoveredDB2.getName() << "sizeOnDisk" << 5000)}); + // The shard receives the setFeatureCompatibilityVersion command. + expectSetFeatureCompatibilityVersion(shardTarget, BSON("ok" << 1)); + // The shardIdentity doc inserted into the admin.system.version collection on the shard. expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName); @@ -896,6 +915,9 @@ TEST_F(AddShardTest, SuccessfullyAddReplicaSet) { // Get databases list from new shard expectListDatabases(shardTarget, std::vector<BSONObj>{BSON("name" << discoveredDB.getName())}); + // The shard receives the setFeatureCompatibilityVersion command. + expectSetFeatureCompatibilityVersion(shardTarget, BSON("ok" << 1)); + // The shardIdentity doc inserted into the admin.system.version collection on the shard. expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName); @@ -958,6 +980,9 @@ TEST_F(AddShardTest, ReplicaSetExtraHostsDiscovered) { // Get databases list from new shard expectListDatabases(shardTarget, std::vector<BSONObj>{BSON("name" << discoveredDB.getName())}); + // The shard receives the setFeatureCompatibilityVersion command. + expectSetFeatureCompatibilityVersion(shardTarget, BSON("ok" << 1)); + // The shardIdentity doc inserted into the admin.system.version collection on the shard. expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName); @@ -1034,6 +1059,9 @@ TEST_F(AddShardTest, AddShardSucceedsEvenIfAddingDBsFromNewShardFails) { BSON("name" << discoveredDB1.getName() << "sizeOnDisk" << 2000), BSON("name" << discoveredDB2.getName() << "sizeOnDisk" << 5000)}); + // The shard receives the setFeatureCompatibilityVersion command. + expectSetFeatureCompatibilityVersion(shardTarget, BSON("ok" << 1)); + // The shardIdentity doc inserted into the admin.system.version collection on the shard. expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName); diff --git a/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp b/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp index 6d5ee674f5c..c43cfe3a8aa 100644 --- a/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp +++ b/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp @@ -262,64 +262,64 @@ TEST_F(ConfigInitializationTest, BuildsNecessaryIndexes) { ASSERT_OK(catalogManager()->initializeConfigDatabaseIfNeeded(operationContext())); auto expectedChunksIndexes = std::vector<BSONObj>{ - BSON("v" << 1 << "key" << BSON("_id" << 1) << "name" + BSON("v" << 2 << "key" << BSON("_id" << 1) << "name" << "_id_" << "ns" << "config.chunks"), - BSON("v" << 1 << "unique" << true << "key" << BSON("ns" << 1 << "min" << 1) << "name" + BSON("v" << 2 << "unique" << true << "key" << BSON("ns" << 1 << "min" << 1) << "name" << "ns_1_min_1" << "ns" << "config.chunks"), - BSON("v" << 1 << "unique" << true << "key" << BSON("ns" << 1 << "shard" << 1 << "min" << 1) + BSON("v" << 2 << "unique" << true << "key" << BSON("ns" << 1 << "shard" << 1 << "min" << 1) << "name" << "ns_1_shard_1_min_1" << "ns" << "config.chunks"), - BSON("v" << 1 << "unique" << true << "key" << BSON("ns" << 1 << "lastmod" << 1) << "name" + BSON("v" << 2 << "unique" << true << "key" << BSON("ns" << 1 << "lastmod" << 1) << "name" << "ns_1_lastmod_1" << "ns" << "config.chunks")}; auto expectedLockpingsIndexes = - std::vector<BSONObj>{BSON("v" << 1 << "key" << BSON("_id" << 1) << "name" + std::vector<BSONObj>{BSON("v" << 2 << "key" << BSON("_id" << 1) << "name" << "_id_" << "ns" << "config.lockpings"), - BSON("v" << 1 << "key" << BSON("ping" << 1) << "name" + BSON("v" << 2 << "key" << BSON("ping" << 1) << "name" << "ping_1" << "ns" << "config.lockpings")}; auto expectedLocksIndexes = std::vector<BSONObj>{ - BSON("v" << 1 << "key" << BSON("_id" << 1) << "name" + BSON("v" << 2 << "key" << BSON("_id" << 1) << "name" << "_id_" << "ns" << "config.locks"), - BSON("v" << 1 << "key" << BSON("ts" << 1) << "name" + BSON("v" << 2 << "key" << BSON("ts" << 1) << "name" << "ts_1" << "ns" << "config.locks"), - BSON("v" << 1 << "key" << BSON("state" << 1 << "process" << 1) << "name" + BSON("v" << 2 << "key" << BSON("state" << 1 << "process" << 1) << "name" << "state_1_process_1" << "ns" << "config.locks")}; auto expectedShardsIndexes = std::vector<BSONObj>{ - BSON("v" << 1 << "key" << BSON("_id" << 1) << "name" + BSON("v" << 2 << "key" << BSON("_id" << 1) << "name" << "_id_" << "ns" << "config.shards"), - BSON("v" << 1 << "unique" << true << "key" << BSON("host" << 1) << "name" + BSON("v" << 2 << "unique" << true << "key" << BSON("host" << 1) << "name" << "host_1" << "ns" << "config.shards")}; auto expectedTagsIndexes = std::vector<BSONObj>{ - BSON("v" << 1 << "key" << BSON("_id" << 1) << "name" + BSON("v" << 2 << "key" << BSON("_id" << 1) << "name" << "_id_" << "ns" << "config.tags"), - BSON("v" << 1 << "unique" << true << "key" << BSON("ns" << 1 << "min" << 1) << "name" + BSON("v" << 2 << "unique" << true << "key" << BSON("ns" << 1 << "min" << 1) << "name" << "ns_1_min_1" << "ns" << "config.tags"), - BSON("v" << 1 << "key" << BSON("ns" << 1 << "tag" << 1) << "name" + BSON("v" << 2 << "key" << BSON("ns" << 1 << "tag" << 1) << "name" << "ns_1_tag_1" << "ns" << "config.tags")}; @@ -352,11 +352,11 @@ TEST_F(ConfigInitializationTest, CompatibleIndexAlreadyExists) { ASSERT_OK(catalogManager()->initializeConfigDatabaseIfNeeded(operationContext())); auto expectedShardsIndexes = std::vector<BSONObj>{ - BSON("v" << 1 << "key" << BSON("_id" << 1) << "name" + BSON("v" << 2 << "key" << BSON("_id" << 1) << "name" << "_id_" << "ns" << "config.shards"), - BSON("v" << 1 << "unique" << true << "key" << BSON("host" << 1) << "name" + BSON("v" << 2 << "unique" << true << "key" << BSON("host" << 1) << "name" << "host_1" << "ns" << "config.shards")}; diff --git a/src/mongo/s/catalog/sharding_catalog_manager_shard_operations_impl.cpp b/src/mongo/s/catalog/sharding_catalog_manager_shard_operations_impl.cpp index 2a2d6b1d3d9..674cba90727 100644 --- a/src/mongo/s/catalog/sharding_catalog_manager_shard_operations_impl.cpp +++ b/src/mongo/s/catalog/sharding_catalog_manager_shard_operations_impl.cpp @@ -617,29 +617,19 @@ StatusWith<std::string> ShardingCatalogManagerImpl::addShard( shardType.setMaxSizeMB(maxSize); } - // If the minimum allowed version for the cluster is 3.4, set the featureCompatibilityVersion to - // 3.4 on the shard. - if (serverGlobalParams.featureCompatibility.version.load() == - ServerGlobalParams::FeatureCompatibility::Version::k34) { - auto versionResponse = - _runCommandForAddShard(opCtx, - targeter.get(), - "admin", - BSON(FeatureCompatibilityVersion::kCommandName - << FeatureCompatibilityVersionCommandParser::kVersion34)); - if (!versionResponse.isOK()) { - return versionResponse.getStatus(); - } + // The featureCompatibilityVersion should be the same throughout the cluster. + auto versionResponse = _runCommandForAddShard( + opCtx, + targeter.get(), + "admin", + BSON(FeatureCompatibilityVersion::kCommandName << FeatureCompatibilityVersion::toString( + serverGlobalParams.featureCompatibility.version.load()))); + if (!versionResponse.isOK()) { + return versionResponse.getStatus(); + } - if (!versionResponse.getValue().commandStatus.isOK()) { - if (versionResponse.getStatus().code() == ErrorCodes::CommandNotFound) { - return {ErrorCodes::OperationFailed, - "featureCompatibilityVersion for cluster is 3.4, cannot add a shard with " - "version below 3.4. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."}; - } - return versionResponse.getValue().commandStatus; - } + if (!versionResponse.getValue().commandStatus.isOK()) { + return versionResponse.getValue().commandStatus; } if (!MONGO_FAIL_POINT(dontUpsertShardIdentityOnNewShards)) { diff --git a/src/mongo/s/commands/cluster_set_feature_compatibility_version_cmd.cpp b/src/mongo/s/commands/cluster_set_feature_compatibility_version_cmd.cpp index 9782f1f05bf..de864f2d44f 100644 --- a/src/mongo/s/commands/cluster_set_feature_compatibility_version_cmd.cpp +++ b/src/mongo/s/commands/cluster_set_feature_compatibility_version_cmd.cpp @@ -40,7 +40,7 @@ namespace mongo { namespace { /** - * Sets the minimum allowed version for the cluster. If it is 3.2, then shards should not use 3.4 + * Sets the minimum allowed version for the cluster. If it is 3.4, then shards should not use 3.6 * features. * * Format: @@ -65,10 +65,10 @@ public: } virtual void help(std::stringstream& help) const { - help << "Set the API version for the cluster. If set to \"3.2\", then 3.4 features are " - "disabled. If \"3.4\", then 3.4 features are enabled, and all nodes in the cluster " - "must be version 3.4. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility."; + help << "Set the API version for the cluster. If set to \"3.4\", then 3.6 features are " + "disabled. If \"3.6\", then 3.6 features are enabled, and all nodes in the cluster " + "must be version 3.6. See " + "http://dochub.mongodb.org/core/3.6-feature-compatibility."; } Status checkAuthForCommand(Client* client, diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp index 93f1ad59b28..e663ea15a26 100644 --- a/src/mongo/s/server.cpp +++ b/src/mongo/s/server.cpp @@ -361,12 +361,12 @@ MONGO_INITIALIZER_GENERAL(ForkServer, ("EndStartupOptionHandling"), ("default")) } } // namespace -// We set the featureCompatibilityVersion to 3.4 in the mongos so that BSON validation always uses -// BSONVersion::kLatest. -MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersion34, ("EndStartupOptionStorage")) +// We set the featureCompatibilityVersion to 3.6 in the mongos and rely on the shards to reject +// usages of new features if their featureCompatibilityVersion is lower. +MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersion36, ("EndStartupOptionStorage")) (InitializerContext* context) { mongo::serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); + ServerGlobalParams::FeatureCompatibility::Version::k36); return Status::OK(); } diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp index 7e1703072ef..16f16be7c56 100644 --- a/src/mongo/shell/dbshell.cpp +++ b/src/mongo/shell/dbshell.cpp @@ -90,12 +90,12 @@ static AtomicBool atPrompt(false); // can eval before getting to prompt namespace { const auto kDefaultMongoURL = "mongodb://127.0.0.1:27017"_sd; -// We set the featureCompatibilityVersion to 3.4 in the mongo shell so that BSON validation always -// uses BSONVersion::kLatest. -MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersion34, ("EndStartupOptionSetup")) +// We set the featureCompatibilityVersion to 3.6 in the mongo shell and rely on the server to reject +// usages of new features if its featureCompatibilityVersion is lower. +MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersion36, ("EndStartupOptionSetup")) (InitializerContext* context) { mongo::serverGlobalParams.featureCompatibility.version.store( - ServerGlobalParams::FeatureCompatibility::Version::k34); + ServerGlobalParams::FeatureCompatibility::Version::k36); return Status::OK(); } } diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js index b95480acf07..41bff90dd06 100644 --- a/src/mongo/shell/shardingtest.js +++ b/src/mongo/shell/shardingtest.js @@ -1004,7 +1004,7 @@ var ShardingTest = function(params) { * be manually changed if and when there is a new feature compatibility version. */ function _hasNewFeatureCompatibilityVersion() { - return false; + return true; } // ShardingTest initialization @@ -1313,9 +1313,7 @@ var ShardingTest = function(params) { var csrsPrimary = this.configRS.getPrimary(); // If 'otherParams.mongosOptions.binVersion' is an array value, then we'll end up constructing a - // version iterator. We initialize the options for the mongos processes before checking whether - // we need to run {setFeatureCompatibilityVersion: "3.2"} on the CSRS primary so we know - // definitively what binVersions will be used for the mongos processes. + // version iterator. const mongosOptions = []; for (var i = 0; i < numMongos; ++i) { let options = { @@ -1335,19 +1333,11 @@ var ShardingTest = function(params) { options.port = options.port || allocatePort(); - // TODO(esha): remove after v3.4 ships. - // Legacy mongoses use a command line option to disable autosplit instead of reading the - // config.settings collection. - if (options.binVersion && MongoRunner.areBinVersionsTheSame('3.2', options.binVersion) && - !otherParams.enableAutoSplit) { - options.noAutoSplit = ""; - } - mongosOptions.push(options); } const configRS = this.configRS; - if (_hasNewFeatureCompatibilityVersion && _isMixedVersionCluster()) { + if (_hasNewFeatureCompatibilityVersion() && _isMixedVersionCluster()) { function setFeatureCompatibilityVersion() { assert.commandWorked(csrsPrimary.adminCommand({setFeatureCompatibilityVersion: '3.4'})); diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js index 216217ed0b2..2cb79d743ab 100644 --- a/src/mongo/shell/utils.js +++ b/src/mongo/shell/utils.js @@ -229,8 +229,6 @@ jsTestOptions = function() { shardMixedBinVersions: TestData.shardMixedBinVersions || false, networkMessageCompressors: TestData.networkMessageCompressors, skipValidationOnInvalidViewDefinitions: TestData.skipValidationOnInvalidViewDefinitions, - forceValidationWithFeatureCompatibilityVersion: - TestData.forceValidationWithFeatureCompatibilityVersion, skipCollectionAndIndexValidation: TestData.skipCollectionAndIndexValidation, skipValidationOnNamespaceNotFound: TestData.skipValidationOnNamespaceNotFound }); diff --git a/src/mongo/transport/session.h b/src/mongo/transport/session.h index e82cd3d8faf..2cfae3815f2 100644 --- a/src/mongo/transport/session.h +++ b/src/mongo/transport/session.h @@ -69,6 +69,9 @@ public: static constexpr TagMask kEmptyTagMask = 0; static constexpr TagMask kKeepOpen = 1; + static constexpr TagMask kInternalClient = 2; + static constexpr TagMask kLatestVersionInternalClientKeepOpen = 4; + static constexpr TagMask kExternalClientKeepOpen = 8; /** * Destroys a session, calling end() for this session in its TransportLayer. |