summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@10gen.com>2016-07-29 14:37:22 -0400
committerDianna Hohensee <dianna.hohensee@10gen.com>2016-08-24 11:48:59 -0400
commit3de973e1fd98473fbf1605e2d6039214aa15b2a4 (patch)
tree47df21978e84da9afc39140e325f630189fc4286
parent30e9b7dba2c530074f1758e43324d1c082ec45ce (diff)
downloadmongo-3de973e1fd98473fbf1605e2d6039214aa15b2a4.tar.gz
SERVER-22671 adding migration status to serverStatus' sharding section
-rw-r--r--buildscripts/resmokeconfig/suites/sharding_auth.yml1
-rw-r--r--buildscripts/resmokeconfig/suites/sharding_auth_audit.yml1
-rw-r--r--buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml3
-rw-r--r--jstests/sharding/migration_server_status.js76
-rw-r--r--src/mongo/db/s/SConscript1
-rw-r--r--src/mongo/db/s/active_migrations_registry.cpp30
-rw-r--r--src/mongo/db/s/active_migrations_registry.h10
-rw-r--r--src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp1
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp70
-rw-r--r--src/mongo/db/s/migration_destination_manager.h35
-rw-r--r--src/mongo/db/s/migration_destination_manager_legacy_commands.cpp37
-rw-r--r--src/mongo/db/s/migration_source_manager.cpp10
-rw-r--r--src/mongo/db/s/migration_source_manager.h7
-rw-r--r--src/mongo/db/s/migration_util.cpp65
-rw-r--r--src/mongo/db/s/migration_util.h60
-rw-r--r--src/mongo/db/s/sharding_server_status.cpp8
-rw-r--r--src/mongo/db/s/sharding_state.cpp4
-rw-r--r--src/mongo/db/s/sharding_state.h8
-rw-r--r--src/mongo/db/s/start_chunk_clone_request.cpp17
-rw-r--r--src/mongo/db/s/start_chunk_clone_request.h15
-rw-r--r--src/mongo/db/s/start_chunk_clone_request_test.cpp5
21 files changed, 417 insertions, 47 deletions
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<NamespaceString> ActiveMigrationsRegistry::getActiveMigrationNss
return boost::none;
}
+BSONObj ActiveMigrationsRegistry::getActiveMigrationStatusReport(OperationContext* txn) {
+ boost::optional<NamespaceString> nss;
+ {
+ stdx::lock_guard<stdx::mutex> 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<stdx::mutex> 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<ScopedRegisterMigration> registerMigration(const MoveChunkRequest& args);
@@ -73,6 +73,14 @@ public:
*/
boost::optional<NamespaceString> 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<stdx::mutex> 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<stdx::mutex> 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<stdx::mutex> 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;
/**
@@ -74,11 +79,19 @@ 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 <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/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 <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
+
+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": <MinKey>, "max": <MaxKey>}
+ * 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<NamespaceString> 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
@@ -228,6 +228,14 @@ public:
boost::optional<NamespaceString> 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> 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 <typename T>
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());