summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorMaria van Keulen <maria@mongodb.com>2018-02-25 18:57:19 -0500
committerMaria van Keulen <maria@mongodb.com>2018-03-09 15:04:28 -0500
commita4d29b292f1bc42ae8133b0a0984c2b012c43528 (patch)
treea48307b9502bac095c30179b67f4db6cac155225 /src/mongo
parentdec9b8f5f4b60b8f29244ecdfd759b6141aa7d34 (diff)
downloadmongo-a4d29b292f1bc42ae8133b0a0984c2b012c43528.tar.gz
SERVER-32630 Ensure the fCV parameter is initialized before reading
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/catalog/database_impl.cpp4
-rw-r--r--src/mongo/db/catalog/index_spec_validate_test.cpp95
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.cpp6
-rw-r--r--src/mongo/db/db.cpp10
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp7
-rw-r--r--src/mongo/db/server_options.h15
-rw-r--r--src/mongo/db/service_context_d_test_fixture.cpp2
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp7
-rw-r--r--src/mongo/db/views/view_catalog_test.cpp1
-rw-r--r--src/mongo/unittest/SConscript1
-rw-r--r--src/mongo/unittest/unittest.cpp12
-rw-r--r--src/mongo/unittest/unittest.h2
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.
*/