diff options
author | Leon Zaruvinsky <leon@mongodb.com> | 2016-07-06 16:13:58 -0400 |
---|---|---|
committer | Leon Zaruvinsky <leon@mongodb.com> | 2016-07-19 13:52:55 -0400 |
commit | e9201e5c46124472b941a1932dc8827a36487e5e (patch) | |
tree | 2a4bac27a738170248833a6b53969f37277b6a35 | |
parent | 9ce36539e7b5aef8078a0f289ce4c99091df9b51 (diff) | |
download | mongo-e9201e5c46124472b941a1932dc8827a36487e5e.tar.gz |
SERVER-24488 Move logic to serialize and deserialize CommitChunkMigration to a CommitChunkMigrationRequest class
6 files changed, 408 insertions, 105 deletions
diff --git a/src/mongo/db/s/config/configsvr_commit_chunk_migration_command.cpp b/src/mongo/db/s/config/configsvr_commit_chunk_migration_command.cpp index 345299ff0b7..72760cdda65 100644 --- a/src/mongo/db/s/config/configsvr_commit_chunk_migration_command.cpp +++ b/src/mongo/db/s/config/configsvr_commit_chunk_migration_command.cpp @@ -28,7 +28,6 @@ #include "mongo/platform/basic.h" -#include "mongo/bson/util/bson_extract.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/concurrency/d_concurrency.h" @@ -41,6 +40,7 @@ #include "mongo/s/chunk_version.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" +#include "mongo/s/request_types/commit_chunk_migration_request_type.h" namespace mongo { @@ -111,43 +111,11 @@ public: return parseNsFullyQualified(dbname, cmdObj); } - /** - * Returns a BSON subobject from "field" in "source". - */ - StatusWith<BSONObj> getBSONField(const BSONObj& source, StringData field) { - BSONElement fieldElement; - Status status = bsonExtractTypedField(source, field, BSONType::Object, &fieldElement); - if (!status.isOK()) { - return status; - } - - return fieldElement.Obj().getOwned(); - } - - /** - * Parses a string value from "field" in "source" and returns it. - */ - static std::string extractString(const BSONObj source, StringData field) { - std::string stringResult; - Status status = bsonExtractStringField(source, field, &stringResult); - uassert(status.code(), - str::stream() << "Failed to parse '" << field << "' field from BSON '" - << source.jsonString() - << "'" - << causedBy(status), - status.isOK()); - uassert(status.code(), - str::stream() << "'" << field << "' field in BSON '" << source.jsonString() - << "' is empty", - stringResult.length() > 0); - return stringResult; - } - static void checkChunkIsOnShard(OperationContext* txn, const NamespaceString& nss, const BSONObj& min, const BSONObj& max, - StringData shard) { + const ShardId& shard) { BSONObj chunkQuery = BSON(ChunkType::ns() << nss.ns() << ChunkType::min() << min << ChunkType::max() << max << ChunkType::shard() @@ -173,8 +141,8 @@ public: BSONObj makeCommitChunkApplyOpsCommand( const NamespaceString& nss, - const StatusWith<ChunkRange>& migratedChunkRange, - const boost::optional<StatusWith<ChunkRange>>& controlChunkRange, + const ChunkRange& migratedChunkRange, + const boost::optional<ChunkRange>& controlChunkRange, const ChunkVersion newMigratedChunkVersion, const boost::optional<ChunkVersion> newControlChunkVersion, StringData toShard, @@ -188,18 +156,16 @@ public: op.append("ns", ChunkType::ConfigNS); BSONObjBuilder n(op.subobjStart("o")); - n.append(ChunkType::name(), - ChunkType::genID(nss.ns(), migratedChunkRange.getValue().getMin())); + n.append(ChunkType::name(), ChunkType::genID(nss.ns(), migratedChunkRange.getMin())); newMigratedChunkVersion.addToBSON(n, ChunkType::DEPRECATED_lastmod()); n.append(ChunkType::ns(), nss.ns()); - n.append(ChunkType::min(), migratedChunkRange.getValue().getMin()); - n.append(ChunkType::max(), migratedChunkRange.getValue().getMax()); + n.append(ChunkType::min(), migratedChunkRange.getMin()); + n.append(ChunkType::max(), migratedChunkRange.getMax()); n.append(ChunkType::shard(), toShard); n.done(); BSONObjBuilder q(op.subobjStart("o2")); - q.append(ChunkType::name(), - ChunkType::genID(nss.ns(), migratedChunkRange.getValue().getMin())); + q.append(ChunkType::name(), ChunkType::genID(nss.ns(), migratedChunkRange.getMin())); q.done(); updates.append(op.obj()); @@ -213,18 +179,16 @@ public: op.append("ns", ChunkType::ConfigNS); BSONObjBuilder n(op.subobjStart("o")); - n.append(ChunkType::name(), - ChunkType::genID(nss.ns(), controlChunkRange->getValue().getMin())); + n.append(ChunkType::name(), ChunkType::genID(nss.ns(), controlChunkRange->getMin())); newControlChunkVersion->addToBSON(n, ChunkType::DEPRECATED_lastmod()); n.append(ChunkType::ns(), nss.ns()); - n.append(ChunkType::min(), controlChunkRange->getValue().getMin()); - n.append(ChunkType::max(), controlChunkRange->getValue().getMax()); + n.append(ChunkType::min(), controlChunkRange->getMin()); + n.append(ChunkType::max(), controlChunkRange->getMax()); n.append(ChunkType::shard(), fromShard); n.done(); BSONObjBuilder q(op.subobjStart("o2")); - q.append(ChunkType::name(), - ChunkType::genID(nss.ns(), controlChunkRange->getValue().getMin())); + q.append(ChunkType::name(), ChunkType::genID(nss.ns(), controlChunkRange->getMin())); q.done(); updates.append(op.obj()); @@ -243,29 +207,9 @@ public: std::string& errmsg, BSONObjBuilder& result) override { const NamespaceString nss = NamespaceString(parseNs(dbName, cmdObj)); - std::string fromShard = extractString(cmdObj, "fromShard"); - std::string toShard = extractString(cmdObj, "toShard"); - - BSONObj migratedChunkField = uassertStatusOK(getBSONField(cmdObj, "migratedChunk")); - StatusWith<ChunkRange> migratedChunkRange = ChunkRange::fromBSON(migratedChunkField); - uassert(migratedChunkRange.getStatus().code(), - str::stream() << "Failed to parse 'migratedChunk' field in " - << "ConfigSvrCommitChunkMigration command request: " - << migratedChunkRange.getStatus().reason(), - migratedChunkRange.isOK()); - - // controlChunk is optional, so parse it if present. - boost::optional<StatusWith<ChunkRange>> controlChunkRange = boost::none; - if (cmdObj.hasField("controlChunk")) { - BSONObj controlChunkField = uassertStatusOK(getBSONField(cmdObj, "controlChunk")); - controlChunkRange = ChunkRange::fromBSON(controlChunkField); - uassert(controlChunkRange->getStatus().code(), - str::stream() - << "Failed to parse 'controlChunk' field in ConfigSvrCommitChunkMigration " - << "command request: " - << controlChunkRange->getStatus().reason(), - controlChunkRange->isOK()); - } + + CommitChunkMigrationRequest commitChunkMigrationRequest = + uassertStatusOK(CommitChunkMigrationRequest::createFromCommand(nss, cmdObj)); // Run operations under a nested lock as a hack to prevent yielding. When query/applyOps // commands are called, they will take a second lock, and the PlanExecutor will be unable to @@ -280,15 +224,16 @@ public: // Check that migratedChunk and controlChunk are where they should be, on fromShard. checkChunkIsOnShard(txn, nss, - migratedChunkRange.getValue().getMin(), - migratedChunkRange.getValue().getMax(), - fromShard); - if (controlChunkRange) { + commitChunkMigrationRequest.getMigratedChunkRange().getMin(), + commitChunkMigrationRequest.getMigratedChunkRange().getMax(), + commitChunkMigrationRequest.getFromShard()); + + if (commitChunkMigrationRequest.hasControlChunkRange()) { checkChunkIsOnShard(txn, nss, - controlChunkRange->getValue().getMin(), - controlChunkRange->getValue().getMax(), - fromShard); + commitChunkMigrationRequest.getControlChunkRange().getMin(), + commitChunkMigrationRequest.getControlChunkRange().getMax(), + commitChunkMigrationRequest.getFromShard()); } // Generate the new chunk version (CV). Query the current max CV of the collection. Use the @@ -320,9 +265,11 @@ public: ChunkVersion newMigratedChunkVersion = ChunkVersion(currentMaxVersion.majorVersion() + 1, 0, currentMaxVersion.epoch()); boost::optional<ChunkVersion> newControlChunkVersion = boost::none; - if (controlChunkRange) { + boost::optional<ChunkRange> newControlChunkRange = boost::none; + if (commitChunkMigrationRequest.hasControlChunkRange()) { newControlChunkVersion = ChunkVersion(currentMaxVersion.majorVersion() + 1, 1, currentMaxVersion.epoch()); + newControlChunkRange = commitChunkMigrationRequest.getControlChunkRange(); } auto applyOpsCommandResponse = grid.shardRegistry()->getConfigShard()->runCommand( @@ -330,12 +277,12 @@ public: ReadPreferenceSetting{ReadPreference::PrimaryOnly}, nss.db().toString(), makeCommitChunkApplyOpsCommand(nss, - migratedChunkRange, - controlChunkRange, + commitChunkMigrationRequest.getMigratedChunkRange(), + newControlChunkRange, newMigratedChunkVersion, newControlChunkVersion, - toShard, - fromShard), + commitChunkMigrationRequest.getToShard().toString(), + commitChunkMigrationRequest.getFromShard().toString()), Shard::RetryPolicy::kIdempotent); if (!applyOpsCommandResponse.isOK()) { @@ -347,7 +294,7 @@ public: } newMigratedChunkVersion.appendWithFieldForCommands(&result, "migratedChunkVersion"); - if (controlChunkRange) { + if (commitChunkMigrationRequest.hasControlChunkRange()) { newControlChunkVersion->appendWithFieldForCommands(&result, "controlChunkVersion"); } diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index cdc188dcd46..9b54e5d4fe3 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -45,6 +45,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/commit_chunk_migration_request_type.h" #include "mongo/s/shard_key_pattern.h" #include "mongo/s/stale_exception.h" #include "mongo/stdx/memory.h" @@ -284,38 +285,32 @@ Status MigrationSourceManager::commitDonateChunk(OperationContext* txn) { str::stream() << "commit clone failed due to " << commitCloneStatus.toString()}; } - BSONObjBuilder builder; - builder.append("_configsvrCommitChunkMigration", _args.getNss().ns()); - builder.append("fromShard", _args.getFromShardId().toString()); - builder.append("toShard", _args.getToShardId().toString()); - { - ChunkType migratedChunkType; - migratedChunkType.setMin(_args.getMinKey()); - migratedChunkType.setMax(_args.getMaxKey()); - builder.append("migratedChunk", migratedChunkType.toBSON()); - } + ChunkType migratedChunkType; + migratedChunkType.setMin(_args.getMinKey()); + migratedChunkType.setMax(_args.getMaxKey()); // If we have chunks left on the FROM shard, bump the version of one of them as well. This will // change the local collection major version, which indicates to other processes that the chunk // metadata has changed and they should refresh. - bool hasControlChunk = false; + boost::optional<ChunkType> controlChunkType = boost::none; if (_committedMetadata->getNumChunks() > 1) { - hasControlChunk = true; ChunkType differentChunk; invariant(_committedMetadata->getDifferentChunk(_args.getMinKey(), &differentChunk)); invariant(differentChunk.getMin().woCompare(_args.getMinKey()) != 0); - - { - ChunkType controlChunkType; - controlChunkType.setMin(differentChunk.getMin()); - controlChunkType.setMax(differentChunk.getMax()); - builder.append("controlChunk", controlChunkType.toBSON()); - } + controlChunkType = std::move(differentChunk); } else { log() << "moveChunk moved last chunk out for collection '" << _args.getNss().ns() << "'"; } + BSONObjBuilder builder; + CommitChunkMigrationRequest::appendAsCommand(&builder, + _args.getNss(), + _args.getFromShardId(), + _args.getToShardId(), + migratedChunkType, + controlChunkType); + builder.append(kWriteConcernField, kMajorityWriteConcern.toBSON()); MONGO_FAIL_POINT_PAUSE_WHILE_SET(hangBeforeCommitMigration); @@ -339,7 +334,7 @@ Status MigrationSourceManager::commitDonateChunk(OperationContext* txn) { // response and forget the migrated chunk. ChunkVersion uncommittedCollVersion; - if (hasControlChunk) { + if (controlChunkType) { uncommittedCollVersion = fassertStatusOK( 40084, ChunkVersion::parseFromBSONWithFieldForCommands( @@ -430,7 +425,7 @@ Status MigrationSourceManager::commitDonateChunk(OperationContext* txn) { << causedBy(commitChunkMigrationResponse.getStatus())}; } - if (hasControlChunk) { + if (controlChunkType) { ChunkVersion refreshedCollVersion = refreshedMetadata->getCollVersion(); if (refreshedCollVersion.majorVersion() <= previousMetadataCollVersion.majorVersion() || diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 44a314f46d3..02662435d88 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -60,6 +60,7 @@ env.Library( 'request_types/add_shard_to_zone_request_type.cpp', 'request_types/assign_key_range_to_zone_request_type.cpp', 'request_types/balance_chunk_request_type.cpp', + 'request_types/commit_chunk_migration_request_type.cpp', 'request_types/remove_shard_from_zone_request_type.cpp', 'chunk_diff.cpp', 'chunk_version.cpp', @@ -230,6 +231,7 @@ env.CppUnitTest('request_types_test', 'request_types/add_shard_to_zone_request_test.cpp', 'request_types/assign_key_range_to_zone_request_test.cpp', 'request_types/balance_chunk_request_test.cpp', + 'request_types/commit_chunk_migration_request_test.cpp', 'request_types/remove_shard_from_zone_request_test.cpp', ], LIBDEPS=[ diff --git a/src/mongo/s/request_types/commit_chunk_migration_request_test.cpp b/src/mongo/s/request_types/commit_chunk_migration_request_test.cpp new file mode 100644 index 00000000000..911dc0e7360 --- /dev/null +++ b/src/mongo/s/request_types/commit_chunk_migration_request_test.cpp @@ -0,0 +1,108 @@ +/** + * 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/bson/bsonmisc.h" +#include "mongo/bson/bsonobjbuilder.h" +#include "mongo/s/request_types/commit_chunk_migration_request_type.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { + +using unittest::assertGet; + +namespace { + +const auto kNamespaceString = NamespaceString("TestDB", "TestColl"); + +const auto kShardId0 = ShardId("shard0"); +const auto kShardId1 = ShardId("shard1"); + +const auto kKey0 = BSON("Key" << -100); +const auto kKey1 = BSON("Key" << 100); +const auto kKey2 = BSON("Key" << -50); +const auto kKey3 = BSON("Key" << 50); + +const char kConfigSvrCommitChunkMigration[] = "_configsvrCommitChunkMigration"; + +TEST(CommitChunkMigrationRequest, WithControlChunk) { + BSONObjBuilder builder; + + ChunkType migratedChunkType; + migratedChunkType.setMin(kKey0); + migratedChunkType.setMax(kKey1); + + ChunkType controlChunkTypeTemp; + controlChunkTypeTemp.setMin(kKey2); + controlChunkTypeTemp.setMax(kKey3); + boost::optional<ChunkType> controlChunkType = std::move(controlChunkTypeTemp); + + CommitChunkMigrationRequest::appendAsCommand( + &builder, kNamespaceString, kShardId0, kShardId1, migratedChunkType, controlChunkType); + + BSONObj cmdObj = builder.obj(); + + auto request = assertGet(CommitChunkMigrationRequest::createFromCommand( + NamespaceString(cmdObj[kConfigSvrCommitChunkMigration].String()), cmdObj)); + + ASSERT_EQ(kNamespaceString, request.getNss()); + ASSERT_EQ(kShardId0, request.getFromShard()); + ASSERT_EQ(kShardId1, request.getToShard()); + ASSERT_EQ(kKey0, request.getMigratedChunkRange().getMin()); + ASSERT_EQ(kKey1, request.getMigratedChunkRange().getMax()); + ASSERT(request.hasControlChunkRange()); + ASSERT_EQ(kKey2, request.getControlChunkRange().getMin()); + ASSERT_EQ(kKey3, request.getControlChunkRange().getMax()); +} + +TEST(CommitChunkMigrationRequest, WithoutControlChunk) { + BSONObjBuilder builder; + + ChunkType migratedChunkType; + migratedChunkType.setMin(kKey0); + migratedChunkType.setMax(kKey1); + + CommitChunkMigrationRequest::appendAsCommand( + &builder, kNamespaceString, kShardId0, kShardId1, migratedChunkType, boost::none); + + BSONObj cmdObj = builder.obj(); + + auto request = assertGet(CommitChunkMigrationRequest::createFromCommand( + NamespaceString(cmdObj[kConfigSvrCommitChunkMigration].String()), cmdObj)); + + ASSERT_EQ(kNamespaceString, request.getNss()); + ASSERT_EQ(kShardId0, request.getFromShard()); + ASSERT_EQ(kShardId1, request.getToShard()); + ASSERT_EQ(kKey0, request.getMigratedChunkRange().getMin()); + ASSERT_EQ(kKey1, request.getMigratedChunkRange().getMax()); + ASSERT(!request.hasControlChunkRange()); +} + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/request_types/commit_chunk_migration_request_type.cpp b/src/mongo/s/request_types/commit_chunk_migration_request_type.cpp new file mode 100644 index 00000000000..f03a105c5cf --- /dev/null +++ b/src/mongo/s/request_types/commit_chunk_migration_request_type.cpp @@ -0,0 +1,149 @@ +/** + * 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/s/request_types/commit_chunk_migration_request_type.h" + +#include "mongo/bson/util/bson_extract.h" + +namespace mongo { +namespace { + +const char kConfigSvrCommitChunkMigration[] = "_configsvrCommitChunkMigration"; +const char kFromShard[] = "fromShard"; +const char kToShard[] = "toShard"; +const char kMigratedChunk[] = "migratedChunk"; +const char kControlChunk[] = "controlChunk"; + +/** + * Attempts to parse a ChunkRange from "field" in "source". + */ +StatusWith<ChunkRange> extractChunkRange(const BSONObj& source, StringData field) { + BSONElement fieldElement; + auto status = bsonExtractTypedField(source, field, BSONType::Object, &fieldElement); + if (!status.isOK()) + return status; + + return ChunkRange::fromBSON(fieldElement.Obj()); +} + +/** + * Attempts to parse a ShardId from "field" in "source". + */ +StatusWith<ShardId> extractShardId(const BSONObj& source, StringData field) { + std::string stringResult; + + auto status = bsonExtractStringField(source, field, &stringResult); + if (!status.isOK()) { + return status; + } + + if (stringResult.empty()) { + return Status(ErrorCodes::UnsupportedFormat, + "The field '" + field.toString() + "' cannot be empty"); + } + + return ShardId(stringResult); +} + +} // namespace + +StatusWith<CommitChunkMigrationRequest> CommitChunkMigrationRequest::createFromCommand( + const NamespaceString& nss, const BSONObj& obj) { + + auto migratedChunkRange = extractChunkRange(obj, kMigratedChunk); + if (!migratedChunkRange.isOK()) { + return migratedChunkRange.getStatus(); + } + + CommitChunkMigrationRequest request(nss, std::move(migratedChunkRange.getValue())); + + { + auto fromShard = extractShardId(obj, kFromShard); + if (!fromShard.isOK()) { + return fromShard.getStatus(); + } + + request._fromShard = std::move(fromShard.getValue()); + } + + { + auto toShard = extractShardId(obj, kToShard); + if (!toShard.isOK()) { + return toShard.getStatus(); + } + + request._toShard = std::move(toShard.getValue()); + } + + { + // controlChunk is optional, so parse it if present. + if (obj.hasField(kControlChunk)) { + auto controlChunkRange = extractChunkRange(obj, kControlChunk); + if (!controlChunkRange.isOK()) { + return controlChunkRange.getStatus(); + } + + request._controlChunkRange = std::move(controlChunkRange.getValue()); + } + } + + return request; +} + +void CommitChunkMigrationRequest::appendAsCommand( + BSONObjBuilder* builder, + const NamespaceString& nss, + const ShardId& fromShard, + const ShardId& toShard, + const ChunkType& migratedChunkType, + const boost::optional<ChunkType>& controlChunkType) { + invariant(builder->asTempObj().isEmpty()); + invariant(nss.isValid()); + + builder->append(kConfigSvrCommitChunkMigration, nss.ns()); + builder->append(kFromShard, fromShard.toString()); + builder->append(kToShard, toShard.toString()); + builder->append(kMigratedChunk, migratedChunkType.toBSON()); + + if (controlChunkType) { + builder->append(kControlChunk, controlChunkType->toBSON()); + } +} + +const ChunkRange& CommitChunkMigrationRequest::getControlChunkRange() const { + invariant(_controlChunkRange); + return _controlChunkRange.get(); +} + +CommitChunkMigrationRequest::CommitChunkMigrationRequest(const NamespaceString& nss, + const ChunkRange& range) + : _nss(nss), _migratedChunkRange(range) {} + +} // namespace mongo diff --git a/src/mongo/s/request_types/commit_chunk_migration_request_type.h b/src/mongo/s/request_types/commit_chunk_migration_request_type.h new file mode 100644 index 00000000000..431cd20b631 --- /dev/null +++ b/src/mongo/s/request_types/commit_chunk_migration_request_type.h @@ -0,0 +1,102 @@ +/** + * 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/db/namespace_string.h" +#include "mongo/s/catalog/type_chunk.h" + +namespace mongo { + +/** + * Creates and parses commit chunk migration command BSON objects. + */ +class CommitChunkMigrationRequest { +public: + /** + * Parses the input command and produces a request corresponding to its arguments. + */ + static StatusWith<CommitChunkMigrationRequest> createFromCommand(const NamespaceString& nss, + const BSONObj& obj); + + /** + * Constructs a commitChunkMigration command with the specified parameters and writes it to + * the builder, without closing the builder. The builder must be empty, but callers are free + * to append more fields once the command has been constructed. + */ + static void appendAsCommand(BSONObjBuilder* builder, + const NamespaceString& nss, + const ShardId& fromShard, + const ShardId& toShard, + const ChunkType& migratedChunkType, + const boost::optional<ChunkType>& controlChunkType); + + const NamespaceString& getNss() const { + return _nss; + } + + const ShardId& getFromShard() const { + return _fromShard; + } + + const ShardId& getToShard() const { + return _toShard; + } + + const ChunkRange& getMigratedChunkRange() const { + return _migratedChunkRange; + } + + const ChunkRange& getControlChunkRange() const; + + bool hasControlChunkRange() { + return bool(_controlChunkRange); + } + +private: + CommitChunkMigrationRequest(const NamespaceString& nss, const ChunkRange& range); + + // The collection for which this request applies. + NamespaceString _nss; + + // The source shard name. + ShardId _fromShard; + + // The recipient shard name. + ShardId _toShard; + + // Range of migrated chunk being moved. + ChunkRange _migratedChunkRange; + + // Range of control chunk being moved, if it exists. + boost::optional<ChunkRange> _controlChunkRange; +}; + +} // namespace mongo |