SERVER-119504 Create a skeleton implementation for FCV upgrade/downgrade plugin system (#48466)
GitOrigin-RevId: 8c2d4d7e6aa2b901c0e993c1bad0139870c34f52
This commit is contained in:
parent
bfd5cd011a
commit
4a6b93ba10
@ -389,6 +389,9 @@ fcv:
|
||||
- src/mongo/db/commands/set_feature_compatibility_version*
|
||||
- src/mongo/db/op_observer/fcv_op_observer*
|
||||
- src/mongo/unittest/ensure_fcv.h
|
||||
- src/mongo/db/commands/set_feature_compatibility_version_steps/fcv_step.*
|
||||
- src/mongo/db/commands/set_feature_compatibility_version_steps/fcv_step_test.*
|
||||
- src/mongo/db/commands/set_feature_compatibility_version_steps/legacy_fcv_step.*
|
||||
|
||||
access_control:
|
||||
meta:
|
||||
|
||||
@ -1031,6 +1031,7 @@ mongo_cc_library(
|
||||
"//src/mongo/db/auth:user",
|
||||
"//src/mongo/db/auth:user_document_parser",
|
||||
"//src/mongo/db/commands/query_cmd:map_reduce_agg",
|
||||
"//src/mongo/db/commands/set_feature_compatibility_version_steps",
|
||||
"//src/mongo/db/global_catalog/ddl:sharding_catalog_manager",
|
||||
"//src/mongo/db/index_builds:index_builds_coordinator",
|
||||
"//src/mongo/db/pipeline",
|
||||
|
||||
@ -99,6 +99,9 @@ filters:
|
||||
- "*set_feature_compatibility_version*":
|
||||
approvers:
|
||||
- 10gen/server-catalog-and-routing-routing-and-topology
|
||||
- "*fcv_step*":
|
||||
approvers:
|
||||
- 10gen/server-catalog-and-routing-routing-and-topology
|
||||
- "snapshot_management*":
|
||||
approvers:
|
||||
- 10gen/server-replication-reviewers
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
#include "mongo/db/commands.h"
|
||||
#include "mongo/db/commands/feature_compatibility_version.h"
|
||||
#include "mongo/db/commands/set_feature_compatibility_version_gen.h"
|
||||
#include "mongo/db/commands/set_feature_compatibility_version_steps/fcv_step.h"
|
||||
#include "mongo/db/database_name.h"
|
||||
#include "mongo/db/dbdirectclient.h"
|
||||
#include "mongo/db/dbhelpers.h"
|
||||
@ -1138,6 +1139,9 @@ private:
|
||||
uasserted(ErrorCodes::CannotUpgrade,
|
||||
"Simulated dry-run validation failure via fail point.");
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.userCollectionsUassertsForUpgrade(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
// This helper function is for any actions that should be done before taking the global lock in
|
||||
@ -1149,6 +1153,10 @@ private:
|
||||
const multiversion::FeatureCompatibilityVersion requestedVersion,
|
||||
boost::optional<Timestamp> changeTimestamp) {
|
||||
auto role = ShardingState::get(opCtx)->pollClusterRole();
|
||||
const auto originalVersion =
|
||||
getTransitionFCVInfo(
|
||||
serverGlobalParams.featureCompatibility.acquireFCVSnapshot().getVersion())
|
||||
.from;
|
||||
// Note the config server is also considered a shard, so the ConfigServer and ShardServer
|
||||
// roles aren't mutually exclusive.
|
||||
if (role && role->has(ClusterRole::ConfigServer)) {
|
||||
@ -1158,6 +1166,9 @@ private:
|
||||
if (role && role->has(ClusterRole::ShardServer)) {
|
||||
// Shard server role actions.
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.prepareToUpgradeActionsBeforeGlobalLock(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
// This helper function is for any user collections creations, changes or deletions that need
|
||||
@ -1186,6 +1197,9 @@ private:
|
||||
return collection->shouldRemoveLegacyTimeseriesBucketingParametersHaveChanged();
|
||||
});
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.userCollectionsWorkForUpgrade(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
// This helper function is for updating server metadata to make sure the new features in the
|
||||
@ -1213,6 +1227,9 @@ private:
|
||||
}
|
||||
|
||||
_cleanUpDeprecatedCatalogMetadata(opCtx);
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.upgradeServerMetadata(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
// TODO(SERVER-100328): remove after 9.0 is branched.
|
||||
@ -1356,6 +1373,11 @@ private:
|
||||
// This helper function is for any actions that should be done before taking the global lock in
|
||||
// S mode.
|
||||
void _prepareToDowngradeActions(OperationContext* opCtx, const FCV requestedVersion) {
|
||||
const auto originalVersion =
|
||||
getTransitionFCVInfo(
|
||||
serverGlobalParams.featureCompatibility.acquireFCVSnapshot().getVersion())
|
||||
.from;
|
||||
|
||||
auto role = ShardingState::get(opCtx)->pollClusterRole();
|
||||
// Note the config server is also considered a shard, so the ConfigServer and ShardServer
|
||||
// roles aren't mutually exclusive.
|
||||
@ -1366,6 +1388,9 @@ private:
|
||||
if (role && role->has(ClusterRole::ShardServer)) {
|
||||
// Shard server role actions.
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.prepareToDowngradeActions(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1573,6 +1598,9 @@ private:
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.userCollectionsUassertsForDowngrade(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
// Remove cluster parameters from the clusterParameters collections which are not enabled on
|
||||
@ -1722,6 +1750,9 @@ private:
|
||||
if (role && role->has(ClusterRole::ShardServer)) {
|
||||
abortAllMultiUpdateCoordinators(opCtx, requestedVersion, originalVersion);
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext())
|
||||
.internalServerCleanupForDowngrade(opCtx, originalVersion, requestedVersion);
|
||||
}
|
||||
|
||||
void abortAllMultiUpdateCoordinators(OperationContext* opCtx,
|
||||
@ -2023,6 +2054,8 @@ private:
|
||||
.migrateRepresentativeQueriesFromQuerySettingsClusterParameterToDedicatedCollection(
|
||||
opCtx);
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext()).finalizeUpgrade(opCtx, requestedVersion);
|
||||
}
|
||||
|
||||
// _finalizeDowngrade is analogous to _finalizeUpgrade, but runs on downgrade. As with
|
||||
@ -2072,6 +2105,8 @@ private:
|
||||
opCtx);
|
||||
service.dropQueryShapeRepresentativeQueriesCollection(opCtx);
|
||||
}
|
||||
|
||||
FCVStepRegistry::get(opCtx->getServiceContext()).finalizeDowngrade(opCtx, requestedVersion);
|
||||
}
|
||||
void _forwardDryRunRequestToShards(OperationContext* opCtx,
|
||||
const SetFeatureCompatibilityVersion& request) {
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
load("//bazel:mongo_src_rules.bzl", "idl_generator", "mongo_cc_library", "mongo_cc_unit_test")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
exports_files(
|
||||
glob([
|
||||
"*.h",
|
||||
"*.cpp",
|
||||
]),
|
||||
)
|
||||
|
||||
mongo_cc_library(
|
||||
name = "set_feature_compatibility_version_steps",
|
||||
srcs = [
|
||||
"fcv_step.cpp",
|
||||
"legacy_fcv_step.cpp",
|
||||
],
|
||||
deps = [
|
||||
"//src/mongo:base",
|
||||
"//src/mongo/db:service_context",
|
||||
],
|
||||
)
|
||||
|
||||
mongo_cc_unit_test(
|
||||
name = "fcv_step_test",
|
||||
srcs = [
|
||||
"fcv_step_test.cpp",
|
||||
],
|
||||
tags = ["mongo_unittest_third_group"],
|
||||
deps = [
|
||||
"//src/mongo/db:service_context_test_fixture",
|
||||
"//src/mongo/db/commands/set_feature_compatibility_version_steps",
|
||||
],
|
||||
)
|
||||
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/db/commands/set_feature_compatibility_version_steps/fcv_step.h"
|
||||
|
||||
#include "mongo/logv2/log.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
|
||||
|
||||
namespace mongo {
|
||||
|
||||
namespace {
|
||||
|
||||
auto fcvStepRegistryDecoration = ServiceContext::declareDecoration<FCVStepRegistry>();
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
FCVStepRegistry& FCVStepRegistry::get(ServiceContext* serviceContext) {
|
||||
return fcvStepRegistryDecoration(serviceContext);
|
||||
}
|
||||
|
||||
FCVStepRegistry::~FCVStepRegistry() {
|
||||
invariant(_steps.empty());
|
||||
}
|
||||
|
||||
void FCVStepRegistry::prepareToUpgradeActionsBeforeGlobalLock(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {
|
||||
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->prepareToUpgradeActionsBeforeGlobalLock(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::userCollectionsUassertsForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->userCollectionsUassertsForUpgrade(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::userCollectionsWorkForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->userCollectionsWorkForUpgrade(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void FCVStepRegistry::upgradeServerMetadata(OperationContext* opCtx,
|
||||
const FCV originalVersion,
|
||||
const FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->upgradeServerMetadata(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::finalizeUpgrade(OperationContext* opCtx, const FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->finalizeUpgrade(opCtx, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::prepareToDowngradeActions(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->prepareToDowngradeActions(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::userCollectionsUassertsForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->userCollectionsUassertsForDowngrade(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::internalServerCleanupForDowngrade(OperationContext* opCtx,
|
||||
const FCV originalVersion,
|
||||
const FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->internalServerCleanupForDowngrade(opCtx, originalVersion, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
void FCVStepRegistry::finalizeDowngrade(OperationContext* opCtx, const FCV requestedVersion) {
|
||||
std::for_each(_steps.begin(), _steps.end(), [&](FCVStep* step) {
|
||||
step->finalizeDowngrade(opCtx, requestedVersion);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void FCVStepRegistry::_registerFeature(FCVStep* step) {
|
||||
_steps.push_back(step);
|
||||
}
|
||||
|
||||
void FCVStepRegistry::_unregisterFeature(FCVStep* step) {
|
||||
auto it = std::find(_steps.begin(), _steps.end(), step);
|
||||
invariant(it != _steps.end());
|
||||
_steps.erase(it);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mongo
|
||||
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mongo/db/operation_context.h"
|
||||
#include "mongo/db/server_options.h"
|
||||
#include "mongo/db/service_context.h"
|
||||
#include "mongo/db/topology/cluster_role.h"
|
||||
#include "mongo/util/modules.h"
|
||||
#include "mongo/util/version/releases.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
namespace mongo {
|
||||
|
||||
/**
|
||||
* FCVSteps are the steps which need to be executed
|
||||
* when FCV is upgraded/downgraded.
|
||||
* Using this interface avoids the need to manually hook the various places in
|
||||
* SetFeatureCompatibilityVersionCommand where the upgrade/downgrade steps are called.
|
||||
*
|
||||
* To define an FCV step, a class need to:
|
||||
*
|
||||
* 1. Inherit from FCVStep
|
||||
* 2. Implement the virtual methods in FCVStep (empty implementations are provided where it makes
|
||||
* sense)
|
||||
* 3. Store a singleton object of the class somewhere (ideally as a ServiceContext decoration).
|
||||
* 4. Define a public static `get(ServiceContext*)` function.
|
||||
* 5. Define a static FCVStepRegistry::Registerer object to declare the name of the step.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #include "mongo/db/commands/set_feature_compatibility_version_steps/fcv_step.h"
|
||||
*
|
||||
* class FooStep : public FCVStep {
|
||||
* public:
|
||||
* static FooStep* get(ServiceContext* serviceContext);
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* private:
|
||||
*
|
||||
* // Mandatory:
|
||||
* void userCollectionsUassertsForUpgrade(OperationContext* opCtx,
|
||||
* FCV originalVersion,
|
||||
* FCV requestedVersion) {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* void userCollectionsWorkForUpgrade(OperationContext* opCtx,
|
||||
* FCV originalVersion,
|
||||
* FCV requestedVersion) {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
*
|
||||
* namespace {
|
||||
*
|
||||
* const auto _fooStepDecoration = ServiceContext::declareDecoration<FooStep>();
|
||||
*
|
||||
* const FCVStepRegistry::Registerer<FooStep> _FooStepRegisterer("FooStep");
|
||||
*
|
||||
* } // namespace
|
||||
*
|
||||
* FooStep* FooStep::get(ServiceContext* serviceContext) {
|
||||
* return &_fooStepDecoration(serviceContext);
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main API implemented by each FCV step
|
||||
*/
|
||||
class MONGO_MOD_PRIVATE FCVStep {
|
||||
public:
|
||||
using FCV = multiversion::FeatureCompatibilityVersion;
|
||||
virtual void prepareToUpgradeActionsBeforeGlobalLock(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void userCollectionsUassertsForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void userCollectionsWorkForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void upgradeServerMetadata(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void finalizeUpgrade(OperationContext* opCtx, FCV requestedVersion) {}
|
||||
|
||||
virtual void prepareToDowngradeActions(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void userCollectionsUassertsForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void internalServerCleanupForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) {}
|
||||
|
||||
virtual void finalizeDowngrade(OperationContext* opCtx, FCV requestedVersion) {}
|
||||
|
||||
/**
|
||||
* Returns the name of the step. Used for logging purposes.
|
||||
*/
|
||||
virtual std::string getStepName() const = 0;
|
||||
|
||||
/*
|
||||
* Allows a step not to register
|
||||
*/
|
||||
virtual bool shouldRegisterFCVStep() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The registry of FCVSteps.
|
||||
*/
|
||||
class MONGO_MOD_PUB FCVStepRegistry final : public FCVStep {
|
||||
FCVStepRegistry(const FCVStepRegistry&) = delete;
|
||||
FCVStepRegistry& operator=(const FCVStepRegistry&) = delete;
|
||||
|
||||
public:
|
||||
template <class ActualStep>
|
||||
class Registerer {
|
||||
Registerer(const Registerer&) = delete;
|
||||
Registerer& operator=(const Registerer&) = delete;
|
||||
|
||||
public:
|
||||
explicit Registerer(std::string name)
|
||||
: _registerer(
|
||||
std::move(name),
|
||||
[&](ServiceContext* serviceContext) {
|
||||
if (!_registered) {
|
||||
_registered = ActualStep::get(serviceContext)->shouldRegisterFCVStep();
|
||||
}
|
||||
if (*_registered) {
|
||||
FCVStepRegistry::get(serviceContext)
|
||||
._registerFeature(ActualStep::get(serviceContext));
|
||||
}
|
||||
},
|
||||
[&](ServiceContext* serviceContext) {
|
||||
if (_registered && *_registered) {
|
||||
FCVStepRegistry::get(serviceContext)
|
||||
._unregisterFeature(ActualStep::get(serviceContext));
|
||||
}
|
||||
}) {}
|
||||
|
||||
private:
|
||||
boost::optional<bool> _registered;
|
||||
ServiceContext::ConstructorActionRegisterer _registerer;
|
||||
};
|
||||
|
||||
FCVStepRegistry() = default;
|
||||
virtual ~FCVStepRegistry();
|
||||
|
||||
static FCVStepRegistry& get(ServiceContext* serviceContext);
|
||||
|
||||
void prepareToUpgradeActionsBeforeGlobalLock(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void userCollectionsUassertsForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void userCollectionsWorkForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void upgradeServerMetadata(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void finalizeUpgrade(OperationContext* opCtx, FCV requestedVersion) final;
|
||||
|
||||
void prepareToDowngradeActions(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void userCollectionsUassertsForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void internalServerCleanupForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final;
|
||||
|
||||
void finalizeDowngrade(OperationContext* opCtx, FCV requestedVersion) final;
|
||||
|
||||
|
||||
inline std::string getStepName() const final {
|
||||
return "FCVStepRegistry";
|
||||
}
|
||||
|
||||
private:
|
||||
void _registerFeature(FCVStep* step);
|
||||
void _unregisterFeature(FCVStep* step);
|
||||
|
||||
std::vector<FCVStep*> _steps;
|
||||
};
|
||||
|
||||
} // namespace mongo
|
||||
@ -0,0 +1,233 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/db/commands/set_feature_compatibility_version_steps/fcv_step.h"
|
||||
|
||||
#include "mongo/db/service_context.h"
|
||||
#include "mongo/db/service_context_test_fixture.h"
|
||||
#include "mongo/unittest/unittest.h"
|
||||
#include "mongo/util/version/releases.h"
|
||||
|
||||
|
||||
namespace mongo {
|
||||
namespace {
|
||||
|
||||
|
||||
template <class ActualStep>
|
||||
class TestStep : public FCVStep {
|
||||
public:
|
||||
using FCV = FCVStep::FCV;
|
||||
int numCallsPrepareToUpgradeActionsBeforeGlobalLock{0};
|
||||
int numCallsUserCollectionsUassertsForUpgrade{0};
|
||||
int numCallsUserCollectionsWorkForUpgrade{0};
|
||||
int numCallsUpgradeServerMetadata{0};
|
||||
int numCallsFinalizeUpgrade{0};
|
||||
int numCallsPrepareToDowngradeActions{0};
|
||||
int numCallsUserCollectionsUassertsForDowngrade{0};
|
||||
int numCallsInternalServerCleanupForDowngrade{0};
|
||||
int numCallsFinalizeDowngrade{0};
|
||||
|
||||
protected:
|
||||
void prepareToUpgradeActionsBeforeGlobalLock(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsPrepareToUpgradeActionsBeforeGlobalLock++;
|
||||
}
|
||||
|
||||
void userCollectionsUassertsForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsUserCollectionsUassertsForUpgrade++;
|
||||
}
|
||||
|
||||
void userCollectionsWorkForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsUserCollectionsWorkForUpgrade++;
|
||||
}
|
||||
|
||||
void upgradeServerMetadata(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsUpgradeServerMetadata++;
|
||||
}
|
||||
|
||||
void finalizeUpgrade(OperationContext* optCtx, FCV requestedVersion) override {
|
||||
numCallsFinalizeUpgrade++;
|
||||
}
|
||||
|
||||
void prepareToDowngradeActions(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsPrepareToDowngradeActions++;
|
||||
}
|
||||
|
||||
void userCollectionsUassertsForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsUserCollectionsUassertsForDowngrade++;
|
||||
}
|
||||
|
||||
void internalServerCleanupForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) override {
|
||||
numCallsInternalServerCleanupForDowngrade++;
|
||||
}
|
||||
|
||||
void finalizeDowngrade(OperationContext* opCtx, FCV requestedVersion) override {
|
||||
numCallsFinalizeDowngrade++;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An FCV Step which is never executed
|
||||
*/
|
||||
|
||||
class FCVStepNeverExecutes : public TestStep<FCVStepNeverExecutes> {
|
||||
public:
|
||||
static FCVStepNeverExecutes* get(ServiceContext* serviceContext);
|
||||
bool shouldRegisterFCVStep() const final {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string getStepName() const final {
|
||||
return "FCVStepNeverExecutes";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const auto getFCVStepNeverExecutes = ServiceContext::declareDecoration<FCVStepNeverExecutes>();
|
||||
|
||||
FCVStepRegistry::Registerer<FCVStepNeverExecutes> fcvStepNeverExecutesRegisterer(
|
||||
"FCVStepNeverExecutes");
|
||||
|
||||
FCVStepNeverExecutes* FCVStepNeverExecutes::get(ServiceContext* serviceContext) {
|
||||
return &getFCVStepNeverExecutes(serviceContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* An FCV Step which is always executed
|
||||
*/
|
||||
|
||||
class FCVStepAlwaysExecutes : public TestStep<FCVStepAlwaysExecutes> {
|
||||
public:
|
||||
static FCVStepAlwaysExecutes* get(ServiceContext* serviceContext);
|
||||
bool shouldRegisterFCVStep() const final {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string getStepName() const final {
|
||||
return "FCVStepAlwaysExecutes";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const auto getFCVStepAlwaysExecutes = ServiceContext::declareDecoration<FCVStepAlwaysExecutes>();
|
||||
|
||||
FCVStepRegistry::Registerer<FCVStepAlwaysExecutes> fcvStepAlwaysExecutesRegister(
|
||||
"FCVStepAlwaysExecutes");
|
||||
|
||||
FCVStepAlwaysExecutes* FCVStepAlwaysExecutes::get(ServiceContext* serviceContext) {
|
||||
return &getFCVStepAlwaysExecutes(serviceContext);
|
||||
}
|
||||
|
||||
|
||||
class FCVStepRegistryTest : public ServiceContextTest {};
|
||||
|
||||
TEST_F(FCVStepRegistryTest, FCVStepRegistrySimple) {
|
||||
auto sc = getGlobalServiceContext();
|
||||
auto opCtxHolder = makeOperationContext();
|
||||
auto opCtx = opCtxHolder.get();
|
||||
|
||||
auto a = FCVStepNeverExecutes::get(sc);
|
||||
auto b = FCVStepAlwaysExecutes::get(sc);
|
||||
|
||||
auto originalVersion = FCVStep::FCV::kVersion_8_0;
|
||||
auto requestedVersion = FCVStep::FCV::kVersion_8_3;
|
||||
|
||||
ASSERT_EQ(0, a->numCallsPrepareToUpgradeActionsBeforeGlobalLock);
|
||||
ASSERT_EQ(0, a->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(0, a->numCallsUserCollectionsWorkForUpgrade);
|
||||
ASSERT_EQ(0, a->numCallsUpgradeServerMetadata);
|
||||
ASSERT_EQ(0, a->numCallsFinalizeUpgrade);
|
||||
ASSERT_EQ(0, a->numCallsPrepareToDowngradeActions);
|
||||
ASSERT_EQ(0, a->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(0, a->numCallsInternalServerCleanupForDowngrade);
|
||||
ASSERT_EQ(0, a->numCallsFinalizeDowngrade);
|
||||
|
||||
ASSERT_EQ(0, b->numCallsPrepareToUpgradeActionsBeforeGlobalLock);
|
||||
ASSERT_EQ(0, b->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(0, b->numCallsUserCollectionsWorkForUpgrade);
|
||||
ASSERT_EQ(0, b->numCallsUpgradeServerMetadata);
|
||||
ASSERT_EQ(0, b->numCallsFinalizeUpgrade);
|
||||
ASSERT_EQ(0, b->numCallsPrepareToDowngradeActions);
|
||||
ASSERT_EQ(0, b->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(0, b->numCallsInternalServerCleanupForDowngrade);
|
||||
ASSERT_EQ(0, b->numCallsFinalizeDowngrade);
|
||||
|
||||
FCVStepRegistry::get(sc).prepareToUpgradeActionsBeforeGlobalLock(
|
||||
opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).userCollectionsUassertsForUpgrade(
|
||||
opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).userCollectionsWorkForUpgrade(
|
||||
opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).upgradeServerMetadata(opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).finalizeUpgrade(opCtx, requestedVersion);
|
||||
FCVStepRegistry::get(sc).prepareToDowngradeActions(opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).userCollectionsUassertsForDowngrade(
|
||||
opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).internalServerCleanupForDowngrade(
|
||||
opCtx, originalVersion, requestedVersion);
|
||||
FCVStepRegistry::get(sc).finalizeDowngrade(opCtx, requestedVersion);
|
||||
|
||||
|
||||
ASSERT_EQ(0, a->numCallsPrepareToUpgradeActionsBeforeGlobalLock);
|
||||
ASSERT_EQ(0, a->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(0, a->numCallsUserCollectionsWorkForUpgrade);
|
||||
ASSERT_EQ(0, a->numCallsUpgradeServerMetadata);
|
||||
ASSERT_EQ(0, a->numCallsFinalizeUpgrade);
|
||||
ASSERT_EQ(0, a->numCallsPrepareToDowngradeActions);
|
||||
ASSERT_EQ(0, a->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(0, a->numCallsInternalServerCleanupForDowngrade);
|
||||
ASSERT_EQ(0, a->numCallsFinalizeDowngrade);
|
||||
|
||||
ASSERT_EQ(1, b->numCallsPrepareToUpgradeActionsBeforeGlobalLock);
|
||||
ASSERT_EQ(1, b->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(1, b->numCallsUserCollectionsWorkForUpgrade);
|
||||
ASSERT_EQ(1, b->numCallsUpgradeServerMetadata);
|
||||
ASSERT_EQ(1, b->numCallsFinalizeUpgrade);
|
||||
ASSERT_EQ(1, b->numCallsPrepareToDowngradeActions);
|
||||
ASSERT_EQ(1, b->numCallsUserCollectionsUassertsForDowngrade);
|
||||
ASSERT_EQ(1, b->numCallsInternalServerCleanupForDowngrade);
|
||||
ASSERT_EQ(1, b->numCallsFinalizeDowngrade);
|
||||
}
|
||||
} // namespace
|
||||
} // namespace mongo
|
||||
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/db/commands/set_feature_compatibility_version_steps/fcv_step.h"
|
||||
#include "mongo/db/service_context.h"
|
||||
|
||||
namespace mongo {
|
||||
|
||||
|
||||
class LegacyFCVStep : public mongo::FCVStep {
|
||||
public:
|
||||
static LegacyFCVStep* get(ServiceContext* serviceContext);
|
||||
|
||||
|
||||
inline std::string getStepName() const final {
|
||||
return "LegacyFCVStep";
|
||||
}
|
||||
|
||||
private:
|
||||
void prepareToUpgradeActionsBeforeGlobalLock(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void userCollectionsUassertsForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void userCollectionsWorkForUpgrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void upgradeServerMetadata(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void finalizeUpgrade(OperationContext* optCtx, FCV requestedVersion) final {}
|
||||
|
||||
void prepareToDowngradeActions(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void userCollectionsUassertsForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void internalServerCleanupForDowngrade(OperationContext* opCtx,
|
||||
FCV originalVersion,
|
||||
FCV requestedVersion) final {}
|
||||
|
||||
void finalizeDowngrade(OperationContext* opCtx, FCV requestedVersion) final {}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
const auto _sampleDecoration = ServiceContext::declareDecoration<LegacyFCVStep>();
|
||||
|
||||
const FCVStepRegistry::Registerer<LegacyFCVStep> _LegacyFCVStepRegisterer("LegacyFCVStep");
|
||||
|
||||
} // namespace
|
||||
|
||||
LegacyFCVStep* LegacyFCVStep::get(ServiceContext* serviceContext) {
|
||||
return &_sampleDecoration(serviceContext);
|
||||
}
|
||||
|
||||
} // namespace mongo
|
||||
|
||||
Loading…
Reference in New Issue
Block a user