diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2016-11-08 12:06:12 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2016-11-11 14:21:42 -0500 |
commit | 07562c2fb080a3856fe06a2ff412d06060a6abb7 (patch) | |
tree | 9b9fd9c65973abdec2e331f25c0b229bc0a96a69 /src/mongo/db | |
parent | cbb4e60d3e2756f5861372121228a6fe82a3cedb (diff) | |
download | mongo-07562c2fb080a3856fe06a2ff412d06060a6abb7.tar.gz |
SERVER-26955 Ensure setFeatureCompatibilityVersion commands support maxTimeMS
Diffstat (limited to 'src/mongo/db')
8 files changed, 189 insertions, 107 deletions
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index 868484de229..cc535fc4fe5 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -31,6 +31,7 @@ env.Library( "connection_status.cpp", "copydb_common.cpp", "fail_point_cmd.cpp", + "feature_compatibility_version_command_parser.cpp", "find_and_modify_common.cpp", "hashcmd.cpp", "isself.cpp", diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp index dcf4ae4c652..2e38906b685 100644 --- a/src/mongo/db/commands/feature_compatibility_version.cpp +++ b/src/mongo/db/commands/feature_compatibility_version.cpp @@ -34,6 +34,7 @@ #include "mongo/base/status.h" #include "mongo/db/catalog/collection_options.h" +#include "mongo/db/commands/feature_compatibility_version_command_parser.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" #include "mongo/db/db_raii.h" @@ -58,8 +59,6 @@ constexpr StringData FeatureCompatibilityVersion::kCollection; constexpr StringData FeatureCompatibilityVersion::kCommandName; constexpr StringData FeatureCompatibilityVersion::kParameterName; constexpr StringData FeatureCompatibilityVersion::kVersionField; -constexpr StringData FeatureCompatibilityVersion::kVersion34; -constexpr StringData FeatureCompatibilityVersion::kVersion32; namespace { const BSONObj k32IncompatibleIndexSpec = @@ -104,9 +103,9 @@ StringData getFeatureCompatibilityVersionString( ServerGlobalParams::FeatureCompatibility::Version version) { switch (version) { case ServerGlobalParams::FeatureCompatibility::Version::k34: - return FeatureCompatibilityVersion::kVersion34; + return FeatureCompatibilityVersionCommandParser::kVersion34; case ServerGlobalParams::FeatureCompatibility::Version::k32: - return FeatureCompatibilityVersion::kVersion32; + return FeatureCompatibilityVersionCommandParser::kVersion32; default: MONGO_UNREACHABLE; } @@ -139,9 +138,9 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili << featureCompatibilityVersionDoc << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); } - if (elem.String() == FeatureCompatibilityVersion::kVersion34) { + if (elem.String() == FeatureCompatibilityVersionCommandParser::kVersion34) { version = ServerGlobalParams::FeatureCompatibility::Version::k34; - } else if (elem.String() == FeatureCompatibilityVersion::kVersion32) { + } else if (elem.String() == FeatureCompatibilityVersionCommandParser::kVersion32) { version = ServerGlobalParams::FeatureCompatibility::Version::k32; } else { return Status( @@ -152,9 +151,9 @@ StatusWith<ServerGlobalParams::FeatureCompatibility::Version> FeatureCompatibili << ", found " << elem.String() << ", expected '" - << FeatureCompatibilityVersion::kVersion34 + << FeatureCompatibilityVersionCommandParser::kVersion34 << "' or '" - << FeatureCompatibilityVersion::kVersion32 + << FeatureCompatibilityVersionCommandParser::kVersion32 << "'. Contents of " << FeatureCompatibilityVersion::kParameterName << " document in " @@ -197,13 +196,13 @@ void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) uassert(40284, "featureCompatibilityVersion must be '3.4' or '3.2'. See " "http://dochub.mongodb.org/core/3.4-feature-compatibility.", - version == FeatureCompatibilityVersion::kVersion34 || - version == FeatureCompatibilityVersion::kVersion32); + version == FeatureCompatibilityVersionCommandParser::kVersion34 || + version == FeatureCompatibilityVersionCommandParser::kVersion32); DBDirectClient client(txn); NamespaceString nss(FeatureCompatibilityVersion::kCollection); - if (version == FeatureCompatibilityVersion::kVersion34) { + if (version == FeatureCompatibilityVersionCommandParser::kVersion34) { // We build a v=2 index on the "admin.system.version" collection as part of setting the // featureCompatibilityVersion to 3.4. This is a new index version that isn't supported by // versions of MongoDB earlier than 3.4 that will cause 3.2 secondaries to crash when it is @@ -248,7 +247,7 @@ void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) // We then update the value of the featureCompatibilityVersion server parameter. serverGlobalParams.featureCompatibility.version.store( ServerGlobalParams::FeatureCompatibility::Version::k34); - } else if (version == FeatureCompatibilityVersion::kVersion32) { + } else if (version == FeatureCompatibilityVersionCommandParser::kVersion32) { // We update the featureCompatibilityVersion document stored in the "admin.system.version" // collection. We do this before dropping the v=2 index in order to maintain the invariant // that if the featureCompatibilityVersion is 3.4, then 'k32IncompatibleIndexSpec' index @@ -321,7 +320,7 @@ void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* txn, nss, BSON("_id" << FeatureCompatibilityVersion::kParameterName << FeatureCompatibilityVersion::kVersionField - << FeatureCompatibilityVersion::kVersion34))); + << FeatureCompatibilityVersionCommandParser::kVersion34))); // We then update the value of the featureCompatibilityVersion server parameter. serverGlobalParams.featureCompatibility.version.store( @@ -347,7 +346,8 @@ void FeatureCompatibilityVersion::onDelete(const BSONObj& doc) { idElement.String() != FeatureCompatibilityVersion::kParameterName) { return; } - log() << "setting featureCompatibilityVersion to " << FeatureCompatibilityVersion::kVersion32; + log() << "setting featureCompatibilityVersion to " + << FeatureCompatibilityVersionCommandParser::kVersion32; serverGlobalParams.featureCompatibility.version.store( ServerGlobalParams::FeatureCompatibility::Version::k32); } diff --git a/src/mongo/db/commands/feature_compatibility_version.h b/src/mongo/db/commands/feature_compatibility_version.h index 2560d08953e..46fa8390bb3 100644 --- a/src/mongo/db/commands/feature_compatibility_version.h +++ b/src/mongo/db/commands/feature_compatibility_version.h @@ -52,8 +52,6 @@ public: static constexpr StringData kCommandName = "setFeatureCompatibilityVersion"_sd; static constexpr StringData kParameterName = "featureCompatibilityVersion"_sd; static constexpr StringData kVersionField = "version"_sd; - static constexpr StringData kVersion34 = "3.4"_sd; - static constexpr StringData kVersion32 = "3.2"_sd; /** * Parses the featureCompatibilityVersion document from admin.system.version, and returns the diff --git a/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp b/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp new file mode 100644 index 00000000000..e8536e88db2 --- /dev/null +++ b/src/mongo/db/commands/feature_compatibility_version_command_parser.cpp @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2016 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/platform/basic.h" + +#include "mongo/db/commands/feature_compatibility_version_command_parser.h" + +#include "mongo/base/status_with.h" +#include "mongo/bson/bsonobj.h" +#include "mongo/db/query/query_request.h" +#include "mongo/util/version.h" + +namespace mongo { + +constexpr StringData FeatureCompatibilityVersionCommandParser::kVersion34; +constexpr StringData FeatureCompatibilityVersionCommandParser::kVersion32; + +StatusWith<std::string> FeatureCompatibilityVersionCommandParser::extractVersionFromCommand( + StringData commandName, const BSONObj& cmdObj) { + if (cmdObj.firstElementFieldName() != commandName) { + return {ErrorCodes::InternalError, + str::stream() << "Expected to find a " << commandName << " command, but found " + << cmdObj}; + } + + const auto versionElem = cmdObj.firstElement(); + + if (versionElem.type() != BSONType::String) { + return {ErrorCodes::TypeMismatch, + str::stream() << "Command argument must be of type " + "String, but was of type " + << typeName(versionElem.type()) + << " in: " + << cmdObj + << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."}; + } + + // Ensure that the command does not contain any unrecognized parameters + for (const auto& cmdElem : cmdObj) { + if (cmdElem.fieldNameStringData() == commandName || + cmdElem.fieldNameStringData() == QueryRequest::cmdOptionMaxTimeMS) { + continue; + } + + uasserted( + ErrorCodes::InvalidOptions, + str::stream() << "Unrecognized field found " << cmdElem.fieldNameStringData() << " in " + << cmdObj + << ". See http ://dochub.mongodb.org/core/3.4-feature-compatibility."); + } + + const std::string version = versionElem.String(); + + if (version != FeatureCompatibilityVersionCommandParser::kVersion34 && + version != FeatureCompatibilityVersionCommandParser::kVersion32) { + return {ErrorCodes::BadValue, + str::stream() << "Invalid command argument. Expected '" + << FeatureCompatibilityVersionCommandParser::kVersion34 + << "' or '" + << FeatureCompatibilityVersionCommandParser::kVersion32 + << "', found " + << version + << " in: " + << cmdObj + << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."}; + } + + return version; +} + +} // namespace mongo diff --git a/src/mongo/db/commands/feature_compatibility_version_command_parser.h b/src/mongo/db/commands/feature_compatibility_version_command_parser.h new file mode 100644 index 00000000000..4e17aa94cdc --- /dev/null +++ b/src/mongo/db/commands/feature_compatibility_version_command_parser.h @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2016 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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 <string> + +#include "mongo/base/string_data.h" + +namespace mongo { + +class BSONObj; +template <typename T> +class StatusWith; + +class FeatureCompatibilityVersionCommandParser { +public: + /** + * Known server release versions. + */ + static constexpr StringData kVersion34 = "3.4"_sd; + static constexpr StringData kVersion32 = "3.2"_sd; + + /** + * Interprets the specified BSON as a command and extracts the desired compatibility version + * from it. + */ + static StatusWith<std::string> extractVersionFromCommand(StringData commandName, + const BSONObj& cmdObj); +}; + +} // namespace mongo diff --git a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp index adc00bd7ae5..4d6c7f9867d 100644 --- a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp +++ b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp @@ -31,6 +31,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/commands/feature_compatibility_version.h" +#include "mongo/db/commands/feature_compatibility_version_command_parser.h" namespace mongo { @@ -86,51 +87,14 @@ public: int options, std::string& errmsg, BSONObjBuilder& result) { + const auto version = uassertStatusOK( + FeatureCompatibilityVersionCommandParser::extractVersionFromCommand(getName(), cmdObj)); - // Validate command. - std::string version; - for (auto&& elem : cmdObj) { - if (elem.fieldNameStringData() == FeatureCompatibilityVersion::kCommandName) { - uassert(ErrorCodes::TypeMismatch, - str::stream() - << FeatureCompatibilityVersion::kCommandName - << " must be of type String, but was of type " - << typeName(elem.type()) - << " in: " - << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility.", - elem.type() == BSONType::String); - version = elem.String(); - } else { - uasserted(ErrorCodes::FailedToParse, - str::stream() - << "unrecognized field '" - << elem.fieldName() - << "' in: " - << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - } - - uassert(ErrorCodes::BadValue, - str::stream() << "invalid value for " << FeatureCompatibilityVersion::kCommandName - << ", expected '" - << FeatureCompatibilityVersion::kVersion34 - << "' or '" - << FeatureCompatibilityVersion::kVersion32 - << "', found " - << version - << " in: " - << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility.", - version == FeatureCompatibilityVersion::kVersion34 || - version == FeatureCompatibilityVersion::kVersion32); - - // Set featureCompatibilityVersion. FeatureCompatibilityVersion::set(txn, version); return true; } + } setFeatureCompatibilityVersionCommand; } // namespace diff --git a/src/mongo/db/s/config/configsvr_control_balancer_command.cpp b/src/mongo/db/s/config/configsvr_control_balancer_command.cpp index 7c269919384..88deff30a9e 100644 --- a/src/mongo/db/s/config/configsvr_control_balancer_command.cpp +++ b/src/mongo/db/s/config/configsvr_control_balancer_command.cpp @@ -78,16 +78,14 @@ public: int options, std::string& errmsg, BSONObjBuilder& result) final { - if (cmdObj.firstElementFieldName() != getName()) { - uasserted(ErrorCodes::InternalError, - str::stream() << "Expected to find a " << getName() << " command, but found " - << cmdObj); - } - - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - str::stream() << getName() << " can only be run on config servers"); - } + uassert(ErrorCodes::InternalError, + str::stream() << "Expected to find a " << getName() << " command, but found " + << cmdObj, + cmdObj.firstElementFieldName() == getName()); + + uassert(ErrorCodes::IllegalOperation, + str::stream() << getName() << " can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); _run(txn, &result); diff --git a/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp b/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp index d42e9313c54..694cec5f96c 100644 --- a/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp +++ b/src/mongo/db/s/config/configsvr_set_feature_compatibility_version_command.cpp @@ -32,6 +32,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/commands/feature_compatibility_version.h" +#include "mongo/db/commands/feature_compatibility_version_command_parser.h" #include "mongo/s/catalog/sharding_catalog_manager.h" #include "mongo/s/grid.h" @@ -86,58 +87,25 @@ public: int options, std::string& errmsg, BSONObjBuilder& result) override { + const auto version = uassertStatusOK( + FeatureCompatibilityVersionCommandParser::extractVersionFromCommand(getName(), cmdObj)); + uassert(ErrorCodes::IllegalOperation, - "_configsvrSetFeatureCompatibilityVersion can only be run on config servers. See " - "http://dochub.mongodb.org/core/3.4-feature-compatibility.", + str::stream() << getName() + << " can only be run on config servers. See " + "http://dochub.mongodb.org/core/3.4-feature-compatibility.", serverGlobalParams.clusterRole == ClusterRole::ConfigServer); - // Validate command. - std::string version; - for (auto&& elem : cmdObj) { - if (elem.fieldNameStringData() == "_configsvrSetFeatureCompatibilityVersion") { - uassert(ErrorCodes::TypeMismatch, - str::stream() - << "_configsvrSetFeatureCompatibilityVersion must be of type " - "String, but was of type " - << typeName(elem.type()) - << " in: " - << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility.", - elem.type() == BSONType::String); - version = elem.String(); - } else { - uasserted(ErrorCodes::FailedToParse, - str::stream() - << "unrecognized field '" - << elem.fieldName() - << "' in: " - << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility."); - } - } - - uassert(ErrorCodes::BadValue, - str::stream() - << "invalid value for _configsvrSetFeatureCompatibilityVersion, expected '" - << FeatureCompatibilityVersion::kVersion34 - << "' or '" - << FeatureCompatibilityVersion::kVersion32 - << "', found " - << version - << " in: " - << cmdObj - << ". See http://dochub.mongodb.org/core/3.4-feature-compatibility.", - version == FeatureCompatibilityVersion::kVersion34 || - version == FeatureCompatibilityVersion::kVersion32); - // Forward to all shards. uassertStatusOK( Grid::get(txn)->catalogManager()->setFeatureCompatibilityVersionOnShards(txn, version)); // On success, set featureCompatibilityVersion on self. FeatureCompatibilityVersion::set(txn, version); + return true; } + } configsvrSetFeatureCompatibilityVersionCmd; } // namespace |