summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Graetzer <simon.gratzer@mongodb.com>2021-06-15 10:39:32 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-15 11:25:45 +0000
commit335f39070b2dbb16f25aebea96d365ecebcb5a10 (patch)
tree1f0e1454f1d820d80bca524350c475d66f48c303
parentd7ea9eaf3cf9195f6f9e102fca4cb9967279d9c8 (diff)
downloadmongo-335f39070b2dbb16f25aebea96d365ecebcb5a10.tar.gz
SERVER-56840 IDLify _configsvrCommitChunkMerge command
-rw-r--r--jstests/auth/lib/commands_lib.js4
-rw-r--r--src/mongo/db/s/config/configsvr_merge_chunk_command.cpp93
-rw-r--r--src/mongo/db/s/config/configsvr_merge_chunks_command.cpp85
-rw-r--r--src/mongo/db/s/merge_chunks_command.cpp39
-rw-r--r--src/mongo/s/SConscript3
-rw-r--r--src/mongo/s/chunk_version.h14
-rw-r--r--src/mongo/s/chunk_version.idl2
-rw-r--r--src/mongo/s/request_types/merge_chunk_request.idl130
-rw-r--r--src/mongo/s/request_types/merge_chunk_request_test.cpp255
-rw-r--r--src/mongo/s/request_types/merge_chunk_request_type.cpp154
-rw-r--r--src/mongo/s/request_types/merge_chunk_request_type.h115
-rw-r--r--src/mongo/s/request_types/merge_chunk_request_valid.h44
-rw-r--r--src/mongo/s/request_types/merge_chunks_request_test.cpp201
-rw-r--r--src/mongo/s/request_types/merge_chunks_request_type.cpp147
-rw-r--r--src/mongo/s/request_types/merge_chunks_request_type.h106
15 files changed, 593 insertions, 799 deletions
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js
index 4618bb9320d..643cfafe03b 100644
--- a/jstests/auth/lib/commands_lib.js
+++ b/jstests/auth/lib/commands_lib.js
@@ -2934,7 +2934,7 @@ var authCommandsLib = {
},
{
testname: "_configsvrCommitChunkMerge",
- command: {_configsvrCommitChunkMerge: "x.y"},
+ command: {_configsvrCommitChunkMerge: "x.y", shard: "shard0000", collEpoch: ObjectId(), chunkBoundaries:[{a:1}, {a:5}, {a:10}]},
skipSharded: true,
expectFail: true,
testcases: [
@@ -2962,7 +2962,7 @@ var authCommandsLib = {
},
{
testname: "_configsvrCommitChunksMerge",
- command: {_configsvrCommitChunksMerge: "x.y"},
+ command: {_configsvrCommitChunksMerge: "x.y", shard: "shard0000", collUUID: {uuid: UUID()}, chunkRange: {min:{a:1}, max:{a:10}}},
skipSharded: true,
expectFail: true,
testcases: [
diff --git a/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp b/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp
index 1d1b8b5f835..17e7fb7436c 100644
--- a/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp
+++ b/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/s/grid.h"
-#include "mongo/s/request_types/merge_chunk_request_type.h"
+#include "mongo/s/request_types/merge_chunk_request_gen.h"
#include "mongo/util/str.h"
namespace mongo {
@@ -62,13 +62,13 @@ namespace {
* writeConcern: <BSONObj>
* }
*/
-class ConfigSvrMergeChunkCommand : public BasicCommand {
+class ConfigSvrMergeChunkCommand : public TypedCommand<ConfigSvrMergeChunkCommand> {
public:
- ConfigSvrMergeChunkCommand() : BasicCommand("_configsvrCommitChunkMerge") {}
+ using Request = ConfigSvrMergeChunk;
std::string help() const override {
return "Internal command, which is sent by a shard to the sharding config server. Do "
- "not call directly. Receives, validates, and processes a MergeChunkRequest";
+ "not call directly. Receives, validates, and processes a ConfigSvrMergeChunk";
}
AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
@@ -79,49 +79,56 @@ public:
return true;
}
- bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const override {
- if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
- ResourcePattern::forClusterResource(), ActionType::internal)) {
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ class Invocation final : public InvocationBase {
+ public:
+ using InvocationBase::InvocationBase;
+
+ ConfigSvrMergeResponse typedRun(OperationContext* opCtx) {
+ uassert(ErrorCodes::IllegalOperation,
+ "_configsvrCommitChunkMerge can only be run on config servers",
+ serverGlobalParams.clusterRole == ClusterRole::ConfigServer);
+
+ uassert(ErrorCodes::InvalidNamespace,
+ "invalid namespace specified for request",
+ ns().isValid());
+ uassert(ErrorCodes::InvalidOptions,
+ "need to provide at least three chunk boundaries for the chunks to be merged",
+ request().getChunkBoundaries().size() >= 3);
+
+ // Set the operation context read concern level to local for reads into the config
+ // database.
+ repl::ReadConcernArgs::get(opCtx) =
+ repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern);
+
+ const BSONObj shardAndCollVers =
+ uassertStatusOK(ShardingCatalogManager::get(opCtx)->commitChunkMerge(
+ opCtx,
+ ns(),
+ request().getEpoch(),
+ request().getChunkBoundaries(),
+ request().getShard().toString(),
+ request().getValidAfter()));
+ return ConfigSvrMergeResponse{
+ ChunkVersion::fromBSONThrowing(shardAndCollVers["shardVersion"].Obj())};
}
- return Status::OK();
- }
- std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override {
- return CommandHelpers::parseNsFullyQualified(cmdObj);
- }
+ private:
+ NamespaceString ns() const override {
+ return request().getCommandParameter();
+ }
- bool run(OperationContext* opCtx,
- const std::string& dbName,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) override {
- uassert(ErrorCodes::IllegalOperation,
- "_configsvrCommitChunkMerge can only be run on config servers",
- serverGlobalParams.clusterRole == ClusterRole::ConfigServer);
-
- // Set the operation context read concern level to local for reads into the config database.
- repl::ReadConcernArgs::get(opCtx) =
- repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern);
-
- auto parsedRequest = uassertStatusOK(MergeChunkRequest::parseFromConfigCommand(cmdObj));
-
- const BSONObj shardAndCollVers = uassertStatusOK(
- ShardingCatalogManager::get(opCtx)->commitChunkMerge(opCtx,
- parsedRequest.getNamespace(),
- parsedRequest.getEpoch(),
- parsedRequest.getChunkBoundaries(),
- parsedRequest.getShardName(),
- parsedRequest.getValidAfter()));
- result.appendElements(shardAndCollVers);
+ bool supportsWriteConcern() const override {
+ return true;
+ }
- return true;
- }
+ void doCheckAuthorization(OperationContext* opCtx) const override {
+ if (!AuthorizationSession::get(opCtx->getClient())
+ ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::internal)) {
+ uasserted(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ }
+ };
} configsvrMergeChunkCmd;
diff --git a/src/mongo/db/s/config/configsvr_merge_chunks_command.cpp b/src/mongo/db/s/config/configsvr_merge_chunks_command.cpp
index 73e4c127749..c41a366fe4b 100644
--- a/src/mongo/db/s/config/configsvr_merge_chunks_command.cpp
+++ b/src/mongo/db/s/config/configsvr_merge_chunks_command.cpp
@@ -30,7 +30,7 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
-#include "mongo/s/request_types/merge_chunks_request_type.h"
+#include "mongo/s/request_types/merge_chunk_request_gen.h"
namespace mongo {
namespace {
@@ -48,13 +48,13 @@ namespace {
* writeConcern: <BSONObj>
* }
*/
-class ConfigSvrMergeChunksCommand : public BasicCommand {
+class ConfigSvrMergeChunksCommand : public TypedCommand<ConfigSvrMergeChunksCommand> {
public:
- ConfigSvrMergeChunksCommand() : BasicCommand("_configsvrCommitChunksMerge") {}
+ using Request = ConfigSvrMergeChunks;
std::string help() const override {
return "Internal command, which is sent by a shard to the sharding config server. Do "
- "not call directly. Receives, validates, and processes a MergeChunksRequest";
+ "not call directly. Receives, validates, and processes a ConfigSvrMergeChunks";
}
AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
@@ -65,50 +65,53 @@ public:
return true;
}
- bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
+ class Invocation final : public InvocationBase {
+ public:
+ using InvocationBase::InvocationBase;
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const override {
- if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
- ResourcePattern::forClusterResource(), ActionType::internal)) {
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
- }
- return Status::OK();
- }
+ ConfigSvrMergeResponse typedRun(OperationContext* opCtx) {
+ uassert(ErrorCodes::IllegalOperation,
+ "_configsvrCommitChunksMerge can only be run on config servers",
+ serverGlobalParams.clusterRole == ClusterRole::ConfigServer);
+ uassert(ErrorCodes::InvalidNamespace,
+ "invalid namespace specified for request",
+ ns().isValid());
- std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override {
- return CommandHelpers::parseNsFullyQualified(cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const std::string& dbName,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) override {
- uassert(ErrorCodes::IllegalOperation,
- "_configsvrCommitChunksMerge can only be run on config servers",
- serverGlobalParams.clusterRole == ClusterRole::ConfigServer);
+ // Set the operation context read concern level to local for reads into the config
+ // database.
+ repl::ReadConcernArgs::get(opCtx) =
+ repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern);
- // Set the operation context read concern level to local for reads into the config database.
- repl::ReadConcernArgs::get(opCtx) =
- repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern);
+ const BSONObj shardAndCollVers = uassertStatusOK(
+ ShardingCatalogManager::get(opCtx)->commitChunksMerge(opCtx,
+ ns(),
+ request().getCollectionUUID(),
+ request().getChunkRange(),
+ request().getShard(),
+ request().getValidAfter()));
+ return ConfigSvrMergeResponse{
+ ChunkVersion::fromBSONThrowing(shardAndCollVers["shardVersion"].Obj())};
+ }
- auto parsedRequest = uassertStatusOK(MergeChunksRequest::parseFromConfigCommand(cmdObj));
+ private:
+ NamespaceString ns() const override {
+ return request().getCommandParameter();
+ }
- const BSONObj shardAndCollVers = uassertStatusOK(
- ShardingCatalogManager::get(opCtx)->commitChunksMerge(opCtx,
- parsedRequest.getNamespace(),
- parsedRequest.getCollectionUUID(),
- parsedRequest.getChunkRange(),
- parsedRequest.getShardId(),
- parsedRequest.getValidAfter()));
- result.appendElements(shardAndCollVers);
+ bool supportsWriteConcern() const override {
+ return true;
+ }
- return true;
- }
+ void doCheckAuthorization(OperationContext* opCtx) const override {
+ if (!AuthorizationSession::get(opCtx->getClient())
+ ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::internal)) {
+ uasserted(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ }
+ };
} configsvrMergeChunksCmd;
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/s/merge_chunks_command.cpp b/src/mongo/db/s/merge_chunks_command.cpp
index f68afa19cac..2b3235113a2 100644
--- a/src/mongo/db/s/merge_chunks_command.cpp
+++ b/src/mongo/db/s/merge_chunks_command.cpp
@@ -48,8 +48,7 @@
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/grid.h"
-#include "mongo/s/request_types/merge_chunk_request_type.h"
-#include "mongo/s/request_types/merge_chunks_request_type.h"
+#include "mongo/s/request_types/merge_chunk_request_gen.h"
#include "mongo/util/str.h"
namespace mongo {
@@ -83,20 +82,17 @@ Shard::CommandResponse commitUsingChunkRange(OperationContext* opCtx,
const auto currentTime = VectorClock::get(opCtx)->getTime();
auto collUUID = metadata.getUUID();
invariant(collUUID);
- MergeChunksRequest request{nss,
- shardingState->shardId(),
- *collUUID,
- chunkRange,
- currentTime.clusterTime().asTimestamp()};
-
- auto configCmdObj =
- request.toConfigCommandBSON(ShardingCatalogClient::kMajorityWriteConcern.toBSON());
+
+ ConfigSvrMergeChunks request{nss, shardingState->shardId(), *collUUID, chunkRange};
+ request.setValidAfter(currentTime.clusterTime().asTimestamp());
+ request.setWriteConcern(ShardingCatalogClient::kMajorityWriteConcern.toBSON());
+
auto cmdResponse =
uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getConfigShard()->runCommand(
opCtx,
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
- "admin",
- configCmdObj,
+ NamespaceString::kAdminDb.toString(),
+ request.toBSON(BSONObj()),
Shard::RetryPolicy::kIdempotent));
return cmdResponse;
@@ -191,20 +187,19 @@ Shard::CommandResponse commitUsingChunksList(OperationContext* opCtx,
// Run _configsvrCommitChunkMerge.
//
const auto currentTime = VectorClock::get(opCtx)->getTime();
- MergeChunkRequest request{nss,
- shardingState->shardId().toString(),
- metadata.getShardVersion().epoch(),
- chunkBoundaries,
- currentTime.clusterTime().asTimestamp()};
-
- auto configCmdObj =
- request.toConfigCommandBSON(ShardingCatalogClient::kMajorityWriteConcern.toBSON());
+ ConfigSvrMergeChunk request{nss,
+ shardingState->shardId().toString(),
+ metadata.getShardVersion().epoch(),
+ chunkBoundaries};
+ request.setValidAfter(currentTime.clusterTime().asTimestamp());
+ request.setWriteConcern(ShardingCatalogClient::kMajorityWriteConcern.toBSON());
+
auto cmdResponse =
uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getConfigShard()->runCommand(
opCtx,
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
- "admin",
- configCmdObj,
+ NamespaceString::kAdminDb.toString(),
+ request.toBSON(BSONObj()),
Shard::RetryPolicy::kIdempotent));
return cmdResponse;
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index fa5dfd08e64..471839f6c4d 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -163,8 +163,7 @@ env.Library(
'request_types/flush_resharding_state_change.idl',
'request_types/flush_routing_table_cache_updates.idl',
'request_types/get_database_version.idl',
- 'request_types/merge_chunk_request_type.cpp',
- 'request_types/merge_chunks_request_type.cpp',
+ 'request_types/merge_chunk_request.idl',
'request_types/migration_secondary_throttle_options.cpp',
'request_types/move_chunk_request.cpp',
'request_types/move_primary.idl',
diff --git a/src/mongo/s/chunk_version.h b/src/mongo/s/chunk_version.h
index 68f430ef026..8d0b393aff8 100644
--- a/src/mongo/s/chunk_version.h
+++ b/src/mongo/s/chunk_version.h
@@ -88,6 +88,13 @@ public:
return uassertStatusOK(fromBSON(obj));
}
+ static ChunkVersion fromBSONArrayThrowing(const BSONElement& element) {
+ uassert(ErrorCodes::TypeMismatch,
+ "Invalid type for chunkVersion element. Expected an array",
+ element.type() == Array);
+ return fromBSONThrowing(element.Obj());
+ }
+
/**
* NOTE: This format should not be used. Use fromBSONThrowing instead.
*
@@ -230,6 +237,13 @@ public:
BSONObj toBSON() const;
/**
+ * Same as ChunkVersion::appendWithField adapted for IDL
+ */
+ void serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const {
+ appendWithField(builder, fieldName);
+ }
+
+ /**
* NOTE: This format serializes chunk version as a timestamp (without the epoch) for
* legacy reasons.
*/
diff --git a/src/mongo/s/chunk_version.idl b/src/mongo/s/chunk_version.idl
index ee33893468b..82ea4f5333c 100644
--- a/src/mongo/s/chunk_version.idl
+++ b/src/mongo/s/chunk_version.idl
@@ -34,6 +34,8 @@ global:
- "mongo/s/chunk_version.h"
types:
+ # serializes as { 0: <major/minor>, 1: <epoch>, 2: <timestamp> }
+ # equivalent to using ChunkVersion::toBSON / ChunkVersion::fromBSON
ChunkVersion:
bson_serialization_type: object
description: An object representing a chunk version for a collection.
diff --git a/src/mongo/s/request_types/merge_chunk_request.idl b/src/mongo/s/request_types/merge_chunk_request.idl
new file mode 100644
index 00000000000..d30db73aa42
--- /dev/null
+++ b/src/mongo/s/request_types/merge_chunk_request.idl
@@ -0,0 +1,130 @@
+# Copyright (C) 2021-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.
+#
+
+# _configsvrCommitChunkMerge / _configsvrCommitChunksMerge IDL File
+
+global:
+ cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/util/uuid.h"
+ - "mongo/s/chunk_version.h"
+ - "mongo/s/request_types/merge_chunk_request_valid.h"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+ - "mongo/s/sharding_types.idl"
+ - "mongo/s/chunk_range.idl"
+
+types:
+ # Non-IDL response used UUIDtoBSON instead of UUID::toCDR
+ my_uuid:
+ bson_serialization_type: object
+ description: "A UUID for some reason not generic uuid type."
+ cpp_type: "mongo::UUID"
+ deserializer: "mongo::UUID::parse"
+ serializer: "mongo::UUID::toBSON"
+
+ # serialize [<major/minor>, <epoch>, <timestamp>]
+ # equivalent to using ChunkVersion::appendToCommand / ChunkVersion::parseFromCommand
+ ChunkVersionArray:
+ bson_serialization_type: any
+ description: "An object representing a chunk version for a collection."
+ cpp_type: "ChunkVersion"
+ serializer: "ChunkVersion::serializeToBSON"
+ deserializer: "ChunkVersion::fromBSONArrayThrowing"
+
+structs:
+ ConfigSvrMergeResponse:
+ description: "Response of the _configsvrCommitChunkMerge command."
+ strict: false
+ fields:
+ shardVersion:
+ type: ChunkVersionArray
+ description: "Latest version of the shard."
+
+commands:
+ _configsvrCommitChunkMerge:
+ command_name: _configsvrCommitChunkMerge
+ cpp_name: "ConfigSvrMergeChunk"
+ description: "The internal _configsvrCommitChunkMerge command on the config server."
+ namespace: type
+ api_version: ""
+ type: namespacestring
+ strict: false
+ reply_type: ConfigSvrMergeResponse
+ fields:
+ shard:
+ type: shard_id
+ description: "String identifier for a shard's name"
+ collEpoch:
+ type: objectid
+ cpp_name: "epoch"
+ description: "Uniquely identifies this instance of the collection, in case of
+ drop/create or shard key refine."
+ chunkBoundaries:
+ type: array<object_owned>
+ description: "Chunk bounds to merge."
+ validator: { callback: 'chunkBoundsNotEmpty' }
+ validAfter:
+ type: timestamp
+ description: "The time after which this chunk is at this shard."
+ optional: true
+ writeConcern:
+ description: "The level of write concern for the creation operation"
+ type: object
+ optional: true
+
+ _configsvrCommitChunksMerge:
+ command_name: _configsvrCommitChunksMerge
+ cpp_name: ConfigSvrMergeChunks
+ description: "The internal _configsvrCommitChunksMerge command on the config server."
+ namespace: type
+ api_version: ""
+ type: namespacestring
+ strict: false
+ reply_type: ConfigSvrMergeResponse
+ fields:
+ shard:
+ description: "The id of the shard."
+ type: shard_id
+ collUUID:
+ type: my_uuid
+ cpp_name: "collectionUUID"
+ description: "The UUID of the collection that the chunk belongs to."
+ chunkRange:
+ type: chunk_range
+ cpp_name: "chunkRange"
+ description: "Chunk bounds to merge."
+ validAfter:
+ type: timestamp
+ description: "The time after which this chunk is at this shard."
+ optional: true
+ writeConcern:
+ description: "The level of write concern for the creation operation."
+ type: object
+ optional: true
diff --git a/src/mongo/s/request_types/merge_chunk_request_test.cpp b/src/mongo/s/request_types/merge_chunk_request_test.cpp
index 88d5d165148..3c11bdc639c 100644
--- a/src/mongo/s/request_types/merge_chunk_request_test.cpp
+++ b/src/mongo/s/request_types/merge_chunk_request_test.cpp
@@ -30,7 +30,7 @@
#include "mongo/platform/basic.h"
#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/s/request_types/merge_chunk_request_type.h"
+#include "mongo/s/request_types/merge_chunk_request_gen.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -38,29 +38,36 @@ namespace {
using unittest::assertGet;
-TEST(MergeChunkRequest, BasicValidConfigCommand) {
- auto request = assertGet(MergeChunkRequest::parseFromConfigCommand(
+IDLParserErrorContext ctx("_configsvrCommitChunkMerge");
+
+TEST(ConfigSvrMergeChunk, BasicValidConfigCommand) {
+ auto request = ConfigSvrMergeChunk::parse(
+ ctx,
BSON("_configsvrCommitChunkMerge"
<< "TestDB.TestColl"
+ << "shard"
+ << "shard0000"
<< "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
- << "shard0000")));
- ASSERT_EQ(NamespaceString("TestDB", "TestColl"), request.getNamespace());
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "$db"
+ << "admin"));
+ ASSERT_EQ(NamespaceString("TestDB", "TestColl"), request.getCommandParameter());
ASSERT_EQ(OID("7fffffff0000000000000001"), request.getEpoch());
ASSERT_BSONOBJ_EQ(BSON("a" << 1), request.getChunkBoundaries().at(0));
ASSERT_BSONOBJ_EQ(BSON("a" << 5), request.getChunkBoundaries().at(1));
ASSERT_BSONOBJ_EQ(BSON("a" << 10), request.getChunkBoundaries().at(2));
- ASSERT_EQ("shard0000", request.getShardName());
+ ASSERT_EQ("shard0000", request.getShard().toString());
+ ASSERT_EQ("admin", request.getDbName());
}
-TEST(MergeChunkRequest, ConfigCommandtoBSON) {
+TEST(ConfigSvrMergeChunk, ConfigCommandtoBSON) {
BSONObj serializedRequest =
BSON("_configsvrCommitChunkMerge"
<< "TestDB.TestColl"
- << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
+ << "shard"
<< "shard0000"
- << "validAfter" << Timestamp{100});
+ << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "validAfter"
+ << Timestamp{100});
BSONObj writeConcernObj = BSON("w"
<< "majority");
@@ -70,113 +77,179 @@ TEST(MergeChunkRequest, ConfigCommandtoBSON) {
cmdBuilder.append("writeConcern", writeConcernObj);
}
- auto request = assertGet(MergeChunkRequest::parseFromConfigCommand(serializedRequest));
- auto requestToBSON = request.toConfigCommandBSON(writeConcernObj);
+ auto appendDB = [](const BSONObj& obj) {
+ BSONObjBuilder builder;
+ builder.appendElements(obj);
+ builder.append("$db", "admin");
+ return builder.obj();
+ };
+
+ auto request = ConfigSvrMergeChunk::parse(ctx, appendDB(serializedRequest));
+ request.setWriteConcern(writeConcernObj);
+ auto requestToBSON = request.toBSON(BSONObj());
ASSERT_BSONOBJ_EQ(cmdBuilder.obj(), requestToBSON);
}
-TEST(MergeChunkRequest, MissingNameSpaceErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(BSON(
- "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
-}
+TEST(ConfigSvrMergeChunk, MissingNameSpaceErrors) {
+ ASSERT_THROWS_CODE(
-TEST(MergeChunkRequest, MissingCollEpochErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "chunkBoundaries" << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10))
- << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+ ConfigSvrMergeChunk::parse(
+ ctx,
+ BSON("collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10))
+ << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ mongo::DBException,
+ 40414);
}
-TEST(MergeChunkRequest, MissingChunkBoundariesErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "collEpoch" << OID("7fffffff0000000000000001") << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+TEST(ConfigSvrMergeChunk, MissingCollEpochErrors) {
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunk::parse(
+ ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ mongo::DBException,
+ 40414);
}
-TEST(MergeChunkRequest, MissingShardNameErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10))));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+TEST(ConfigSvrMergeChunk, MissingChunkBoundariesErrors) {
+ ASSERT_THROWS_CODE(
+
+ ConfigSvrMergeChunk::parse(ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "collEpoch" << OID("7fffffff0000000000000001") << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ mongo::DBException,
+ 40414);
}
-TEST(MergeChunkRequest, WrongNamespaceTypeErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << 1234 << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+TEST(ConfigSvrMergeChunk, MissingShardNameErrors) {
+ ASSERT_THROWS_CODE(
+
+ ConfigSvrMergeChunk::parse(
+ ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "$db"
+ << "admin")),
+ mongo::DBException,
+ 40414);
}
-TEST(MergeChunkRequest, WrongCollEpochTypeErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "collEpoch" << 1234 << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+TEST(ConfigSvrMergeChunk, WrongNamespaceTypeErrors) {
+ ASSERT_THROWS_CODE(
+
+ ConfigSvrMergeChunk::parse(
+ ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << 1234 << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunkRequest, WrongChunkBoundariesTypeErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(BSON(
- "_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries" << 1234 << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+
+TEST(ConfigSvrMergeChunk, WrongCollEpochTypeErrors) {
+ ASSERT_THROWS_CODE(
+
+ ConfigSvrMergeChunk::parse(
+ ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "collEpoch" << 1234 << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunkRequest, WrongShardNameTypeErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(BSON(
- "_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard" << 1234));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+TEST(ConfigSvrMergeChunk, WrongChunkBoundariesTypeErrors) {
+ ASSERT_THROWS_CODE(
+
+ ConfigSvrMergeChunk::parse(ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "collEpoch" << OID("7fffffff0000000000000001")
+ << "chunkBoundaries" << 1234 << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunkRequest, InvalidNamespaceErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << ""
- << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
- << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::InvalidNamespace, request.getStatus());
+TEST(ConfigSvrMergeChunk, WrongShardNameTypeErrors) {
+ ASSERT_THROWS_CODE(
+
+ ConfigSvrMergeChunk::parse(
+ ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
+ << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
+ << 1234 << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunkRequest, EmptyChunkBoundariesErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunkMerge"
- << "TestDB.TestColl"
- << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries" << BSONArray()
- << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::InvalidOptions, request.getStatus());
+//// IDL validators do not work on command value
+// TEST(ConfigSvrMergeChunk, InvalidNamespaceErrors) {
+// auto request = MergeChunkRequest::parseFromConfigBSONCommand(
+// BSON("_configsvrCommitChunkMerge"
+// << ""
+// << "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
+// << BSON_ARRAY(BSON("a" << 1) << BSON("a" << 5) << BSON("a" << 10)) << "shard"
+// << "shard0000" << "$db" << "admin"));
+// ASSERT_EQ(ErrorCodes::InvalidNamespace, request.getStatus());
+// }
+
+TEST(ConfigSvrMergeChunk, EmptyChunkBoundariesErrors) {
+ auto req = ConfigSvrMergeChunk::parse(ctx,
+ BSON("_configsvrCommitChunkMerge"
+ << "TestDB.TestColl"
+ << "collEpoch" << OID("7fffffff0000000000000001")
+ << "chunkBoundaries" << BSONArray() << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin"));
+ // trigger validator (bit useless)
+ ASSERT_THROWS_CODE(
+ req.setChunkBoundaries(req.getChunkBoundaries()), DBException, ErrorCodes::InvalidOptions);
}
-TEST(MergeChunkRequest, TooFewChunkBoundariesErrors) {
- auto request = MergeChunkRequest::parseFromConfigCommand(
+TEST(ConfigSvrMergeChunk, TooFewChunkBoundariesErrors) {
+ auto req = ConfigSvrMergeChunk::parse(
+ ctx,
BSON("_configsvrCommitChunkMerge"
<< "TestDB.TestColl"
<< "collEpoch" << OID("7fffffff0000000000000001") << "chunkBoundaries"
<< BSON_ARRAY(BSON("a" << 1) << BSON("a" << 10)) << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::InvalidOptions, request.getStatus());
+ << "shard0000"
+ << "$db"
+ << "admin"));
+ // trigger validator (bit useless)
+
+ ASSERT_THROWS_CODE(
+ req.setChunkBoundaries(req.getChunkBoundaries()), DBException, ErrorCodes::InvalidOptions);
}
} // namespace
diff --git a/src/mongo/s/request_types/merge_chunk_request_type.cpp b/src/mongo/s/request_types/merge_chunk_request_type.cpp
deleted file mode 100644
index 387bacc16b0..00000000000
--- a/src/mongo/s/request_types/merge_chunk_request_type.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Copyright (C) 2018-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/platform/basic.h"
-
-#include "mongo/s/request_types/merge_chunk_request_type.h"
-
-#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/bson/util/bson_extract.h"
-#include "mongo/db/write_concern_options.h"
-
-namespace mongo {
-namespace {
-
-const char kConfigsvrMergeChunk[] = "_configsvrCommitChunkMerge";
-const char kCollEpoch[] = "collEpoch";
-const char kChunkBoundaries[] = "chunkBoundaries";
-const char kShardName[] = "shard";
-const char kValidAfter[] = "validAfter";
-} // namespace
-
-MergeChunkRequest::MergeChunkRequest(NamespaceString nss,
- std::string shardName,
- OID epoch,
- std::vector<BSONObj> chunkBoundaries,
- boost::optional<Timestamp> validAfter)
- : _nss(std::move(nss)),
- _epoch(std::move(epoch)),
- _chunkBoundaries(std::move(chunkBoundaries)),
- _shardName(std::move(shardName)),
- _validAfter(validAfter) {}
-
-StatusWith<MergeChunkRequest> MergeChunkRequest::parseFromConfigCommand(const BSONObj& cmdObj) {
- std::string ns;
- {
- auto parseNamespaceStatus = bsonExtractStringField(cmdObj, kConfigsvrMergeChunk, &ns);
- if (!parseNamespaceStatus.isOK()) {
- return parseNamespaceStatus;
- }
- }
-
- NamespaceString nss(ns);
- if (!nss.isValid()) {
- return {ErrorCodes::InvalidNamespace,
- str::stream() << "invalid namespace '" << nss.ns() << "' specified for request"};
- }
-
- OID epoch;
- {
- auto parseEpochStatus = bsonExtractOIDField(cmdObj, kCollEpoch, &epoch);
- if (!parseEpochStatus.isOK()) {
- return parseEpochStatus;
- }
- }
-
- std::vector<BSONObj> chunkBoundaries;
- {
- BSONElement chunkBoundariesElem;
- auto chunkBoundariesElemStatus =
- bsonExtractTypedField(cmdObj, kChunkBoundaries, mongo::Array, &chunkBoundariesElem);
-
- if (!chunkBoundariesElemStatus.isOK()) {
- return chunkBoundariesElemStatus;
- }
- BSONObjIterator it(chunkBoundariesElem.Obj());
- while (it.more()) {
- chunkBoundaries.push_back(it.next().Obj().getOwned());
- }
-
- if (chunkBoundaries.size() < 3) {
- return {ErrorCodes::InvalidOptions,
- "need to provide at least three chunk boundaries for the chunks to be merged"};
- }
- }
-
- std::string shardName;
- {
- auto parseShardNameStatus = bsonExtractStringField(cmdObj, kShardName, &shardName);
- if (!parseShardNameStatus.isOK()) {
- return parseShardNameStatus;
- }
- }
-
- boost::optional<Timestamp> validAfter = boost::none;
- {
- Timestamp ts{0};
- auto status = bsonExtractTimestampField(cmdObj, kValidAfter, &ts);
- if (!status.isOK() && status != ErrorCodes::NoSuchKey) {
- return status;
- }
-
- if (status.isOK()) {
- validAfter = ts;
- }
- }
-
- return MergeChunkRequest(std::move(nss),
- std::move(shardName),
- std::move(epoch),
- std::move(chunkBoundaries),
- validAfter);
-}
-
-BSONObj MergeChunkRequest::toConfigCommandBSON(const BSONObj& writeConcern) {
- BSONObjBuilder cmdBuilder;
- appendAsConfigCommand(&cmdBuilder);
-
- // Tack on passed-in writeConcern
- cmdBuilder.append(WriteConcernOptions::kWriteConcernField, writeConcern);
-
- return cmdBuilder.obj();
-}
-
-void MergeChunkRequest::appendAsConfigCommand(BSONObjBuilder* cmdBuilder) {
- cmdBuilder->append(kConfigsvrMergeChunk, _nss.ns());
- cmdBuilder->append(kCollEpoch, _epoch);
- {
- BSONArrayBuilder chunkBoundariesArray(cmdBuilder->subarrayStart(kChunkBoundaries));
- for (const auto& chunkBoundary : _chunkBoundaries) {
- chunkBoundariesArray.append(chunkBoundary);
- }
- }
- cmdBuilder->append(kShardName, _shardName);
- invariant(_validAfter.is_initialized());
- cmdBuilder->append(kValidAfter, _validAfter.get());
-}
-
-} // namespace mongo
diff --git a/src/mongo/s/request_types/merge_chunk_request_type.h b/src/mongo/s/request_types/merge_chunk_request_type.h
deleted file mode 100644
index 38d2a9f90db..00000000000
--- a/src/mongo/s/request_types/merge_chunk_request_type.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * Copyright (C) 2018-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 <vector>
-
-#include "mongo/base/status_with.h"
-
-#include "mongo/db/jsobj.h"
-#include "mongo/db/namespace_string.h"
-
-namespace mongo {
-
-/**
- * Provides support for parsing and serialization of arguments to the config server mergeChunk
- * command.
- */
-class MergeChunkRequest {
-public:
- MergeChunkRequest(NamespaceString nss,
- std::string shardName,
- OID epoch,
- std::vector<BSONObj> chunkBoundaries,
- boost::optional<Timestamp> validAfter);
-
- /**
- * Parses the provided BSON content as the internal _configsvrCommitChunkMerge command, and if
- * it contains the correct types, constructs a MergeChunkRequest object from it.
- *
- * {
- * _configsvrCommitChunkMerge: <NamespaceString nss>,
- * collEpoch: <OID epoch>,
- * chunkBoundaries: [
- * <BSONObj key1>,
- * <BSONObj key2>,
- * ...
- * ],
- * shard: <string shard>
- * }
- */
- static StatusWith<MergeChunkRequest> parseFromConfigCommand(const BSONObj& cmdObj);
-
- /**
- * Creates a BSONObjBuilder and uses it to create and return a BSONObj from this
- * MergeChunkRequest instance. Calls appendAsConfigCommand and tacks on the passed-in
- * writeConcern.
- */
- BSONObj toConfigCommandBSON(const BSONObj& writeConcern);
-
- /**
- * Creates a serialized BSONObj of the internal _configsvCommitChunkMerge command from this
- * MergeChunkRequest instance.
- */
- void appendAsConfigCommand(BSONObjBuilder* cmdBuilder);
-
- const NamespaceString& getNamespace() const {
- return _nss;
- }
-
- const OID& getEpoch() const {
- return _epoch;
- }
-
- const std::vector<BSONObj>& getChunkBoundaries() const {
- return _chunkBoundaries;
- }
-
- const std::string& getShardName() const {
- return _shardName;
- }
-
- const boost::optional<Timestamp>& getValidAfter() const {
- return _validAfter;
- }
-
-private:
- NamespaceString _nss;
- OID _epoch;
-
- // The boundaries of the chunks to be merged.
- std::vector<BSONObj> _chunkBoundaries;
-
- std::string _shardName;
-
- boost::optional<Timestamp> _validAfter;
-};
-
-} // namespace mongo
diff --git a/src/mongo/s/request_types/merge_chunk_request_valid.h b/src/mongo/s/request_types/merge_chunk_request_valid.h
new file mode 100644
index 00000000000..8929f9165bb
--- /dev/null
+++ b/src/mongo/s/request_types/merge_chunk_request_valid.h
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2021-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 <string>
+#include <vector>
+
+#include "mongo/bson/bsonobj.h"
+
+namespace mongo {
+
+inline Status chunkBoundsNotEmpty(const std::vector<BSONObj>& values) {
+ if (values.size() < 3) {
+ return {ErrorCodes::InvalidOptions,
+ "need to provide at least three chunk boundaries for the chunks to be merged"};
+ }
+ return Status::OK();
+}
+} // namespace mongo
diff --git a/src/mongo/s/request_types/merge_chunks_request_test.cpp b/src/mongo/s/request_types/merge_chunks_request_test.cpp
index 2b5e48ba9f2..b97114ae94c 100644
--- a/src/mongo/s/request_types/merge_chunks_request_test.cpp
+++ b/src/mongo/s/request_types/merge_chunks_request_test.cpp
@@ -30,8 +30,9 @@
#include "mongo/platform/basic.h"
#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/s/request_types/merge_chunks_request_type.h"
+#include "mongo/s/request_types/merge_chunk_request_gen.h"
#include "mongo/unittest/unittest.h"
+#include "mongo/util/assert_util.h"
namespace mongo {
namespace {
@@ -39,28 +40,32 @@ namespace {
using unittest::assertGet;
ChunkRange chunkRange(BSON("a" << 1), BSON("a" << 10));
+IDLParserErrorContext ctx("_configsvrCommitChunksMerge");
-TEST(MergeChunksRequest, BasicValidConfigCommand) {
+TEST(ConfigSvrMergeChunks, BasicValidConfigCommand) {
auto collUUID = UUID::gen();
- auto request = assertGet(MergeChunksRequest::parseFromConfigCommand(
+ auto request = ConfigSvrMergeChunks::parse(
+ ctx,
BSON("_configsvrCommitChunksMerge"
<< "TestDB.TestColl"
<< "collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON() << "shard"
- << "shard0000")));
- ASSERT_EQ(NamespaceString("TestDB", "TestColl"), request.getNamespace());
+ << "shard0000"
+ << "$db"
+ << "admin"));
+ ASSERT_EQ(NamespaceString("TestDB", "TestColl"), request.getCommandParameter());
ASSERT_TRUE(collUUID == request.getCollectionUUID());
ASSERT_TRUE(chunkRange == request.getChunkRange());
- ASSERT_EQ("shard0000", request.getShardId().toString());
+ ASSERT_EQ("shard0000", request.getShard().toString());
}
-TEST(MergeChunksRequest, ConfigCommandtoBSON) {
+TEST(ConfigSvrMergeChunks, ConfigCommandtoBSON) {
auto collUUID = UUID::gen();
- BSONObj serializedRequest =
- BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON() << "shard"
- << "shard0000"
- << "validAfter" << Timestamp{100});
+ BSONObj serializedRequest = BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "shard"
+ << "shard0000"
+ << "collUUID" << collUUID.toBSON() << "chunkRange"
+ << chunkRange.toBSON() << "validAfter" << Timestamp{100});
BSONObj writeConcernObj = BSON("w"
<< "majority");
@@ -70,95 +75,139 @@ TEST(MergeChunksRequest, ConfigCommandtoBSON) {
cmdBuilder.append("writeConcern", writeConcernObj);
}
- auto request = assertGet(MergeChunksRequest::parseFromConfigCommand(serializedRequest));
- auto requestToBSON = request.toConfigCommandBSON(writeConcernObj);
+ auto appendDB = [](const BSONObj& obj) {
+ BSONObjBuilder builder;
+ builder.appendElements(obj);
+ builder.append("$db", "admin");
+ return builder.obj();
+ };
+
+ auto request = ConfigSvrMergeChunks::parse(ctx, appendDB(serializedRequest));
+ request.setWriteConcern(writeConcernObj);
+ auto requestToBSON = request.toBSON(BSONObj());
ASSERT_BSONOBJ_EQ(cmdBuilder.obj(), requestToBSON);
}
-TEST(MergeChunksRequest, MissingNameSpaceErrors) {
+TEST(ConfigSvrMergeChunks, MissingNameSpaceErrors) {
auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON() << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunks::parse(ctx,
+ BSON("collUUID" << collUUID.toBSON() << "chunkRange"
+ << chunkRange.toBSON() << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ mongo::DBException,
+ 40414);
}
-TEST(MergeChunksRequest, MissingcollUUIDErrors) {
- auto request = MergeChunksRequest::parseFromConfigCommand(BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "chunkRange"
- << chunkRange.toBSON() << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+TEST(ConfigSvrMergeChunks, MissingcollUUIDErrors) {
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "chunkRange" << chunkRange.toBSON() << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ mongo::DBException,
+ 40414);
+ // ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
}
-TEST(MergeChunksRequest, MissingChunkRangeErrors) {
+TEST(ConfigSvrMergeChunks, MissingChunkRangeErrors) {
auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "collUUID"
- << collUUID.toBSON() << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "collUUID" << collUUID.toBSON() << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ 40414);
}
-TEST(MergeChunksRequest, MissingShardIdErrors) {
+TEST(ConfigSvrMergeChunks, MissingShardIdErrors) {
auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON()));
- ASSERT_EQ(ErrorCodes::NoSuchKey, request.getStatus());
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "collUUID" << collUUID.toBSON() << "chunkRange"
+ << chunkRange.toBSON() << "$db"
+ << "admin")),
+ DBException,
+ 40414);
}
-TEST(MergeChunksRequest, WrongNamespaceTypeErrors) {
+TEST(ConfigSvrMergeChunks, WrongNamespaceTypeErrors) {
auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunksMerge" << 1234 << "collUUID" << collUUID.toBSON()
- << "chunkRange" << chunkRange.toBSON() << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << 1234 << "collUUID" << collUUID.toBSON() << "chunkRange"
+ << chunkRange.toBSON() << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunksRequest, WrongcollUUIDTypeErrors) {
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "collUUID" << 1234 << "chunkRange" << chunkRange.toBSON() << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+TEST(ConfigSvrMergeChunks, WrongcollUUIDTypeErrors) {
+ ASSERT_THROWS_CODE(ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "collUUID" << 1234 << "chunkRange"
+ << chunkRange.toBSON() << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunksRequest, WrongChunkRangeTypeErrors) {
- auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "collUUID" << collUUID.toBSON() << "chunkRange" << 1234 << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
-}
-TEST(MergeChunksRequest, WrongShardIdTypeErrors) {
+TEST(ConfigSvrMergeChunks, WrongChunkRangeTypeErrors) {
auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunksMerge"
- << "TestDB.TestColl"
- << "collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON() << "shard"
- << 1234));
- ASSERT_EQ(ErrorCodes::TypeMismatch, request.getStatus());
+ ASSERT_THROWS_CODE(ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "collUUID" << collUUID.toBSON()
+ << "chunkRange" << 1234 << "shard"
+ << "shard0000"
+ << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
-TEST(MergeChunksRequest, InvalidNamespaceErrors) {
+TEST(ConfigSvrMergeChunks, WrongShardIdTypeErrors) {
auto collUUID = UUID::gen();
- auto request = MergeChunksRequest::parseFromConfigCommand(
- BSON("_configsvrCommitChunksMerge"
- << ""
- << "collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON() << "shard"
- << "shard0000"));
- ASSERT_EQ(ErrorCodes::InvalidNamespace, request.getStatus());
+ ASSERT_THROWS_CODE(
+ ConfigSvrMergeChunks::parse(ctx,
+ BSON("_configsvrCommitChunksMerge"
+ << "TestDB.TestColl"
+ << "collUUID" << collUUID.toBSON() << "chunkRange"
+ << chunkRange.toBSON() << "shard" << 1234 << "$db"
+ << "admin")),
+ DBException,
+ ErrorCodes::TypeMismatch);
}
+//// IDL validators do not work on command value
+// TEST(ConfigSvrMergeChunks, InvalidNamespaceErrors) {
+// ASSERT_THROWS_CODE({
+// auto collUUID = UUID::gen();
+// ConfigSvrMergeChunks::parse(ctx,
+// BSON("_configsvrCommitChunksMerge" << ""
+// << "collUUID" << collUUID.toBSON() << "chunkRange" << chunkRange.toBSON() << "shard"
+// << "shard0000" << "$db" << "admin"));
+// }, DBException, ErrorCodes::InvalidNamespace);
+// }
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/s/request_types/merge_chunks_request_type.cpp b/src/mongo/s/request_types/merge_chunks_request_type.cpp
deleted file mode 100644
index 1ea06a036fb..00000000000
--- a/src/mongo/s/request_types/merge_chunks_request_type.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * Copyright (C) 2021-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/s/request_types/merge_chunks_request_type.h"
-#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/bson/util/bson_extract.h"
-#include "mongo/db/write_concern_options.h"
-#include "mongo/platform/basic.h"
-
-namespace mongo {
-namespace {
-
-const char kConfigsvrMergeChunks[] = "_configsvrCommitChunksMerge";
-const char kCollUUID[] = "collUUID";
-const char kChunkRange[] = "chunkRange";
-const char kShardId[] = "shard";
-const char kValidAfter[] = "validAfter";
-} // namespace
-
-MergeChunksRequest::MergeChunksRequest(NamespaceString nss,
- ShardId shardId,
- UUID collectionUUID,
- ChunkRange chunkRange,
- boost::optional<Timestamp> validAfter)
- : _nss(std::move(nss)),
- _collectionUUID(std::move(collectionUUID)),
- _chunkRange(std::move(chunkRange)),
- _shardId(std::move(shardId)),
- _validAfter(validAfter) {}
-
-StatusWith<MergeChunksRequest> MergeChunksRequest::parseFromConfigCommand(const BSONObj& cmdObj) {
- std::string ns;
- {
- auto parseNamespaceStatus = bsonExtractStringField(cmdObj, kConfigsvrMergeChunks, &ns);
- if (!parseNamespaceStatus.isOK()) {
- return parseNamespaceStatus;
- }
- }
- NamespaceString nss(ns);
- if (!nss.isValid()) {
- return {ErrorCodes::InvalidNamespace,
- str::stream() << "invalid namespace '" << nss.ns() << "' specified for request"};
- }
-
- BSONElement collUUIDElem;
- {
- auto parseCollUUIDStatus =
- bsonExtractTypedField(cmdObj, kCollUUID, mongo::Object, &collUUIDElem);
- if (!parseCollUUIDStatus.isOK()) {
- return parseCollUUIDStatus;
- }
- }
-
- auto collUUID = UUID::parse(collUUIDElem.Obj().getField("uuid"));
- if (!collUUID.isOK()) {
- return collUUID.getStatus();
- }
-
- BSONElement chunkRangeElem;
- {
- auto chunkRangeStatus =
- bsonExtractTypedField(cmdObj, kChunkRange, mongo::Object, &chunkRangeElem);
- if (!chunkRangeStatus.isOK()) {
- return chunkRangeStatus;
- }
- }
-
- auto chunkRange = ChunkRange::fromBSON(chunkRangeElem.Obj().getOwned());
- if (!chunkRange.isOK()) {
- return chunkRange.getStatus();
- }
-
- std::string shardIdString;
- {
- auto parseShardIdStatus = bsonExtractStringField(cmdObj, kShardId, &shardIdString);
- if (!parseShardIdStatus.isOK()) {
- return parseShardIdStatus;
- }
- }
-
- boost::optional<Timestamp> validAfter = boost::none;
- {
- Timestamp ts{0};
- auto status = bsonExtractTimestampField(cmdObj, kValidAfter, &ts);
- if (!status.isOK() && status != ErrorCodes::NoSuchKey) {
- return status;
- }
-
- if (status.isOK()) {
- validAfter = ts;
- }
- }
-
- return MergeChunksRequest(std::move(nss),
- ShardId(shardIdString),
- std::move(collUUID.getValue()),
- std::move(chunkRange.getValue()),
- validAfter);
-}
-
-BSONObj MergeChunksRequest::toConfigCommandBSON(const BSONObj& writeConcern) {
- BSONObjBuilder cmdBuilder;
- appendAsConfigCommand(&cmdBuilder);
-
- // Tack on passed-in writeConcern
- cmdBuilder.append(WriteConcernOptions::kWriteConcernField, writeConcern);
-
- return cmdBuilder.obj();
-}
-
-void MergeChunksRequest::appendAsConfigCommand(BSONObjBuilder* cmdBuilder) {
- cmdBuilder->append(kConfigsvrMergeChunks, _nss.ns());
- cmdBuilder->append(kCollUUID, _collectionUUID.toBSON());
- cmdBuilder->append(kChunkRange, _chunkRange.toBSON());
- cmdBuilder->append(kShardId, _shardId);
- invariant(_validAfter.is_initialized());
- cmdBuilder->append(kValidAfter, _validAfter.get());
-}
-
-
-} // namespace mongo
diff --git a/src/mongo/s/request_types/merge_chunks_request_type.h b/src/mongo/s/request_types/merge_chunks_request_type.h
deleted file mode 100644
index bed10c7f338..00000000000
--- a/src/mongo/s/request_types/merge_chunks_request_type.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Copyright (C) 2021-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/namespace_string.h"
-#include "mongo/s/catalog/type_chunk.h"
-
-namespace mongo {
-
-/**
- * Provides support for parsing and serialization of arguments to the config server mergeChunks
- * command.
- */
-class MergeChunksRequest {
-public:
- MergeChunksRequest(NamespaceString nss,
- ShardId shardId,
- UUID collUUID,
- ChunkRange chunkRange,
- boost::optional<Timestamp> validAfter);
- /**
- * Parses the provided BSON content as the internal _configsvrCommitChunksMerge command
- * and if it contains the correct types, constructs a MergeChunksRequest object from it.
- *
- * {
- * _configsvrCommitChunksMerge: <NamespaceString nss>,
- * collUUID: <UUID>,
- * chunkRage: <ChunkRange [minKey, maxKey)>,
- * shard: <string shard>
- * }
- */
- static StatusWith<MergeChunksRequest> parseFromConfigCommand(const BSONObj& cmdObj);
-
- /**
- * Creates a BSONObjBuilder and uses it to create and return a BSONObj from this
- * MergeChunksRequest instance. Calls appendAsConfigCommand and tacks on the passed-in
- * writeConcern.
- */
- BSONObj toConfigCommandBSON(const BSONObj& writeConcern);
-
- /**
- * Creates a serialized BSONObj of the internal _configsvCommitChunksMerge command
- * from this MergeChunksRequest instance.
- */
- void appendAsConfigCommand(BSONObjBuilder* cmdBuilder);
-
- const NamespaceString& getNamespace() const {
- return _nss;
- }
-
- const UUID& getCollectionUUID() const {
- return _collectionUUID;
- }
-
- const ChunkRange& getChunkRange() const {
- return _chunkRange;
- }
-
- const ShardId& getShardId() const {
- return _shardId;
- }
-
- const boost::optional<Timestamp>& getValidAfter() const {
- return _validAfter;
- }
-
-private:
- NamespaceString _nss;
-
- UUID _collectionUUID;
-
- ChunkRange _chunkRange;
-
- ShardId _shardId;
-
- boost::optional<Timestamp> _validAfter;
-};
-
-} // namespace mongo