From 3de973e1fd98473fbf1605e2d6039214aa15b2a4 Mon Sep 17 00:00:00 2001 From: Dianna Hohensee Date: Fri, 29 Jul 2016 14:37:22 -0400 Subject: SERVER-22671 adding migration status to serverStatus' sharding section --- .../resmokeconfig/suites/sharding_auth.yml | 1 + .../resmokeconfig/suites/sharding_auth_audit.yml | 1 + ...harding_last_stable_mongos_and_mixed_shards.yml | 3 +- jstests/sharding/migration_server_status.js | 76 ++++++++++++++++++++++ src/mongo/db/s/SConscript | 1 + src/mongo/db/s/active_migrations_registry.cpp | 30 +++++++++ src/mongo/db/s/active_migrations_registry.h | 10 ++- .../db/s/migration_chunk_cloner_source_legacy.cpp | 1 + src/mongo/db/s/migration_destination_manager.cpp | 70 +++++++++++++++----- src/mongo/db/s/migration_destination_manager.h | 35 ++++++++-- ...gration_destination_manager_legacy_commands.cpp | 37 +++++++---- src/mongo/db/s/migration_source_manager.cpp | 10 +++ src/mongo/db/s/migration_source_manager.h | 7 ++ src/mongo/db/s/migration_util.cpp | 65 ++++++++++++++++++ src/mongo/db/s/migration_util.h | 60 +++++++++++++++++ src/mongo/db/s/sharding_server_status.cpp | 8 +++ src/mongo/db/s/sharding_state.cpp | 4 ++ src/mongo/db/s/sharding_state.h | 8 +++ src/mongo/db/s/start_chunk_clone_request.cpp | 17 ++++- src/mongo/db/s/start_chunk_clone_request.h | 15 +++-- src/mongo/db/s/start_chunk_clone_request_test.cpp | 5 +- 21 files changed, 417 insertions(+), 47 deletions(-) create mode 100644 jstests/sharding/migration_server_status.js create mode 100644 src/mongo/db/s/migration_util.cpp create mode 100644 src/mongo/db/s/migration_util.h diff --git a/buildscripts/resmokeconfig/suites/sharding_auth.yml b/buildscripts/resmokeconfig/suites/sharding_auth.yml index 1ebddfc00bf..2a0b30cfe7c 100644 --- a/buildscripts/resmokeconfig/suites/sharding_auth.yml +++ b/buildscripts/resmokeconfig/suites/sharding_auth.yml @@ -21,6 +21,7 @@ selector: - jstests/sharding/migration_ignore_interrupts.js # SERVER-21713 - jstests/sharding/movechunk_interrupt_at_primary_stepdown.js # SERVER-21713 - jstests/sharding/movechunk_parallel.js # SERVER-21713 + - jstests/sharding/migration_server_status.js # SERVER-21713 # TODO: Enable when SERVER-22672 is complete - jstests/sharding/printShardingStatus.js diff --git a/buildscripts/resmokeconfig/suites/sharding_auth_audit.yml b/buildscripts/resmokeconfig/suites/sharding_auth_audit.yml index f4759f8067e..f22e49b50e0 100644 --- a/buildscripts/resmokeconfig/suites/sharding_auth_audit.yml +++ b/buildscripts/resmokeconfig/suites/sharding_auth_audit.yml @@ -21,6 +21,7 @@ selector: - jstests/sharding/migration_ignore_interrupts.js # SERVER-21713 - jstests/sharding/movechunk_interrupt_at_primary_stepdown.js # SERVER-21713 - jstests/sharding/movechunk_parallel.js # SERVER-21713 + - jstests/sharding/migration_server_status.js # SERVER-21713 # TODO: Enable when SERVER-22672 is complete - jstests/sharding/printShardingStatus.js diff --git a/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml b/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml index 8f786e4318b..882821c1490 100644 --- a/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml +++ b/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml @@ -57,7 +57,8 @@ selector: - jstests/sharding/cleanup_orphaned_cmd_during_movechunk_hashed.js - jstests/sharding/migration_failure.js - jstests/sharding/migration_with_source_ops.js - # Parallel migrations are not supported with 3.2 shards + # Testing features that do not exist on v3.2 shards. + - jstests/sharding/migration_server_status.js - jstests/sharding/movechunk_parallel.js executor: diff --git a/jstests/sharding/migration_server_status.js b/jstests/sharding/migration_server_status.js new file mode 100644 index 00000000000..f084f094dd2 --- /dev/null +++ b/jstests/sharding/migration_server_status.js @@ -0,0 +1,76 @@ +// +// Tests that serverStatus includes a migration status when called on the source shard of an active +// migration. +// + +load('./jstests/libs/chunk_manipulation_util.js'); + +(function() { + 'use strict'; + + var staticMongod = MongoRunner.runMongod({}); // For startParallelOps. + + var st = new ShardingTest({shards: 2, mongos: 1}); + + var mongos = st.s0; + var admin = mongos.getDB("admin"); + var coll = mongos.getCollection("db.coll"); + + assert.commandWorked(admin.runCommand({enableSharding: coll.getDB() + ""})); + st.ensurePrimaryShard(coll.getDB() + "", st.shard0.shardName); + assert.commandWorked(admin.runCommand({shardCollection: coll + "", key: {_id: 1}})); + assert.commandWorked(admin.runCommand({split: coll + "", middle: {_id: 0}})); + + // Pause the migration once it starts on both shards -- somewhat arbitrary pause point. + pauseMoveChunkAtStep(st.shard0, moveChunkStepNames.startedMoveChunk); + + var joinMoveChunk = moveChunkParallel( + staticMongod, st.s0.host, {_id: 1}, null, coll.getFullName(), st.shard1.shardName); + + var assertMigrationStatusOnServerStatus = function(serverStatusResult, + sourceShard, + destinationShard, + isDonorShard, + minKey, + maxKey, + collectionName) { + var migrationResult = serverStatusResult.sharding.migrations; + assert.eq(sourceShard, migrationResult.source); + assert.eq(destinationShard, migrationResult.destination); + assert.eq(isDonorShard, migrationResult.isDonorShard); + assert.eq(minKey, migrationResult.chunk.min); + assert.eq(maxKey, migrationResult.chunk.max); + assert.eq(collectionName, migrationResult.collection); + }; + + waitForMoveChunkStep(st.shard0, moveChunkStepNames.startedMoveChunk); + + // Source shard should return a migration status. + var shard0ServerStatus = st.shard0.getDB('admin').runCommand({serverStatus: 1}); + assert(shard0ServerStatus.sharding.migrations); + assertMigrationStatusOnServerStatus(shard0ServerStatus, + st.shard0.shardName, + st.shard1.shardName, + true, + {"_id": 0}, + {"_id": {"$maxKey": 1}}, + coll + ""); + + // Destination shard should not return any migration status. + var shard1ServerStatus = st.shard1.getDB('admin').runCommand({serverStatus: 1}); + assert(!shard1ServerStatus.sharding.migrations); + + // Mongos should never return a migration status. + var mongosServerStatus = st.s0.getDB('admin').runCommand({serverStatus: 1}); + assert(!mongosServerStatus.sharding.migrations); + + unpauseMoveChunkAtStep(st.shard0, moveChunkStepNames.startedMoveChunk); + joinMoveChunk(); + + // Migration is over, should no longer get a migration status. + var shard0ServerStatus = st.shard0.getDB('admin').runCommand({serverStatus: 1}); + assert(!shard0ServerStatus.sharding.migrations); + + st.stop(); + +})(); diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index d6369675030..d892b0ca8dd 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -55,6 +55,7 @@ env.Library( 'migration_chunk_cloner_source_legacy.cpp', 'migration_destination_manager.cpp', 'migration_source_manager.cpp', + 'migration_util.cpp', 'move_timing_helper.cpp', 'operation_sharding_state.cpp', 'shard_identity_rollback_notifier.cpp', diff --git a/src/mongo/db/s/active_migrations_registry.cpp b/src/mongo/db/s/active_migrations_registry.cpp index 70e69a05f66..93f06c813db 100644 --- a/src/mongo/db/s/active_migrations_registry.cpp +++ b/src/mongo/db/s/active_migrations_registry.cpp @@ -31,6 +31,9 @@ #include "mongo/db/s/active_migrations_registry.h" #include "mongo/base/status_with.h" +#include "mongo/db/db_raii.h" +#include "mongo/db/s/collection_sharding_state.h" +#include "mongo/db/s/migration_source_manager.h" #include "mongo/util/assert_util.h" namespace mongo { @@ -68,6 +71,33 @@ boost::optional ActiveMigrationsRegistry::getActiveMigrationNss return boost::none; } +BSONObj ActiveMigrationsRegistry::getActiveMigrationStatusReport(OperationContext* txn) { + boost::optional nss; + { + stdx::lock_guard lk(_mutex); + + if (_activeMoveChunkState) { + nss = _activeMoveChunkState->args.getNss(); + } + } + + // The state of the MigrationSourceManager could change between taking and releasing the mutex + // above and then taking the collection lock here, but that's fine because it isn't important + // to return information on a migration that just ended or started. This is just best effort and + // desireable for reporting, and then diagnosing, migrations that are stuck. + if (nss) { + // Lock the collection so nothing changes while we're getting the migration report. + AutoGetCollection autoColl(txn, nss.get(), MODE_IS); + + auto css = CollectionShardingState::get(txn, nss.get()); + if (css && css->getMigrationSourceManager()) { + return css->getMigrationSourceManager()->getMigrationStatusReport(); + } + } + + return BSONObj(); +} + void ActiveMigrationsRegistry::_clearMigration() { stdx::lock_guard lk(_mutex); invariant(_activeMoveChunkState); diff --git a/src/mongo/db/s/active_migrations_registry.h b/src/mongo/db/s/active_migrations_registry.h index 37ccbb1b9b9..1415a4c469f 100644 --- a/src/mongo/db/s/active_migrations_registry.h +++ b/src/mongo/db/s/active_migrations_registry.h @@ -63,7 +63,7 @@ public: * arguments, returns a ScopedRegisterMigration, which can be used to join the already running * migration. * - * Othwerwise returns a ConflictingOperationInProgress error. + * Otherwise returns a ConflictingOperationInProgress error. */ StatusWith registerMigration(const MoveChunkRequest& args); @@ -73,6 +73,14 @@ public: */ boost::optional getActiveMigrationNss(); + /** + * Returns a report on the active migration if there currently is one. Otherwise, returns an + * empty BSONObj. + * + * Takes an IS lock on the namespace of the active migration, if one is active. + */ + BSONObj getActiveMigrationStatusReport(OperationContext* txn); + private: friend class ScopedRegisterMigration; diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp index 08721b06419..2a2d2e77d3e 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp @@ -212,6 +212,7 @@ Status MigrationChunkClonerSourceLegacy::startClone(OperationContext* txn) { _sessionId, _args.getConfigServerCS(), _donorCS, + _args.getFromShardId(), _args.getToShardId(), _args.getMinKey(), _args.getMaxKey(), diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index 3e4ad61b94a..87b45e9df03 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -53,6 +53,7 @@ #include "mongo/db/repl/replication_coordinator_global.h" #include "mongo/db/s/collection_metadata.h" #include "mongo/db/s/collection_sharding_state.h" +#include "mongo/db/s/migration_util.h" #include "mongo/db/s/move_timing_helper.h" #include "mongo/db/s/sharded_connection_info.h" #include "mongo/db/s/sharding_state.h" @@ -216,6 +217,10 @@ void MigrationDestinationManager::setState(State newState) { bool MigrationDestinationManager::isActive() const { stdx::lock_guard lk(_mutex); + return _isActive_inlock(); +} + +bool MigrationDestinationManager::_isActive_inlock() const { return _sessionId.is_initialized(); } @@ -228,8 +233,8 @@ void MigrationDestinationManager::report(BSONObjBuilder& b) { b.append("sessionId", _sessionId->toString()); } - b.append("ns", _ns); - b.append("from", _from); + b.append("ns", _nss.ns()); + b.append("from", _fromShardConnString.toString()); b.append("min", _min); b.append("max", _max); b.append("shardKeyPattern", _shardKeyPattern); @@ -248,9 +253,21 @@ void MigrationDestinationManager::report(BSONObjBuilder& b) { bb.done(); } +BSONObj MigrationDestinationManager::getMigrationStatusReport() { + stdx::lock_guard lk(_mutex); + if (_isActive_inlock()) { + return migrationutil::makeMigrationStatusDocument( + _nss, _fromShard, _toShard, false, _min, _max); + } else { + return BSONObj(); + } +} + Status MigrationDestinationManager::start(const string& ns, const MigrationSessionId& sessionId, - const string& fromShard, + const ConnectionString& fromShardConnString, + const ShardId& fromShard, + const ShardId& toShard, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, @@ -262,9 +279,9 @@ Status MigrationDestinationManager::start(const string& ns, return Status(ErrorCodes::ConflictingOperationInProgress, str::stream() << "Active migration already in progress " << "ns: " - << _ns + << _nss.ns() << ", from: " - << _from + << _fromShardConnString.toString() << ", min: " << _min << ", max: " @@ -274,8 +291,10 @@ Status MigrationDestinationManager::start(const string& ns, _state = READY; _errmsg = ""; - _ns = ns; - _from = fromShard; + _nss = NamespaceString(ns); + _fromShardConnString = fromShardConnString; + _fromShard = fromShard; + _toShard = toShard; _min = min; _max = max; _shardKeyPattern = shardKeyPattern; @@ -296,11 +315,18 @@ Status MigrationDestinationManager::start(const string& ns, _migrateThreadHandle.join(); } - _migrateThreadHandle = stdx::thread( - [this, ns, sessionId, min, max, shardKeyPattern, fromShard, epoch, writeConcern]() { - _migrateThread( - ns, sessionId, min, max, shardKeyPattern, fromShard, epoch, writeConcern); - }); + _migrateThreadHandle = stdx::thread([this, + ns, + sessionId, + min, + max, + shardKeyPattern, + fromShardConnString, + epoch, + writeConcern]() { + _migrateThread( + ns, sessionId, min, max, shardKeyPattern, fromShardConnString, epoch, writeConcern); + }); return Status::OK(); } @@ -357,7 +383,7 @@ void MigrationDestinationManager::_migrateThread(std::string ns, BSONObj min, BSONObj max, BSONObj shardKeyPattern, - std::string fromShard, + ConnectionString fromShardConnString, OID epoch, WriteConcernOptions writeConcern) { Client::initThread("migrateThread"); @@ -369,8 +395,15 @@ void MigrationDestinationManager::_migrateThread(std::string ns, } try { - _migrateDriver( - opCtx.get(), ns, sessionId, min, max, shardKeyPattern, fromShard, epoch, writeConcern); + _migrateDriver(opCtx.get(), + ns, + sessionId, + min, + max, + shardKeyPattern, + fromShardConnString, + epoch, + writeConcern); } catch (std::exception& e) { { stdx::lock_guard sl(_mutex); @@ -408,7 +441,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, - const std::string& fromShard, + const ConnectionString& fromShardConnString, const OID& epoch, const WriteConcernOptions& writeConcern) { invariant(isActive()); @@ -416,7 +449,8 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn, invariant(!max.isEmpty()); log() << "starting receiving-end of migration of chunk " << min << " -> " << max - << " for collection " << ns << " from " << fromShard << " at epoch " << epoch.toString(); + << " for collection " << ns << " from " << fromShardConnString << " at epoch " + << epoch.toString(); string errmsg; MoveTimingHelper timing(txn, "to", ns, min, max, 6 /* steps */, &errmsg, ShardId(), ShardId()); @@ -431,7 +465,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn, invariant(initialState == READY); - ScopedDbConnection conn(fromShard); + ScopedDbConnection conn(fromShardConnString); // Just tests the connection conn->getLastError(); diff --git a/src/mongo/db/s/migration_destination_manager.h b/src/mongo/db/s/migration_destination_manager.h index 4f928ab99fd..12e437f6ed4 100644 --- a/src/mongo/db/s/migration_destination_manager.h +++ b/src/mongo/db/s/migration_destination_manager.h @@ -34,7 +34,10 @@ #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/oid.h" +#include "mongo/client/connection_string.h" +#include "mongo/db/namespace_string.h" #include "mongo/db/s/migration_session_id.h" +#include "mongo/s/shard_id.h" #include "mongo/stdx/condition_variable.h" #include "mongo/stdx/mutex.h" #include "mongo/stdx/thread.h" @@ -42,7 +45,6 @@ namespace mongo { -class NamespaceString; class OperationContext; class Status; struct WriteConcernOptions; @@ -66,6 +68,9 @@ public: State getState() const; void setState(State newState); + /** + * Checks whether the MigrationDestinationManager is currently handling a migration. + */ bool isActive() const; /** @@ -73,12 +78,20 @@ public: */ void report(BSONObjBuilder& b); + /** + * Returns a report on the active migration, if the migration is active. Otherwise return an + * empty BSONObj. + */ + BSONObj getMigrationStatusReport(); + /** * Returns OK if migration started successfully. */ Status start(const std::string& ns, const MigrationSessionId& sessionId, - const std::string& fromShard, + const ConnectionString& fromShardConnString, + const ShardId& fromShard, + const ShardId& toShard, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, @@ -98,7 +111,7 @@ private: BSONObj min, BSONObj max, BSONObj shardKeyPattern, - std::string fromShard, + ConnectionString fromShardConnString, OID epoch, WriteConcernOptions writeConcern); @@ -108,7 +121,7 @@ private: const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, - const std::string& fromShard, + const ConnectionString& fromShardConnString, const OID& epoch, const WriteConcernOptions& writeConcern); @@ -159,6 +172,14 @@ private: const BSONObj& max, const OID& epoch); + /** + * Checks whether the MigrationDestinationManager is currently handling a migration by checking + * that the migration "_sessionId" is initialized. + * + * Expects the caller to have the class _mutex locked! + */ + bool _isActive_inlock() const; + // Mutex to guard all fields mutable stdx::mutex _mutex; @@ -170,8 +191,10 @@ private: stdx::thread _migrateThreadHandle; - std::string _ns; - std::string _from; + NamespaceString _nss; + ConnectionString _fromShardConnString; + ShardId _fromShard; + ShardId _toShard; BSONObj _min; BSONObj _max; diff --git a/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp b/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp index 6c528147df9..dca0a9c43bd 100644 --- a/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp +++ b/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp @@ -126,10 +126,9 @@ public: } } - if (!cmdObj["toShardName"].eoo()) { - dassert(cmdObj["toShardName"].type() == String); - shardingState->setShardName(cmdObj["toShardName"].String()); - } + const ShardId toShard(cmdObj["toShardName"].String()); + shardingState->setShardName(toShard.toString()); + const ShardId fromShard(cmdObj["fromShardName"].String()); const string ns = cmdObj.firstElement().String(); @@ -158,20 +157,30 @@ public: BSONObj shardKeyPattern = cmdObj["shardKeyPattern"].Obj().getOwned(); - const string fromShard(cmdObj["from"].String()); + auto statusWithFromShardConnectionString = ConnectionString::parse(cmdObj["from"].String()); + if (!statusWithFromShardConnectionString.isOK()) { + errmsg = str::stream() << "cannot start recv'ing chunk " + << "[" << min << "," << max << ")" + << causedBy(statusWithFromShardConnectionString.getStatus()); + + warning() << errmsg; + return false; + } const MigrationSessionId migrationSessionId( uassertStatusOK(MigrationSessionId::extractFromBSON(cmdObj))); - Status startStatus = - shardingState->migrationDestinationManager()->start(ns, - migrationSessionId, - fromShard, - min, - max, - shardKeyPattern, - currentVersion.epoch(), - writeConcern); + Status startStatus = shardingState->migrationDestinationManager()->start( + ns, + migrationSessionId, + statusWithFromShardConnectionString.getValue(), + fromShard, + toShard, + min, + max, + shardKeyPattern, + currentVersion.epoch(), + writeConcern); if (!startStatus.isOK()) { return appendCommandStatus(result, startStatus); } diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index 3ee4660a932..f1bb4701e34 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -38,6 +38,7 @@ #include "mongo/db/s/collection_metadata.h" #include "mongo/db/s/collection_sharding_state.h" #include "mongo/db/s/migration_chunk_cloner_source_legacy.h" +#include "mongo/db/s/migration_util.h" #include "mongo/db/s/operation_sharding_state.h" #include "mongo/db/s/sharding_state.h" #include "mongo/db/s/sharding_state_recovery.h" @@ -533,4 +534,13 @@ void MigrationSourceManager::_cleanup(OperationContext* txn) { _state = kDone; } +BSONObj MigrationSourceManager::getMigrationStatusReport() const { + return migrationutil::makeMigrationStatusDocument(_args.getNss(), + _args.getFromShardId(), + _args.getToShardId(), + true, + _args.getMinKey(), + _args.getMaxKey()); +} + } // namespace mongo diff --git a/src/mongo/db/s/migration_source_manager.h b/src/mongo/db/s/migration_source_manager.h index a5f1260c098..99ce842cdbd 100644 --- a/src/mongo/db/s/migration_source_manager.h +++ b/src/mongo/db/s/migration_source_manager.h @@ -172,6 +172,13 @@ public: return _critSecSignal; } + /** + * Returns a report on the active migration. + * + * Must be called with some form of lock on the collection namespace. + */ + BSONObj getMigrationStatusReport() const; + private: // Used to track the current state of the source manager. See the methods above, which have // comments explaining the various state transitions. diff --git a/src/mongo/db/s/migration_util.cpp b/src/mongo/db/s/migration_util.cpp new file mode 100644 index 00000000000..0eccd40f3db --- /dev/null +++ b/src/mongo/db/s/migration_util.cpp @@ -0,0 +1,65 @@ +/** + * 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 . + * + * 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/s/migration_util.h" + +#include "mongo/bson/bsonobj.h" +#include "mongo/bson/bsonobjbuilder.h" +#include "mongo/db/namespace_string.h" +#include "mongo/s/catalog/type_chunk.h" + +namespace mongo { +namespace migrationutil { +namespace { + +const char kSourceShard[] = "source"; +const char kDestinationShard[] = "destination"; +const char kIsDonorShard[] = "isDonorShard"; +const char kChunk[] = "chunk"; +const char kCollection[] = "collection"; +} + +BSONObj makeMigrationStatusDocument(const NamespaceString& nss, + const ShardId& fromShard, + const ShardId& toShard, + const bool& isDonorShard, + const BSONObj& min, + const BSONObj& max) { + BSONObjBuilder builder; + builder.append(kSourceShard, fromShard.toString()); + builder.append(kDestinationShard, toShard.toString()); + builder.append(kIsDonorShard, isDonorShard); + builder.append(kChunk, BSON(ChunkType::min(min) << ChunkType::max(max))); + builder.append(kCollection, nss.ns()); + return builder.obj(); +} + +} // namespace migrationutil +} // namespace mongo diff --git a/src/mongo/db/s/migration_util.h b/src/mongo/db/s/migration_util.h new file mode 100644 index 00000000000..20369bab790 --- /dev/null +++ b/src/mongo/db/s/migration_util.h @@ -0,0 +1,60 @@ +/** + * 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 . + * + * 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 + +namespace mongo { + +class BSONObj; +class NamespaceString; +class ShardId; + +namespace migrationutil { + +/** + * Creates a report document with the provided parameters: + * + * { + * source: "shard0000" + * destination: "shard0001" + * isDonorShard: true or false + * chunk: {"min": , "max": } + * collection: "dbName.collName" + * } + * + */ +BSONObj makeMigrationStatusDocument(const NamespaceString& nss, + const ShardId& fromShard, + const ShardId& toShard, + const bool& isDonorShard, + const BSONObj& min, + const BSONObj& max); + +} // namespace shardutil + +} // namespace mongo diff --git a/src/mongo/db/s/sharding_server_status.cpp b/src/mongo/db/s/sharding_server_status.cpp index 4cb8c4f047e..8f58e24600b 100644 --- a/src/mongo/db/s/sharding_server_status.cpp +++ b/src/mongo/db/s/sharding_server_status.cpp @@ -55,6 +55,14 @@ public: shardingState->getConfigServer(txn).toString()); Grid::get(txn)->configOpTime().append(&result, "lastSeenConfigServerOpTime"); + + // Get a migration status report if a migration is active for which this is the source + // shard. ShardingState::getActiveMigrationStatusReport will take an IS lock on the + // namespace of the active migration if there is one that is active. + BSONObj migrationStatus = ShardingState::get(txn)->getActiveMigrationStatusReport(txn); + if (!migrationStatus.isEmpty()) { + result.append("migrations", migrationStatus); + } } return result.obj(); diff --git a/src/mongo/db/s/sharding_state.cpp b/src/mongo/db/s/sharding_state.cpp index d5e57b8357d..16898c65b21 100644 --- a/src/mongo/db/s/sharding_state.cpp +++ b/src/mongo/db/s/sharding_state.cpp @@ -751,6 +751,10 @@ boost::optional ShardingState::getActiveMigrationNss() { return _activeMigrationsRegistry.getActiveMigrationNss(); } +BSONObj ShardingState::getActiveMigrationStatusReport(OperationContext* txn) { + return _activeMigrationsRegistry.getActiveMigrationStatusReport(txn); +} + void ShardingState::appendInfo(OperationContext* txn, BSONObjBuilder& builder) { const bool isEnabled = enabled(); builder.appendBool("enabled", isEnabled); diff --git a/src/mongo/db/s/sharding_state.h b/src/mongo/db/s/sharding_state.h index 28eb837c215..66711e4d29f 100644 --- a/src/mongo/db/s/sharding_state.h +++ b/src/mongo/db/s/sharding_state.h @@ -227,6 +227,14 @@ public: */ boost::optional getActiveMigrationNss(); + /** + * Get a migration status report from the migration registry. If no migration is active, this + * returns an empty BSONObj. + * + * Takes an IS lock on the namespace of the active migration, if one is active. + */ + BSONObj getActiveMigrationStatusReport(OperationContext* txn); + /** * For testing only. Mock the initialization method used by initializeFromConfigConnString and * initializeFromShardIdentity after all checks are performed. diff --git a/src/mongo/db/s/start_chunk_clone_request.cpp b/src/mongo/db/s/start_chunk_clone_request.cpp index 9aa27ba5fc9..757a818f66f 100644 --- a/src/mongo/db/s/start_chunk_clone_request.cpp +++ b/src/mongo/db/s/start_chunk_clone_request.cpp @@ -33,7 +33,6 @@ #include "mongo/base/status_with.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/util/bson_extract.h" -#include "mongo/s/shard_id.h" namespace mongo { namespace { @@ -41,6 +40,7 @@ namespace { const char kRecvChunkStart[] = "_recvChunkStart"; const char kConfigServerConnectionString[] = "configdb"; const char kFromShardConnectionString[] = "from"; +const char kFromShardId[] = "fromShardName"; const char kToShardId[] = "toShardName"; const char kChunkMinKey[] = "min"; const char kChunkMaxKey[] = "max"; @@ -104,7 +104,18 @@ StatusWith StartChunkCloneRequest::createFromCommand(Nam } { - Status status = bsonExtractStringField(obj, kToShardId, &request._toShardId); + std::string fromShard; + Status status = bsonExtractStringField(obj, kFromShardId, &fromShard); + request._fromShardId = fromShard; + if (!status.isOK()) { + return status; + } + } + + { + std::string toShard; + Status status = bsonExtractStringField(obj, kToShardId, &toShard); + request._toShardId = toShard; if (!status.isOK()) { return status; } @@ -161,6 +172,7 @@ void StartChunkCloneRequest::appendAsCommand( const MigrationSessionId& sessionId, const ConnectionString& configServerConnectionString, const ConnectionString& fromShardConnectionString, + const ShardId& fromShardId, const ShardId& toShardId, const BSONObj& chunkMinKey, const BSONObj& chunkMaxKey, @@ -174,6 +186,7 @@ void StartChunkCloneRequest::appendAsCommand( sessionId.append(builder); builder->append(kConfigServerConnectionString, configServerConnectionString.toString()); builder->append(kFromShardConnectionString, fromShardConnectionString.toString()); + builder->append(kFromShardId, fromShardId.toString()); builder->append(kToShardId, toShardId.toString()); builder->append(kChunkMinKey, chunkMinKey); builder->append(kChunkMaxKey, chunkMaxKey); diff --git a/src/mongo/db/s/start_chunk_clone_request.h b/src/mongo/db/s/start_chunk_clone_request.h index 8a7b43d5f27..12533f287f6 100644 --- a/src/mongo/db/s/start_chunk_clone_request.h +++ b/src/mongo/db/s/start_chunk_clone_request.h @@ -34,13 +34,14 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/s/migration_session_id.h" #include "mongo/s/migration_secondary_throttle_options.h" +#include "mongo/s/shard_id.h" namespace mongo { class BSONObjBuilder; template class StatusWith; -class ShardId; + /** * Parses the arguments for a start chunk clone operation. */ @@ -62,6 +63,7 @@ public: const MigrationSessionId& sessionId, const ConnectionString& configServerConnectionString, const ConnectionString& fromShardConnectionString, + const ShardId& fromShardId, const ShardId& toShardId, const BSONObj& chunkMinKey, const BSONObj& chunkMaxKey, @@ -84,7 +86,11 @@ public: return _fromShardCS; } - const std::string& getToShardId() const { + const ShardId& getFromShardId() const { + return _fromShardId; + } + + const ShardId& getToShardId() const { return _toShardId; } @@ -123,8 +129,9 @@ private: // The source host and port ConnectionString _fromShardCS; - // The recipient shard id - std::string _toShardId; + // The recipient and destination shard IDs. + ShardId _fromShardId; + ShardId _toShardId; // Exact min and max key of the chunk being moved BSONObj _minKey; diff --git a/src/mongo/db/s/start_chunk_clone_request_test.cpp b/src/mongo/db/s/start_chunk_clone_request_test.cpp index 342d49d9130..92b797ec9cd 100644 --- a/src/mongo/db/s/start_chunk_clone_request_test.cpp +++ b/src/mongo/db/s/start_chunk_clone_request_test.cpp @@ -52,6 +52,7 @@ TEST(StartChunkCloneRequest, CreateAsCommandComplete) { sessionId, assertGet(ConnectionString::parse("TestConfigRS/CS1:12345,CS2:12345,CS3:12345")), assertGet(ConnectionString::parse("TestDonorRS/Donor1:12345,Donor2:12345,Donor3:12345")), + ShardId("shard0001"), ShardId("shard0002"), BSON("Key" << -100), BSON("Key" << 100), @@ -62,6 +63,7 @@ TEST(StartChunkCloneRequest, CreateAsCommandComplete) { auto request = assertGet(StartChunkCloneRequest::createFromCommand( NamespaceString(cmdObj["_recvChunkStart"].String()), cmdObj)); + ASSERT_EQ("TestDB.TestColl", request.getNss().ns()); ASSERT_EQ(sessionId.toString(), request.getSessionId().toString()); ASSERT(sessionId.matches(request.getSessionId())); @@ -70,7 +72,8 @@ TEST(StartChunkCloneRequest, CreateAsCommandComplete) { assertGet(ConnectionString::parse("TestDonorRS/Donor1:12345,Donor2:12345,Donor3:12345")) .toString(), request.getFromShardConnectionString().toString()); - ASSERT_EQ("shard0002", request.getToShardId()); + ASSERT_EQ("shard0001", request.getFromShardId().toString()); + ASSERT_EQ("shard0002", request.getToShardId().toString()); ASSERT_BSONOBJ_EQ(BSON("Key" << -100), request.getMinKey()); ASSERT_BSONOBJ_EQ(BSON("Key" << 100), request.getMaxKey()); ASSERT_BSONOBJ_EQ(BSON("Key" << 1), request.getShardKeyPattern()); -- cgit v1.2.1