diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/catalog/database_impl.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_spec_validate_test.cpp | 95 | ||||
-rw-r--r-- | src/mongo/db/commands/feature_compatibility_version.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/db.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/server_options.h | 15 | ||||
-rw-r--r-- | src/mongo/db/service_context_d_test_fixture.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog_test.cpp | 1 | ||||
-rw-r--r-- | src/mongo/unittest/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/unittest/unittest.cpp | 12 | ||||
-rw-r--r-- | src/mongo/unittest/unittest.h | 2 |
12 files changed, 91 insertions, 71 deletions
diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index ebbe30aee40..e6cc8ef537c 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -814,8 +814,10 @@ Collection* DatabaseImpl::createCollection(OperationContext* opCtx, if (collection->requiresIdIndex()) { if (optionsWithUUID.autoIndexId == CollectionOptions::YES || optionsWithUUID.autoIndexId == CollectionOptions::DEFAULT) { + // createCollection() may be called before the in-memory fCV parameter is + // initialized, so use the unsafe fCV getter here. const auto featureCompatibilityVersion = - serverGlobalParams.featureCompatibility.getVersion(); + serverGlobalParams.featureCompatibility.getVersionUnsafe(); IndexCatalog* ic = collection->getIndexCatalog(); fullIdIndexSpec = uassertStatusOK(ic->createIndexOnEmptyCollection( opCtx, diff --git a/src/mongo/db/catalog/index_spec_validate_test.cpp b/src/mongo/db/catalog/index_spec_validate_test.cpp index 9af8fa54b01..44f4e48b32c 100644 --- a/src/mongo/db/catalog/index_spec_validate_test.cpp +++ b/src/mongo/db/catalog/index_spec_validate_test.cpp @@ -40,6 +40,7 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/query_test_service_context.h" +#include "mongo/db/server_options.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -49,7 +50,6 @@ using index_key_validate::validateIndexSpec; using index_key_validate::validateIdIndexSpec; using index_key_validate::validateIndexSpecCollation; -const ServerGlobalParams::FeatureCompatibility defaultFeatureCompatibility{}; const NamespaceString kTestNamespace("test", "index_spec_validate"); constexpr OperationContext* kDefaultOpCtx = nullptr; @@ -71,7 +71,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotAnObject) { BSON("key" << 1 << "name" << "indexName"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::TypeMismatch, validateIndexSpec(kDefaultOpCtx, BSON("key" @@ -79,13 +79,13 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotAnObject) { << "name" << "indexName"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::TypeMismatch, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSONArray() << "name" << "indexName"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfFieldRepeatedInKeyPattern) { @@ -94,7 +94,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfFieldRepeatedInKeyPattern) { BSON("key" << BSON("field" << 1 << "field" << 1) << "name" << "indexName"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::BadValue, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1 << "otherField" << -1 << "field" @@ -102,7 +102,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfFieldRepeatedInKeyPattern) { << "name" << "indexName"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotPresent) { @@ -111,7 +111,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfKeyPatternIsNotPresent) { BSON("name" << "indexName"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotAString) { @@ -119,7 +119,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotAString) { validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" << 1), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotPresent) { @@ -127,7 +127,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNameIsNotPresent) { validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1)), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsNotAString) { @@ -138,7 +138,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsNotAString) { << "ns" << 1), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::TypeMismatch, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -146,7 +146,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsNotAString) { << "ns" << BSONObj()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsEmptyString) { @@ -157,7 +157,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceIsEmptyString) { << "ns" << ""), NamespaceString(), - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceDoesNotMatch) { @@ -168,7 +168,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceDoesNotMatch) { << "ns" << "some string"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); // Verify that we reject the index specification when the "ns" field only contains the // collection name. @@ -179,7 +179,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfNamespaceDoesNotMatch) { << "ns" << kTestNamespace.coll()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsIndexSpecWithNamespaceFilledInIfItIsNotPresent) { @@ -189,7 +189,7 @@ TEST(IndexSpecValidateTest, ReturnsIndexSpecWithNamespaceFilledInIfItIsNotPresen << "v" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -203,7 +203,7 @@ TEST(IndexSpecValidateTest, ReturnsIndexSpecWithNamespaceFilledInIfItIsNotPresen // Verify that the index specification we returned is still considered valid. ASSERT_OK(validateIndexSpec( - kDefaultOpCtx, result.getValue(), kTestNamespace, defaultFeatureCompatibility)); + kDefaultOpCtx, result.getValue(), kTestNamespace, serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsIndexSpecUnchangedIfNamespaceAndVersionArePresent) { @@ -215,7 +215,7 @@ TEST(IndexSpecValidateTest, ReturnsIndexSpecUnchangedIfNamespaceAndVersionArePre << "v" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -236,7 +236,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotANumber) { << "v" << "not a number"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::TypeMismatch, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -244,7 +244,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotANumber) { << "v" << BSONObj()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { @@ -255,7 +255,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { << "v" << 2.2), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::BadValue, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -263,7 +263,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { << "v" << std::nan("1")), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::BadValue, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -271,7 +271,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { << "v" << std::numeric_limits<double>::infinity()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::BadValue, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -279,7 +279,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsNotRepresentableAsInt) { << "v" << std::numeric_limits<long long>::max()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsV0) { @@ -290,7 +290,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsV0) { << "v" << 0), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsUnsupported) { @@ -304,7 +304,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsUnsupported) { << BSON("locale" << "en")), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::CannotCreateIndex, validateIndexSpec(kDefaultOpCtx, @@ -313,7 +313,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfVersionIsUnsupported) { << "v" << -3LL), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, AcceptsIndexVersionsThatAreAllowedForCreation) { @@ -323,7 +323,7 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionsThatAreAllowedForCreation) { << "v" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -341,7 +341,7 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionsThatAreAllowedForCreation) { << "v" << 2LL), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -361,7 +361,7 @@ TEST(IndexSpecValidateTest, DefaultIndexVersionIsV2) { << "ns" << kTestNamespace.ns()), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -375,7 +375,7 @@ TEST(IndexSpecValidateTest, DefaultIndexVersionIsV2) { // Verify that the index specification we returned is still considered valid. ASSERT_OK(validateIndexSpec( - kDefaultOpCtx, result.getValue(), kTestNamespace, defaultFeatureCompatibility)); + kDefaultOpCtx, result.getValue(), kTestNamespace, serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, AcceptsIndexVersionV1) { @@ -385,7 +385,7 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionV1) { << "v" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -399,17 +399,13 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionV1) { } TEST(IndexSpecValidateTest, AcceptsIndexVersionV2Unique) { - ServerGlobalParams::FeatureCompatibility featureCompatibility; - featureCompatibility.setVersion( - ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo40); - auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" << "indexName" << "v" << 3), kTestNamespace, - featureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -420,7 +416,6 @@ TEST(IndexSpecValidateTest, AcceptsIndexVersionV2Unique) { << "v" << 3)), sorted(result.getValue())); - featureCompatibility.reset(); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsNotAnObject) { ASSERT_EQ(ErrorCodes::TypeMismatch, @@ -430,7 +425,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsNotAnObject) { << "collation" << 1), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::TypeMismatch, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -438,7 +433,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsNotAnObject) { << "collation" << "not an object"), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); ASSERT_EQ(ErrorCodes::TypeMismatch, validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("field" << 1) << "name" @@ -446,7 +441,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsNotAnObject) { << "collation" << BSONArray()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsEmpty) { @@ -457,7 +452,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsEmpty) { << "collation" << BSONObj()), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsPresentAndVersionIsLessThanV2) { @@ -471,7 +466,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfCollationIsPresentAndVersionIsLessTh << "v" << 1), kTestNamespace, - defaultFeatureCompatibility)); + serverGlobalParams.featureCompatibility)); } TEST(IndexSpecValidateTest, AcceptsAnyNonEmptyObjectValueForCollation) { @@ -484,7 +479,7 @@ TEST(IndexSpecValidateTest, AcceptsAnyNonEmptyObjectValueForCollation) { << BSON("locale" << "simple")), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -507,7 +502,7 @@ TEST(IndexSpecValidateTest, AcceptsAnyNonEmptyObjectValueForCollation) { << "collation" << BSON("unknownCollationOption" << true)), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -532,7 +527,7 @@ TEST(IndexSpecValidateTest, AcceptsIndexSpecIfCollationIsPresentAndVersionIsEqua << BSON("locale" << "en")), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); // We don't care about the order of the fields in the resulting index specification. @@ -557,7 +552,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfUnknownFieldIsPresentInSpecV2) { << "unknownField" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_EQ(ErrorCodes::InvalidIndexSpecificationOption, result); } @@ -570,7 +565,7 @@ TEST(IndexSpecValidateTest, ReturnsAnErrorIfUnknownFieldIsPresentInSpecV1) { << "unknownField" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_EQ(ErrorCodes::InvalidIndexSpecificationOption, result); } @@ -802,7 +797,7 @@ TEST(IndexSpecPartialFilterTest, FailsIfPartialFilterIsNotAnObject) { << "partialFilterExpression" << 1), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); } @@ -813,7 +808,7 @@ TEST(IndexSpecPartialFilterTest, FailsIfPartialFilterContainsBannedFeature) { << "partialFilterExpression" << BSON("$isolated" << 1)), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_EQ(result.getStatus(), ErrorCodes::QueryFeatureNotAllowed); } @@ -824,7 +819,7 @@ TEST(IndexSpecPartialFilterTest, AcceptsValidPartialFilterExpression) { << "partialFilterExpression" << BSON("a" << 1)), kTestNamespace, - defaultFeatureCompatibility); + serverGlobalParams.featureCompatibility); ASSERT_OK(result.getStatus()); } diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp index 43c4bbd4d6a..e9b98c38c63 100644 --- a/src/mongo/db/commands/feature_compatibility_version.cpp +++ b/src/mongo/db/commands/feature_compatibility_version.cpp @@ -147,8 +147,10 @@ void FeatureCompatibilityVersion::onInsertOrUpdate(OperationContext* opCtx, cons // To avoid extra log messages when the targetVersion is set/unset, only log when the version // changes. - auto oldVersion = serverGlobalParams.featureCompatibility.getVersion(); - if (oldVersion != newVersion) { + bool isDifferent = serverGlobalParams.featureCompatibility.isVersionInitialized() + ? serverGlobalParams.featureCompatibility.getVersion() != newVersion + : true; + if (isDifferent) { log() << "setting featureCompatibilityVersion to " << FeatureCompatibilityVersionParser::toString(newVersion); } diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 683d2f3e347..d52ef2343f2 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -839,10 +839,12 @@ void shutdownTask() { opCtx = uniqueOpCtx.get(); } - if (serverGlobalParams.featureCompatibility.getVersion() != - ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo40) { - // If we are in latest fCV, drop the 'checkpointTimestamp' collection so if we downgrade - // and then upgrade again, we do not trust a stale 'checkpointTimestamp'. + if (serverGlobalParams.featureCompatibility.isVersionInitialized() && + serverGlobalParams.featureCompatibility.getVersion() == + ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo36) { + // If we are fully downgraded, drop the 'checkpointTimestamp' collection. Otherwise a + // 3.6 binary can apply operations without updating the 'checkpointTimestamp', + // corrupting data. log(LogComponent::kReplication) << "shutdown: removing checkpointTimestamp collection..."; Status status = diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index a794d12932e..07acdf5be45 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -2535,10 +2535,11 @@ ReplicationCoordinatorImpl::_updateMemberStateFromTopologyCoordinator_inlock( } log() << "transition to " << newState << " from " << _memberState << rsLog; - // Initializes the featureCompatibilityVersion to the default value, because arbiters do not - // receive the replicated version. + // Initializes the featureCompatibilityVersion to the latest value, because arbiters do not + // receive the replicated version. This is to avoid bugs like SERVER-32639. if (newState.arbiter()) { - serverGlobalParams.featureCompatibility.reset(); + serverGlobalParams.featureCompatibility.setVersion( + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo40); } _memberState = newState; diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h index 7c146b7b063..5e4e934e2b0 100644 --- a/src/mongo/db/server_options.h +++ b/src/mongo/db/server_options.h @@ -199,10 +199,21 @@ struct ServerGlobalParams { } /** - * This safe getter for the featureCompatibilityVersion returns a default value when the - * version has not yet been set. + * This safe getter for the featureCompatibilityVersion parameter ensures the parameter has + * been initialized with a meaningful value. */ const Version getVersion() const { + invariant(isVersionInitialized()); + return _version.load(); + } + + /** + * This unsafe getter for the featureCompatibilityVersion parameter returns the last-stable + * featureCompatibilityVersion value if the parameter has not yet been initialized with a + * meaningful value. This getter should only be used if the parameter is intentionally read + * prior to the creation/parsing of the featureCompatibilityVersion document. + */ + const Version getVersionUnsafe() const { Version v = _version.load(); return (v == Version::kUnsetDefault36Behavior) ? Version::kFullyDowngradedTo36 : v; } diff --git a/src/mongo/db/service_context_d_test_fixture.cpp b/src/mongo/db/service_context_d_test_fixture.cpp index 4f69e5eb7b9..d42641381e9 100644 --- a/src/mongo/db/service_context_d_test_fixture.cpp +++ b/src/mongo/db/service_context_d_test_fixture.cpp @@ -51,6 +51,7 @@ namespace mongo { void ServiceContextMongoDTest::setUp() { + Test::setUp(); Client::initThread(getThreadName()); auto const serviceContext = getServiceContext(); @@ -86,6 +87,7 @@ void ServiceContextMongoDTest::tearDown() { ON_BLOCK_EXIT([&] { Client::destroy(); }); auto opCtx = cc().makeOperationContext(); _dropAllDBs(opCtx.get()); + Test::tearDown(); } ServiceContext* ServiceContextMongoDTest::getServiceContext() { diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp index a3381606ecf..a365149462e 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp @@ -513,13 +513,8 @@ void WiredTigerKVEngine::cleanShutdown() { // state is set. One is when `EncryptionHooks::restartRequired` is true. The other is when // the server shuts down because it refuses to acknowledge an FCV value more than one // version behind (e.g: 4.0 errors when reading 3.4). - // - // In the first case, we ideally do not perform a file format downgrade (but it is - // acceptable). In the second, the server must downgrade to allow a 3.6 binary to start - // up. Ideally, our internal FCV value would allow for older values, even if only to - // immediately shutdown. This would allow downstream logic, such as this method, to make - // an informed decision. const bool needsDowngrade = !_readOnly && + serverGlobalParams.featureCompatibility.isVersionInitialized() && serverGlobalParams.featureCompatibility.getVersion() == ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo36; diff --git a/src/mongo/db/views/view_catalog_test.cpp b/src/mongo/db/views/view_catalog_test.cpp index b18b5a4780d..8e811f3827a 100644 --- a/src/mongo/db/views/view_catalog_test.cpp +++ b/src/mongo/db/views/view_catalog_test.cpp @@ -131,6 +131,7 @@ protected: class ReplViewCatalogFixture : public ViewCatalogFixture { public: void setUp() override { + Test::setUp(); auto service = getServiceContext(); repl::ReplSettings settings; diff --git a/src/mongo/unittest/SConscript b/src/mongo/unittest/SConscript index b4e137ff4b9..50c94ac7abf 100644 --- a/src/mongo/unittest/SConscript +++ b/src/mongo/unittest/SConscript @@ -14,6 +14,7 @@ env.Library(target="unittest", ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/server_options_core', '$BUILD_DIR/mongo/util/options_parser/options_parser', ]) diff --git a/src/mongo/unittest/unittest.cpp b/src/mongo/unittest/unittest.cpp index fa5f177da61..9a87664f4c9 100644 --- a/src/mongo/unittest/unittest.cpp +++ b/src/mongo/unittest/unittest.cpp @@ -37,6 +37,7 @@ #include "mongo/base/checked_cast.h" #include "mongo/base/init.h" +#include "mongo/db/server_options.h" #include "mongo/logger/console_appender.h" #include "mongo/logger/log_manager.h" #include "mongo/logger/logger.h" @@ -179,8 +180,15 @@ void Test::run() { } } -void Test::setUp() {} -void Test::tearDown() {} +// Attempting to read the featureCompatibilityVersion parameter before it is explicitly initialized +// with a meaningful value will trigger failures as of SERVER-32630. +void Test::setUp() { + serverGlobalParams.featureCompatibility.setVersion( + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo40); +} +void Test::tearDown() { + serverGlobalParams.featureCompatibility.reset(); +} namespace { class StringVectorAppender : public logger::MessageLogDomain::EventAppender { diff --git a/src/mongo/unittest/unittest.h b/src/mongo/unittest/unittest.h index 44b1e68846c..1a41f7acbf3 100644 --- a/src/mongo/unittest/unittest.h +++ b/src/mongo/unittest/unittest.h @@ -344,7 +344,6 @@ protected: */ void printCapturedLogLines() const; -private: /** * Called on the test object before running the test. */ @@ -355,6 +354,7 @@ private: */ virtual void tearDown(); +private: /** * The test itself. */ |