diff options
Diffstat (limited to 'src/mongo/idl')
| -rw-r--r-- | src/mongo/idl/SConscript | 20 | ||||
| -rw-r--r-- | src/mongo/idl/basic_types.h | 5 | ||||
| -rw-r--r-- | src/mongo/idl/basic_types.idl | 7 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_parameter_synchronization_helpers.cpp | 147 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_parameter_synchronization_helpers.h | 105 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_server_parameter_initializer.cpp | 95 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_server_parameter_initializer.h | 46 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_server_parameter_initializer_test.cpp | 3 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_server_parameter_op_observer.cpp | 63 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_server_parameter_op_observer.h | 19 | ||||
| -rw-r--r-- | src/mongo/idl/cluster_server_parameter_op_observer_test.cpp | 173 | ||||
| -rw-r--r-- | src/mongo/idl/server_parameter_test_util.h | 43 |
12 files changed, 292 insertions, 434 deletions
diff --git a/src/mongo/idl/SConscript b/src/mongo/idl/SConscript index a95eb570aa5..2fcbf03c37a 100644 --- a/src/mongo/idl/SConscript +++ b/src/mongo/idl/SConscript @@ -74,23 +74,7 @@ env.Library( LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/dbdirectclient', '$BUILD_DIR/mongo/db/repl/replica_set_aware_service', - 'cluster_parameter_synchronization_helpers', - ], -) - -env.Library( - target='cluster_parameter_synchronization_helpers', - source=[ - 'cluster_parameter_synchronization_helpers.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/base', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/audit', - '$BUILD_DIR/mongo/db/db_raii', - '$BUILD_DIR/mongo/db/logical_time', - ], + ] ) env.Library( @@ -104,7 +88,6 @@ env.Library( LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/dbdirectclient', '$BUILD_DIR/mongo/db/op_observer', - 'cluster_parameter_synchronization_helpers', 'cluster_server_parameter_initializer', ], ) @@ -153,7 +136,6 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/repl/storage_interface_impl', '$BUILD_DIR/mongo/db/service_context_d_test_fixture', '$BUILD_DIR/mongo/util/signal_handlers', - 'cluster_parameter_synchronization_helpers', 'cluster_server_parameter_initializer', 'cluster_server_parameter_test_parameter', ], diff --git a/src/mongo/idl/basic_types.h b/src/mongo/idl/basic_types.h index 4f93115bf0c..4b77f57461d 100644 --- a/src/mongo/idl/basic_types.h +++ b/src/mongo/idl/basic_types.h @@ -127,11 +127,6 @@ private: boost::optional<bool> _value; }; -template <typename H> -H AbslHashValue(H h, const OptionalBool& optBool) { - return H::combine(std::move(h), optBool.has_value(), bool(optBool)); -} - /** * Class to represent a BSON element with any type from IDL. The caller must ensure that the backing * BSON stays alive while this type is in use. diff --git a/src/mongo/idl/basic_types.idl b/src/mongo/idl/basic_types.idl index e41c18b7714..634b05d9539 100644 --- a/src/mongo/idl/basic_types.idl +++ b/src/mongo/idl/basic_types.idl @@ -163,13 +163,6 @@ types: cpp_type: "std::vector<std::uint8_t>" deserializer: "mongo::BSONElement::_binDataVector" - bindata_sensitive: - bson_serialization_type: bindata - bindata_subtype: sensitive - description: "A BSON bindata of sensitive sub type" - cpp_type: "std::vector<std::uint8_t>" - deserializer: "mongo::BSONElement::_binDataVector" - uuid: bson_serialization_type: bindata bindata_subtype: uuid diff --git a/src/mongo/idl/cluster_parameter_synchronization_helpers.cpp b/src/mongo/idl/cluster_parameter_synchronization_helpers.cpp deleted file mode 100644 index 1566c42fa8e..00000000000 --- a/src/mongo/idl/cluster_parameter_synchronization_helpers.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Copyright (C) 2023-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. - */ -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl - -#include "mongo/idl/cluster_parameter_synchronization_helpers.h" - -#include "mongo/base/string_data.h" -#include "mongo/db/audit.h" -#include "mongo/db/catalog_raii.h" -#include "mongo/db/multitenancy_gen.h" -#include "mongo/logv2/log.h" - -namespace mongo::cluster_parameters { - -constexpr auto kIdField = "_id"_sd; -constexpr auto kCPTField = "clusterParameterTime"_sd; -constexpr auto kOplog = "oplog"_sd; - -void updateParameter(BSONObj doc, StringData mode) { - auto nameElem = doc[kIdField]; - if (nameElem.type() != String) { - LOGV2_DEBUG(6226301, - 1, - "Update with invalid cluster server parameter name", - "mode"_attr = mode, - "_id"_attr = nameElem); - return; - } - - auto name = nameElem.valueStringData(); - auto* sp = ServerParameterSet::getClusterParameterSet()->getIfExists(name); - if (!sp) { - LOGV2_DEBUG(6226300, - 3, - "Update to unknown cluster server parameter", - "mode"_attr = mode, - "name"_attr = name); - return; - } - - auto cptElem = doc[kCPTField]; - if ((cptElem.type() != mongo::Date) && (cptElem.type() != bsonTimestamp)) { - LOGV2_DEBUG(6226302, - 1, - "Update to cluster server parameter has invalid clusterParameterTime", - "mode"_attr = mode, - "name"_attr = name, - "clusterParameterTime"_attr = cptElem); - return; - } - - uassertStatusOK(sp->set(doc)); -} - -void clearParameter(ServerParameter* sp) { - if (sp->getClusterParameterTime() == LogicalTime::kUninitialized) { - // Nothing to clear. - return; - } - - uassertStatusOK(sp->reset()); -} - -void clearParameter(StringData id) { - auto* sp = ServerParameterSet::getClusterParameterSet()->getIfExists(id); - if (!sp) { - LOGV2_DEBUG(6226303, - 5, - "oplog event deletion of unknown cluster server parameter", - "name"_attr = id); - return; - } - - clearParameter(sp); -} - -void clearAllParameters() { - const auto& params = ServerParameterSet::getClusterParameterSet()->getMap(); - for (const auto& it : params) { - clearParameter(it.second); - } -} - -void initializeAllParametersFromDisk(OperationContext* opCtx) { - doLoadAllParametersFromDisk( - opCtx, "initializing"_sd, [](OperationContext* opCtx, BSONObj doc, StringData mode) { - updateParameter(doc, mode); - }); -} - -void resynchronizeAllParametersFromDisk(OperationContext* opCtx) { - const auto& allParams = ServerParameterSet::getClusterParameterSet()->getMap(); - std::set<std::string> unsetSettings; - for (const auto& it : allParams) { - unsetSettings.insert(it.second->name()); - } - - doLoadAllParametersFromDisk( - opCtx, - "resynchronizing"_sd, - [&unsetSettings](OperationContext* opCtx, BSONObj doc, StringData mode) { - unsetSettings.erase(doc[kIdField].str()); - updateParameter(doc, mode); - }); - - // For all known settings which were not present in this resync, - // explicitly clear any value which may be present in-memory. - for (const auto& setting : unsetSettings) { - clearParameter(setting); - } -} - -void maybeUpdateClusterParametersPostImportCollectionCommit(OperationContext* opCtx, - const NamespaceString& nss) { - if (nss == NamespaceString::kClusterParametersNamespace) { - // Something was imported, do a full collection scan to sync up. - cluster_parameters::initializeAllParametersFromDisk(opCtx); - } -} - -} // namespace mongo::cluster_parameters diff --git a/src/mongo/idl/cluster_parameter_synchronization_helpers.h b/src/mongo/idl/cluster_parameter_synchronization_helpers.h deleted file mode 100644 index d69271a7c03..00000000000 --- a/src/mongo/idl/cluster_parameter_synchronization_helpers.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (C) 2023-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/db_raii.h" - -namespace mongo { - -namespace cluster_parameters { - -void updateParameter(BSONObj doc, StringData mode); - -void clearParameter(ServerParameter* sp); - -void clearParameter(StringData id); - -void clearAllParameters(); - -/** - * Used to initialize in-memory cluster parameter state based on the on-disk contents after startup - * recovery or initial sync is complete. - */ -void initializeAllParametersFromDisk(OperationContext* opCtx); - -/** - * Used on rollback. Updates settings which are present and clears settings which are not. - */ -void resynchronizeAllParametersFromDisk(OperationContext* opCtx); - -template <typename OnEntry> -void doLoadAllParametersFromDisk(OperationContext* opCtx, StringData mode, OnEntry onEntry) try { - - // If the RecoveryUnit already had an open snapshot, keep the snapshot open. Otherwise - // abandon the snapshot when exiting the function. - ScopeGuard scopeGuard([&] { opCtx->recoveryUnit()->abandonSnapshot(); }); - if (opCtx->recoveryUnit()->isActive()) { - scopeGuard.dismiss(); - } - - AutoGetCollectionForRead coll(opCtx, NamespaceString::kClusterParametersNamespace); - if (!coll) { - return; - } - - std::vector<Status> failures; - - auto cursor = coll->getCursor(opCtx); - for (auto doc = cursor->next(); doc; doc = cursor->next()) { - try { - onEntry(opCtx, doc.get().data.toBson(), mode); - } catch (const DBException& ex) { - failures.push_back(ex.toStatus()); - } - } - - if (!failures.empty()) { - StringBuilder msg; - for (const auto& failure : failures) { - msg << failure.toString() << ", "; - } - msg.reset(msg.len() - 2); - uasserted(ErrorCodes::OperationFailed, msg.str()); - } -} catch (const DBException& ex) { - uassertStatusOK(ex.toStatus().withContext( - str::stream() << "Failed " << mode << " cluster server parameters from disk")); -} - -/** - * Used after an importCollection commits. Will update the in-memory cluster parameter state if the - * given namespace is a cluster parameters namespace. - */ -void maybeUpdateClusterParametersPostImportCollectionCommit(OperationContext* opCtx, - const NamespaceString& nss); - -} // namespace cluster_parameters - -} // namespace mongo diff --git a/src/mongo/idl/cluster_server_parameter_initializer.cpp b/src/mongo/idl/cluster_server_parameter_initializer.cpp index e28e0542ecb..3205f7a4fa7 100644 --- a/src/mongo/idl/cluster_server_parameter_initializer.cpp +++ b/src/mongo/idl/cluster_server_parameter_initializer.cpp @@ -34,7 +34,6 @@ #include "mongo/base/string_data.h" #include "mongo/db/repl/replica_set_aware_service.h" #include "mongo/db/service_context.h" -#include "mongo/idl/cluster_parameter_synchronization_helpers.h" #include "mongo/logv2/log.h" namespace mongo { @@ -59,10 +58,102 @@ ClusterServerParameterInitializer* ClusterServerParameterInitializer::get( return &getInstance(serviceContext); } +void ClusterServerParameterInitializer::updateParameter(BSONObj doc, StringData mode) { + auto nameElem = doc[kIdField]; + if (nameElem.type() != String) { + LOGV2_DEBUG(6226301, + 1, + "Update with invalid cluster server parameter name", + "mode"_attr = mode, + "_id"_attr = nameElem); + return; + } + + auto name = nameElem.valueStringData(); + auto* sp = ServerParameterSet::getClusterParameterSet()->getIfExists(name); + if (!sp) { + LOGV2_DEBUG(6226300, + 3, + "Update to unknown cluster server parameter", + "mode"_attr = mode, + "name"_attr = name); + return; + } + + auto cptElem = doc[kCPTField]; + if ((cptElem.type() != mongo::Date) && (cptElem.type() != bsonTimestamp)) { + LOGV2_DEBUG(6226302, + 1, + "Update to cluster server parameter has invalid clusterParameterTime", + "mode"_attr = mode, + "name"_attr = name, + "clusterParameterTime"_attr = cptElem); + return; + } + + uassertStatusOK(sp->set(doc)); +} + +void ClusterServerParameterInitializer::clearParameter(ServerParameter* sp) { + if (sp->getClusterParameterTime() == LogicalTime::kUninitialized) { + // Nothing to clear. + return; + } + + uassertStatusOK(sp->reset()); +} + +void ClusterServerParameterInitializer::clearParameter(StringData id) { + auto* sp = ServerParameterSet::getClusterParameterSet()->getIfExists(id); + if (!sp) { + LOGV2_DEBUG(6226303, + 5, + "oplog event deletion of unknown cluster server parameter", + "name"_attr = id); + return; + } + + clearParameter(sp); +} + +void ClusterServerParameterInitializer::clearAllParameters() { + const auto& params = ServerParameterSet::getClusterParameterSet()->getMap(); + for (const auto& it : params) { + clearParameter(it.second); + } +} + +void ClusterServerParameterInitializer::initializeAllParametersFromDisk(OperationContext* opCtx) { + doLoadAllParametersFromDisk(opCtx, "initializing"_sd, [this](BSONObj doc, StringData mode) { + updateParameter(doc, mode); + }); +} + +void ClusterServerParameterInitializer::resynchronizeAllParametersFromDisk( + OperationContext* opCtx) { + const auto& allParams = ServerParameterSet::getClusterParameterSet()->getMap(); + std::set<std::string> unsetSettings; + for (const auto& it : allParams) { + unsetSettings.insert(it.second->name()); + } + + doLoadAllParametersFromDisk( + opCtx, "resynchronizing"_sd, [this, &unsetSettings](BSONObj doc, StringData mode) { + unsetSettings.erase(doc[kIdField].str()); + updateParameter(doc, mode); + }); + + // For all known settings which were not present in this resync, + // explicitly clear any value which may be present in-memory. + for (const auto& setting : unsetSettings) { + clearParameter(setting); + } +} + void ClusterServerParameterInitializer::onInitialDataAvailable(OperationContext* opCtx, bool isMajorityDataAvailable) { LOGV2_INFO(6608200, "Initializing cluster server parameters from disk"); - cluster_parameters::initializeAllParametersFromDisk(opCtx); + initializeAllParametersFromDisk(opCtx); } } // namespace mongo diff --git a/src/mongo/idl/cluster_server_parameter_initializer.h b/src/mongo/idl/cluster_server_parameter_initializer.h index 49d501a7e6d..0eb02bb058c 100644 --- a/src/mongo/idl/cluster_server_parameter_initializer.h +++ b/src/mongo/idl/cluster_server_parameter_initializer.h @@ -52,6 +52,23 @@ public: static ClusterServerParameterInitializer* get(OperationContext* opCtx); static ClusterServerParameterInitializer* get(ServiceContext* serviceContext); + void updateParameter(BSONObj doc, StringData mode); + void clearParameter(ServerParameter* sp); + void clearParameter(StringData id); + void clearAllParameters(); + + /** + * Used to initialize in-memory cluster parameter state based on the on-disk contents after + * startup recovery or initial sync is complete. + */ + void initializeAllParametersFromDisk(OperationContext* opCtx); + + /** + * Used on rollback and rename with drop. + * Updates settings which are present and clears settings which are not. + */ + void resynchronizeAllParametersFromDisk(OperationContext* opCtx); + // Virtual methods coming from the ReplicaSetAwareService void onStartup(OperationContext* opCtx) override final {} @@ -65,6 +82,35 @@ public: void onStepUpComplete(OperationContext* opCtx, long long term) override final {} void onStepDown() override final {} void onBecomeArbiter() override final {} + +private: + template <typename OnEntry> + void doLoadAllParametersFromDisk(OperationContext* opCtx, + StringData mode, + OnEntry onEntry) try { + std::vector<Status> failures; + + DBDirectClient client(opCtx); + FindCommandRequest findRequest{NamespaceString::kClusterParametersNamespace}; + client.find(std::move(findRequest), ReadPreferenceSetting{}, [&](BSONObj doc) { + try { + onEntry(doc, mode); + } catch (const DBException& ex) { + failures.push_back(ex.toStatus()); + } + }); + if (!failures.empty()) { + StringBuilder msg; + for (const auto& failure : failures) { + msg << failure.toString() << ", "; + } + msg.reset(msg.len() - 2); + uasserted(ErrorCodes::OperationFailed, msg.str()); + } + } catch (const DBException& ex) { + uassertStatusOK(ex.toStatus().withContext( + str::stream() << "Failed " << mode << " cluster server parameters from disk")); + } }; } // namespace mongo diff --git a/src/mongo/idl/cluster_server_parameter_initializer_test.cpp b/src/mongo/idl/cluster_server_parameter_initializer_test.cpp index a2211ed0295..e8a62b6a1c1 100644 --- a/src/mongo/idl/cluster_server_parameter_initializer_test.cpp +++ b/src/mongo/idl/cluster_server_parameter_initializer_test.cpp @@ -38,7 +38,6 @@ #include "mongo/db/repl/replication_coordinator_mock.h" #include "mongo/db/repl/storage_interface_mock.h" #include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/idl/cluster_parameter_synchronization_helpers.h" #include "mongo/idl/cluster_server_parameter_gen.h" #include "mongo/idl/cluster_server_parameter_initializer.h" #include "mongo/idl/cluster_server_parameter_test_gen.h" @@ -69,7 +68,7 @@ public: // Delete all cluster server parameter documents written and refresh in-memory state. remove(); auto opCtx = cc().makeOperationContext(); - cluster_parameters::resynchronizeAllParametersFromDisk(opCtx.get()); + _initializer.resynchronizeAllParametersFromDisk(opCtx.get()); } /** * Simulates the call to the ClusterServerParameterInitializer at the end of initial sync, when diff --git a/src/mongo/idl/cluster_server_parameter_op_observer.cpp b/src/mongo/idl/cluster_server_parameter_op_observer.cpp index ea9553d46fb..b8787dcfa12 100644 --- a/src/mongo/idl/cluster_server_parameter_op_observer.cpp +++ b/src/mongo/idl/cluster_server_parameter_op_observer.cpp @@ -34,7 +34,7 @@ #include <memory> #include "mongo/db/dbdirectclient.h" -#include "mongo/idl/cluster_parameter_synchronization_helpers.h" +#include "mongo/idl/cluster_server_parameter_initializer.h" #include "mongo/logv2/log.h" namespace mongo { @@ -67,9 +67,7 @@ void ClusterServerParameterOpObserver::onInserts(OperationContext* opCtx, } for (auto it = first; it != last; ++it) { - opCtx->recoveryUnit()->onCommit([doc = it->doc](boost::optional<Timestamp>) { - cluster_parameters::updateParameter(doc, kOplog); - }); + ClusterServerParameterInitializer::get(opCtx)->updateParameter(it->doc, kOplog); } } @@ -80,9 +78,7 @@ void ClusterServerParameterOpObserver::onUpdate(OperationContext* opCtx, return; } - opCtx->recoveryUnit()->onCommit([updatedDoc](boost::optional<Timestamp>) { - cluster_parameters::updateParameter(updatedDoc, kOplog); - }); + ClusterServerParameterInitializer::get(opCtx)->updateParameter(updatedDoc, kOplog); } void ClusterServerParameterOpObserver::aboutToDelete(OperationContext* opCtx, @@ -119,8 +115,7 @@ void ClusterServerParameterOpObserver::onDelete(OperationContext* opCtx, const OplogDeleteEntryArgs& args) { const auto& docName = aboutToDeleteDoc(opCtx); if (!docName.empty()) { - opCtx->recoveryUnit()->onCommit( - [docName](boost::optional<Timestamp>) { cluster_parameters::clearParameter(docName); }); + ClusterServerParameterInitializer::get(opCtx)->clearParameter(docName); } } @@ -128,8 +123,7 @@ void ClusterServerParameterOpObserver::onDropDatabase(OperationContext* opCtx, const std::string& dbName) { if (dbName == NamespaceString::kConfigDb) { // Entire config DB deleted, reset to default state. - opCtx->recoveryUnit()->onCommit( - [](boost::optional<Timestamp>) { cluster_parameters::clearAllParameters(); }); + ClusterServerParameterInitializer::get(opCtx)->clearAllParameters(); } } @@ -141,21 +135,58 @@ repl::OpTime ClusterServerParameterOpObserver::onDropCollection( CollectionDropType dropType) { if (isConfigNamespace(collectionName)) { // Entire collection deleted, reset to default state. - opCtx->recoveryUnit()->onCommit( - [](boost::optional<Timestamp>) { cluster_parameters::clearAllParameters(); }); + ClusterServerParameterInitializer::get(opCtx)->clearAllParameters(); } return {}; } +void ClusterServerParameterOpObserver::postRenameCollection( + OperationContext* opCtx, + const NamespaceString& fromCollection, + const NamespaceString& toCollection, + const UUID& uuid, + const boost::optional<UUID>& dropTargetUUID, + bool stayTemp) { + if (isConfigNamespace(fromCollection)) { + // Same as collection dropped from a config point of view. + ClusterServerParameterInitializer::get(opCtx)->clearAllParameters(); + } + + if (isConfigNamespace(toCollection)) { + // Potentially many documents now set, perform full scan. + if (dropTargetUUID) { + // Possibly lost configurations in overwrite. + ClusterServerParameterInitializer::get(opCtx)->resynchronizeAllParametersFromDisk( + opCtx); + } else { + // Collection did not exist prior to rename. + ClusterServerParameterInitializer::get(opCtx)->initializeAllParametersFromDisk(opCtx); + } + } +} + +void ClusterServerParameterOpObserver::onImportCollection(OperationContext* opCtx, + const UUID& importUUID, + const NamespaceString& nss, + long long numRecords, + long long dataSize, + const BSONObj& catalogEntry, + const BSONObj& storageMetadata, + bool isDryRun) { + if (!isDryRun && (numRecords > 0) && isConfigNamespace(nss)) { + // Something was imported, do a full collection scan to sync up. + // No need to apply rollback rules since nothing will have been deleted. + ClusterServerParameterInitializer::get(opCtx)->initializeAllParametersFromDisk(opCtx); + } +} + void ClusterServerParameterOpObserver::_onReplicationRollback(OperationContext* opCtx, const RollbackObserverInfo& rbInfo) { if (rbInfo.rollbackNamespaces.count(NamespaceString::kClusterParametersNamespace)) { // Some kind of rollback happend in the settings collection. // Just reload from disk to be safe. - // We can call resynchronize directly because onReplicationRollback is guaranteed to be - // called from a state with no active WUOW and no database locks. - cluster_parameters::resynchronizeAllParametersFromDisk(opCtx); + ClusterServerParameterInitializer::get(opCtx)->resynchronizeAllParametersFromDisk(opCtx); } } diff --git a/src/mongo/idl/cluster_server_parameter_op_observer.h b/src/mongo/idl/cluster_server_parameter_op_observer.h index 86bec6b61da..2ef05729e39 100644 --- a/src/mongo/idl/cluster_server_parameter_op_observer.h +++ b/src/mongo/idl/cluster_server_parameter_op_observer.h @@ -72,18 +72,12 @@ public: const UUID& uuid, std::uint64_t numRecords, CollectionDropType dropType) final; - -private: - void _onReplicationRollback(OperationContext* opCtx, const RollbackObserverInfo& rbInfo) final; - -public: - // Remainder of operations are ignorable. void postRenameCollection(OperationContext* opCtx, const NamespaceString& fromCollection, const NamespaceString& toCollection, const UUID& uuid, const boost::optional<UUID>& dropTargetUUID, - bool stayTemp) final {} + bool stayTemp) final; void onImportCollection(OperationContext* opCtx, const UUID& importUUID, const NamespaceString& nss, @@ -91,7 +85,12 @@ public: long long dataSize, const BSONObj& catalogEntry, const BSONObj& storageMetadata, - bool isDryRun) final {} + bool isDryRun) final; + + void _onReplicationRollback(OperationContext* opCtx, const RollbackObserverInfo& rbInfo) final; + +public: + // Remainder of operations are ignorable. void onCreateIndex(OperationContext* opCtx, const NamespaceString& nss, @@ -213,10 +212,6 @@ public: size_t numberOfPrePostImagesToWrite, Date_t wallClockTime) final {} - void onTransactionPrepareNonPrimary(OperationContext* opCtx, - const std::vector<repl::OplogEntry>& statements, - const repl::OpTime& prepareOpTime) final {} - void onTransactionAbort(OperationContext* opCtx, boost::optional<OplogSlot> abortOplogEntryOpTime) final {} diff --git a/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp b/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp index 7553bfc191a..2ba82076bf2 100644 --- a/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp +++ b/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp @@ -31,9 +31,9 @@ #include "mongo/platform/basic.h" -#include "mongo/db/catalog_raii.h" -#include "mongo/idl/cluster_server_parameter_op_observer.h" #include "mongo/idl/cluster_server_parameter_test_util.h" + +#include "mongo/idl/cluster_server_parameter_op_observer.h" #include "mongo/logv2/log.h" namespace mongo { @@ -47,58 +47,60 @@ const std::vector<NamespaceString> kIgnoredNamespaces = { class ClusterServerParameterOpObserverTest : public ClusterServerParameterTestBase { public: - void doInserts(const NamespaceString& nss, - std::initializer_list<BSONObj> docs, - bool commit = true) { + void doInserts(const NamespaceString& nss, std::initializer_list<BSONObj> docs) { std::vector<InsertStatement> stmts; std::transform(docs.begin(), docs.end(), std::back_inserter(stmts), [](auto doc) { return InsertStatement(doc); }); auto opCtx = cc().makeOperationContext(); - WriteUnitOfWork wuow(opCtx.get()); - - AutoGetCollection autoColl(opCtx.get(), nss, MODE_IX); observer.onInserts( opCtx.get(), nss, UUID::gen(), stmts.cbegin(), stmts.cend(), false /* fromMigrate */); - if (commit) - wuow.commit(); } - void doUpdate(const NamespaceString& nss, BSONObj updatedDoc, bool commit = true) { + void doUpdate(const NamespaceString& nss, BSONObj updatedDoc) { // Actual UUID doesn't matter, just use any... CollectionUpdateArgs updateArgs; updateArgs.update = BSON("$set" << updatedDoc); updateArgs.updatedDoc = updatedDoc; OplogUpdateEntryArgs entryArgs(&updateArgs, nss, UUID::gen()); auto opCtx = cc().makeOperationContext(); - WriteUnitOfWork wuow(opCtx.get()); - AutoGetCollection autoColl(opCtx.get(), nss, MODE_IX); observer.onUpdate(opCtx.get(), entryArgs); - if (commit) - wuow.commit(); } - void doDelete(const NamespaceString& nss, - BSONObj deletedDoc, - bool includeDeletedDoc = true, - bool commit = true) { + void doDelete(const NamespaceString& nss, BSONObj deletedDoc, bool includeDeletedDoc = true) { auto opCtx = cc().makeOperationContext(); - WriteUnitOfWork wuow(opCtx.get()); - AutoGetCollection autoColl(opCtx.get(), nss, MODE_IX); - observer.aboutToDelete(opCtx.get(), nss, UUID::gen(), deletedDoc); + auto uuid = UUID::gen(); + observer.aboutToDelete(opCtx.get(), nss, uuid, deletedDoc); OplogDeleteEntryArgs args; args.deletedDoc = includeDeletedDoc ? &deletedDoc : nullptr; - observer.onDelete(opCtx.get(), nss, UUID::gen(), 1 /* StmtId */, args); - if (commit) - wuow.commit(); + observer.onDelete(opCtx.get(), nss, uuid, 1 /* StmtId */, args); } - void doDropDatabase(const std::string& dbname, bool commit = true) { + void doDropDatabase(StringData dbname) { auto opCtx = cc().makeOperationContext(); - WriteUnitOfWork wuow(opCtx.get()); - observer.onDropDatabase(opCtx.get(), dbname); - if (commit) - wuow.commit(); + observer.onDropDatabase(opCtx.get(), dbname.toString()); + } + + void doRenameCollection(const NamespaceString& fromColl, const NamespaceString& toColl) { + auto opCtx = cc().makeOperationContext(); + observer.postRenameCollection(opCtx.get(), + fromColl, + toColl, + UUID::gen(), + boost::none /* targetUUID */, + false /* stayTemp */); + } + + void doImportCollection(const NamespaceString& nss) { + auto opCtx = cc().makeOperationContext(); + observer.onImportCollection(opCtx.get(), + UUID::gen(), + nss, + 10 /* num records */, + 1 << 20 /* data size */, + BSONObj() /* catalogEntry */, + BSONObj() /* storageMetadata */, + false /* isDryRun */); } void doReplicationRollback(const std::vector<NamespaceString>& namespaces) { @@ -163,28 +165,6 @@ public: assertIgnored(NamespaceString::kClusterParametersNamespace, fn); } - void assertParameterState(int line, - int intVal, - StringData strVal, - boost::optional<LogicalTime> cpt = boost::none) { - auto* sp = ServerParameterSet::getClusterParameterSet() - ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide, - ClusterServerParameterTest>>(kCSPTest); - ; - try { - if (cpt) { - ASSERT_EQ(sp->getClusterParameterTime(), *cpt); - } - - ClusterServerParameterTest cspTest = sp->getValue(); - ASSERT_EQ(cspTest.getIntValue(), intVal); - ASSERT_EQ(cspTest.getStrValue(), strVal); - } catch (...) { - LOGV2_ERROR(6887700, "ASSERT_PARAMETER_STATE failed", "line"_attr = line); - throw; - } - } - protected: ClusterServerParameterOpObserver observer; }; @@ -328,12 +308,12 @@ TEST_F(ClusterServerParameterOpObserverTest, onDropDatabase) { assertIgnoredOtherNamespaces([this](const auto& nss) { const auto dbname = nss.db(); if (dbname != kConfigDB) { - doDropDatabase(dbname.toString()); + doDropDatabase(dbname); } }); // Actually drop the config DB. - doDropDatabase(kConfigDB.toString()); + doDropDatabase(kConfigDB); auto* sp = ServerParameterSet::getClusterParameterSet() ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide, @@ -345,12 +325,63 @@ TEST_F(ClusterServerParameterOpObserverTest, onDropDatabase) { ASSERT_EQ(cspTest.getStrValue(), kDefaultStrValue); } +TEST_F(ClusterServerParameterOpObserverTest, onRenameCollection) { + initializeState(); + + const NamespaceString kTestFoo("test", "foo"); + // Rename ignorable collections. + assertIgnoredOtherNamespaces([&](const auto& nss) { doRenameCollection(nss, kTestFoo); }); + assertIgnoredOtherNamespaces([&](const auto& nss) { doRenameCollection(kTestFoo, nss); }); + + auto* sp = ServerParameterSet::getClusterParameterSet() + ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide, + ClusterServerParameterTest>>(kCSPTest); + ASSERT(sp != nullptr); + + // These renames "work" despite not mutating durable state + // since the rename away doesn't require a rescan. + + // Rename away (and reset to default) + doRenameCollection(NamespaceString::kClusterParametersNamespace, kTestFoo); + ClusterServerParameterTest cspTest = sp->getValue(); + ASSERT_EQ(cspTest.getIntValue(), kDefaultIntValue); + ASSERT_EQ(cspTest.getStrValue(), kDefaultStrValue); + + // Rename in (and restore to initialized state) + doRenameCollection(kTestFoo, NamespaceString::kClusterParametersNamespace); + cspTest = sp->getValue(); + ASSERT_EQ(cspTest.getIntValue(), kInitialIntValue); + ASSERT_EQ(cspTest.getStrValue(), kInitialStrValue); +} + +TEST_F(ClusterServerParameterOpObserverTest, onImportCollection) { + initializeState(); + + const NamespaceString kTestFoo("test", "foo"); + // Import ignorable collections. + assertIgnoredOtherNamespaces([&](const auto& nss) { doImportCollection(nss); }); + + auto* sp = ServerParameterSet::getClusterParameterSet() + ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide, + ClusterServerParameterTest>>(kCSPTest); + ASSERT(sp != nullptr); + + // Import the collection (rescan). + auto doc = + makeClusterParametersDoc(LogicalTime(Timestamp(time(nullptr))), 333, "onImportCollection"); + upsert(doc); + doImportCollection(NamespaceString::kClusterParametersNamespace); + ClusterServerParameterTest cspTest = sp->getValue(); + ASSERT_EQ(cspTest.getIntValue(), 333); + ASSERT_EQ(cspTest.getStrValue(), "onImportCollection"); +} + TEST_F(ClusterServerParameterOpObserverTest, onReplicationRollback) { initializeState(); const NamespaceString kTestFoo("test", "foo"); // Import ignorable collections. - assertIgnoredOtherNamespaces([&](const auto& nss) { doReplicationRollback({nss}); }); + assertIgnoredOtherNamespaces([&](const auto& nss) { doImportCollection(nss); }); auto* sp = ServerParameterSet::getClusterParameterSet() ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide, @@ -381,37 +412,5 @@ TEST_F(ClusterServerParameterOpObserverTest, onReplicationRollback) { ASSERT_EQ(cspTest.getStrValue(), kDefaultStrValue); } -#define ASSERT_PARAMETER_STATE(...) assertParameterState(__LINE__, __VA_ARGS__) - -TEST_F(ClusterServerParameterOpObserverTest, abortsAfterObservation) { - - const auto initialDoc = initializeState(); - - doInserts(NamespaceString::kClusterParametersNamespace, - {makeClusterParametersDoc(LogicalTime(Timestamp(12345678)), 123, "abc")}, - false /* commit */); - - ASSERT_PARAMETER_STATE(kInitialIntValue, kInitialStrValue); - - doUpdate(NamespaceString::kClusterParametersNamespace, - {makeClusterParametersDoc(LogicalTime(Timestamp(87654321)), 321, "cba")}, - false /* commit */); - - ASSERT_PARAMETER_STATE(kInitialIntValue, kInitialStrValue); - - doDelete(NamespaceString::kClusterParametersNamespace, - initialDoc, - true /* includeDeletedDoc */, - false /* commit */); - - ASSERT_PARAMETER_STATE(kInitialIntValue, kInitialStrValue); - - doDropDatabase(kConfigDB.toString(), false /* commit */); - - ASSERT_PARAMETER_STATE(kInitialIntValue, kInitialStrValue); -} - -#undef ASSERT_PARAMETER_STATE - } // namespace } // namespace mongo diff --git a/src/mongo/idl/server_parameter_test_util.h b/src/mongo/idl/server_parameter_test_util.h index f7e2ae31834..566489dd1a9 100644 --- a/src/mongo/idl/server_parameter_test_util.h +++ b/src/mongo/idl/server_parameter_test_util.h @@ -36,59 +36,38 @@ namespace mongo { /** - * Test-only class that sets a server parameter to the specified value and allows - * resetting after the test completes. + * Test-only RAII type that allows to set a server parameter value during the execution of a + * unit test, or part of a unit test, and resets it to the original value on destruction. */ -class ServerParameterControllerForTest { +class RAIIServerParameterControllerForTest { public: /** * Constructor setting the server parameter to the specified value. */ template <typename T> - ServerParameterControllerForTest(const std::string& name, T value) + RAIIServerParameterControllerForTest(const std::string& name, T value) : _serverParam(ServerParameterSet::getNodeParameterSet()->get(name)) { - // Save the old value. + // Save the old value BSONObjBuilder bob; _serverParam->appendSupportingRoundtrip(nullptr, bob, name); _oldValue = bob.obj(); - // Set server param to the new value. + // Set to the new value uassertStatusOK(_serverParam->set(BSON(name << value).firstElement())); } - void reset() { - // Reset to the old value. - auto elem = _oldValue.firstElement(); - uassertStatusOK(_serverParam->set(elem)); - } - -private: - ServerParameter* _serverParam; - BSONObj _oldValue; -}; - -/** - * Test-only RAII type that wraps ServerParameterControllerForTest. Upon destruction, the server - * parameter will be set to its original value. - */ -class RAIIServerParameterControllerForTest { -public: - /** - * Constructor setting the server parameter to the specified value. - */ - template <typename T> - RAIIServerParameterControllerForTest(const std::string& name, T value) - : _serverParamController(ServerParameterControllerForTest(name, value)) {} - /** * Destructor resetting the server parameter to the original value. */ ~RAIIServerParameterControllerForTest() { - _serverParamController.reset(); + // Reset to the old value + auto elem = _oldValue.firstElement(); + uassertStatusOK(_serverParam->set(elem)); } private: - ServerParameterControllerForTest _serverParamController; + ServerParameter* _serverParam; + BSONObj _oldValue; }; } // namespace mongo |
