diff options
15 files changed, 129 insertions, 156 deletions
diff --git a/src/mongo/db/catalog/drop_collection.cpp b/src/mongo/db/catalog/drop_collection.cpp index ccfc5050987..42ff085c9cf 100644 --- a/src/mongo/db/catalog/drop_collection.cpp +++ b/src/mongo/db/catalog/drop_collection.cpp @@ -56,10 +56,8 @@ Status dropCollection(OperationContext* opCtx, log() << "CMD: drop " << collectionName; } - const std::string dbname = collectionName.db().toString(); - return writeConflictRetry(opCtx, "drop", collectionName.ns(), [&] { - AutoGetDb autoDb(opCtx, dbname, MODE_X); + AutoGetDb autoDb(opCtx, collectionName.db(), MODE_X); Database* const db = autoDb.getDb(); Collection* coll = db ? db->getCollection(opCtx, collectionName) : nullptr; auto view = diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 4f69f3f5545..8261d9508c2 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -60,7 +60,6 @@ #include "mongo/db/query/plan_summary_stats.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/repl/replication_coordinator.h" -#include "mongo/db/s/collection_metadata.h" #include "mongo/db/s/collection_sharding_state.h" #include "mongo/db/s/sharding_state.h" #include "mongo/db/server_options.h" @@ -92,6 +91,72 @@ using IndexVersion = IndexDescriptor::IndexVersion; namespace dps = ::mongo::dotted_path_support; namespace mr { +namespace { + +/** + * Runs a count against the namespace specified by 'ns'. If the caller holds the global write lock, + * then this function does not acquire any additional locks. + */ +unsigned long long collectionCount(OperationContext* opCtx, + const NamespaceString& nss, + bool callerHoldsGlobalLock) { + boost::optional<AutoGetCollectionForReadCommand> ctx; + + Collection* coll = nullptr; + + // If the global write lock is held, we must avoid using AutoGetCollectionForReadCommand as it + // may lead to deadlock when waiting for a majority snapshot to be committed. See SERVER-24596. + if (callerHoldsGlobalLock) { + Database* db = DatabaseHolder::getDatabaseHolder().get(opCtx, nss.ns()); + if (db) { + coll = db->getCollection(opCtx, nss); + } + } else { + ctx.emplace(opCtx, nss); + coll = ctx->getCollection(); + } + + return coll ? coll->numRecords(opCtx) : 0; +} + +/** + * Emit that will be called by a js function. + */ +BSONObj fastEmit(const BSONObj& args, void* data) { + uassert(10077, "fastEmit takes 2 args", args.nFields() == 2); + uassert(13069, + "an emit can't be more than half max bson size", + args.objsize() < (BSONObjMaxUserSize / 2)); + + State* state = (State*)data; + if (args.firstElement().type() == Undefined) { + BSONObjBuilder b(args.objsize()); + b.appendNull(""); + BSONObjIterator i(args); + i.next(); + b.append(i.next()); + state->emit(b.obj()); + } else { + state->emit(args); + } + return BSONObj(); +} + +/** + * This function is called when we realize we cant use js mode for m/r on the 1st key. + */ +BSONObj _bailFromJS(const BSONObj& args, void* data) { + State* state = (State*)data; + state->bailFromJS(); + + // emit this particular key if there is one + if (!args.isEmpty()) { + fastEmit(args, data); + } + return BSONObj(); +} + +} // namespace AtomicUInt32 Config::JOB_NUMBER; @@ -140,9 +205,8 @@ BSONObj JSFinalizer::finalize(const BSONObj& o) { Scope::NoDBAccess no = s->disableDBAccess("can't access db inside finalize"); s->invokeSafe(_func.func(), &o, 0); - // don't want to use o.objsize() to size b - // since there are many cases where the point of finalize - // is converting many fields to 1 + // We don't want to use o.objsize() to size b since there are many cases where the point of + // finalize is converting many fields to 1 BSONObjBuilder b; b.append(o.firstElement()); s->append(b, "value", "__returnValue"); @@ -631,42 +695,15 @@ long long State::postProcessCollection(OperationContext* opCtx, return postProcessCollectionNonAtomic(opCtx, curOp, pm, holdingGlobalLock); } -namespace { - -// Runs a count against the namespace specified by 'ns'. If the caller holds the global write lock, -// then this function does not acquire any additional locks. -unsigned long long _collectionCount(OperationContext* opCtx, - const NamespaceString& nss, - bool callerHoldsGlobalLock) { - Collection* coll = nullptr; - boost::optional<AutoGetCollectionForReadCommand> ctx; - - // If the global write lock is held, we must avoid using AutoGetCollectionForReadCommand as it - // may lead to deadlock when waiting for a majority snapshot to be committed. See SERVER-24596. - if (callerHoldsGlobalLock) { - Database* db = DatabaseHolder::getDatabaseHolder().get(opCtx, nss.ns()); - if (db) { - coll = db->getCollection(opCtx, nss); - } - } else { - ctx.emplace(opCtx, nss); - coll = ctx->getCollection(); - } - - return coll ? coll->numRecords(opCtx) : 0; -} - -} // namespace - long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, CurOp* curOp, ProgressMeterHolder& pm, bool callerHoldsGlobalLock) { if (_config.outputOptions.finalNamespace == _config.tempNamespace) - return _collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock); + return collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock); if (_config.outputOptions.outType == Config::REPLACE || - _collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock) == 0) { + collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock) == 0) { // This must be global because we may write across different databases. Lock::GlobalWrite lock(opCtx); // replace: just rename from temp to final collection name, dropping previous collection @@ -686,8 +723,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, } else if (_config.outputOptions.outType == Config::MERGE) { // merge: upsert new docs into old collection { - const auto count = - _collectionCount(opCtx, _config.tempNamespace, callerHoldsGlobalLock); + const auto count = collectionCount(opCtx, _config.tempNamespace, callerHoldsGlobalLock); stdx::lock_guard<Client> lk(*opCtx->getClient()); curOp->setMessage_inlock( "m/r: merge post processing", "M/R Merge Post Processing Progress", count); @@ -706,8 +742,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, BSONList values; { - const auto count = - _collectionCount(opCtx, _config.tempNamespace, callerHoldsGlobalLock); + const auto count = collectionCount(opCtx, _config.tempNamespace, callerHoldsGlobalLock); stdx::lock_guard<Client> lk(*opCtx->getClient()); curOp->setMessage_inlock( "m/r: reduce post processing", "M/R Reduce Post Processing Progress", count); @@ -743,7 +778,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, pm.finished(); } - return _collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock); + return collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock); } /** @@ -968,7 +1003,7 @@ void State::init() { void State::switchMode(bool jsMode) { _jsMode = jsMode; if (jsMode) { - // emit function that stays in JS + // Emit function that stays in JS _scope->setFunction("emit", "function(key, value) {" " if (typeof(key) === 'object') {" @@ -989,8 +1024,8 @@ void State::switchMode(bool jsMode) { "}"); _scope->injectNative("_bailFromJS", _bailFromJS, this); } else { - // emit now populates C++ map - _scope->injectNative("emit", fast_emit, this); + // Emit now populates C++ map + _scope->injectNative("emit", fastEmit, this); } } @@ -1316,43 +1351,6 @@ void State::reduceAndSpillInMemoryStateIfNeeded() { } /** - * emit that will be called by js function - */ -BSONObj fast_emit(const BSONObj& args, void* data) { - uassert(10077, "fast_emit takes 2 args", args.nFields() == 2); - uassert(13069, - "an emit can't be more than half max bson size", - args.objsize() < (BSONObjMaxUserSize / 2)); - - State* state = (State*)data; - if (args.firstElement().type() == Undefined) { - BSONObjBuilder b(args.objsize()); - b.appendNull(""); - BSONObjIterator i(args); - i.next(); - b.append(i.next()); - state->emit(b.obj()); - } else { - state->emit(args); - } - return BSONObj(); -} - -/** - * function is called when we realize we cant use js mode for m/r on the 1st key - */ -BSONObj _bailFromJS(const BSONObj& args, void* data) { - State* state = (State*)data; - state->bailFromJS(); - - // emit this particular key if there is one - if (!args.isEmpty()) { - fast_emit(args, data); - } - return BSONObj(); -} - -/** * This class represents a map/reduce command executed on a single server */ class MapReduceCommand : public ErrmsgCommandDeprecated { @@ -1441,7 +1439,7 @@ public: bool showTotal = true; if (state.config().filter.isEmpty()) { const bool holdingGlobalLock = false; - const auto count = _collectionCount(opCtx, config.nss, holdingGlobalLock); + const auto count = collectionCount(opCtx, config.nss, holdingGlobalLock); progressTotal = (config.limit && static_cast<unsigned long long>(config.limit) < count) ? config.limit diff --git a/src/mongo/db/commands/mr.h b/src/mongo/db/commands/mr.h index ce708d6d62a..9ddc21d50e1 100644 --- a/src/mongo/db/commands/mr.h +++ b/src/mongo/db/commands/mr.h @@ -1,5 +1,3 @@ -// mr.h - /** * Copyright (C) 2012 10gen Inc. * @@ -177,7 +175,6 @@ private: // ----------------- - class TupleKeyCmp { public: TupleKeyCmp() {} @@ -410,9 +407,6 @@ protected: ScriptingFunction _reduceAndFinalizeAndInsert; }; -BSONObj fast_emit(const BSONObj& args, void* data); -BSONObj _bailFromJS(const BSONObj& args, void* data); - void addPrivilegesRequiredForMapReduce(const BasicCommand* commandTemplate, const std::string& dbname, const BSONObj& cmdObj, @@ -423,5 +417,5 @@ void addPrivilegesRequiredForMapReduce(const BasicCommand* commandTemplate, */ bool mrSupportsWriteConcern(const BSONObj& cmd); -} // end mr namespace -} +} // namespace mr +} // namespace mongo diff --git a/src/mongo/db/s/config/configsvr_add_shard_command.cpp b/src/mongo/db/s/config/configsvr_add_shard_command.cpp index bf5ed552446..09e9c1bc5a1 100644 --- a/src/mongo/db/s/config/configsvr_add_shard_command.cpp +++ b/src/mongo/db/s/config/configsvr_add_shard_command.cpp @@ -92,20 +92,19 @@ public: const std::string& unusedDbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrAddShard can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrAddShard can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); + + // Set the operation context read concern level to local for reads into the config database. + repl::ReadConcernArgs::get(opCtx) = + repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern); // Do not allow adding shards while a featureCompatibilityVersion upgrade or downgrade is in // progress (see SERVER-31231 for details). invariant(!opCtx->lockState()->isLocked()); Lock::SharedLock lk(opCtx->lockState(), FeatureCompatibilityVersion::fcvLock); - // Set the operation context read concern level to local for reads into the config database. - repl::ReadConcernArgs::get(opCtx) = - repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern); - auto swParsedRequest = AddShardRequest::parseFromConfigCommand(cmdObj); uassertStatusOK(swParsedRequest.getStatus()); auto parsedRequest = std::move(swParsedRequest.getValue()); diff --git a/src/mongo/db/s/config/configsvr_add_shard_to_zone_command.cpp b/src/mongo/db/s/config/configsvr_add_shard_to_zone_command.cpp index 5c50ee4ed73..96fb10d3f34 100644 --- a/src/mongo/db/s/config/configsvr_add_shard_to_zone_command.cpp +++ b/src/mongo/db/s/config/configsvr_add_shard_to_zone_command.cpp @@ -45,8 +45,6 @@ namespace mongo { namespace { -using std::string; - /** * Internal sharding command run on config servers to add a shard to zone. * @@ -92,10 +90,9 @@ public: const std::string& unusedDbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrAddShardToZone can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrAddShardToZone can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_commit_move_primary_command.cpp b/src/mongo/db/s/config/configsvr_commit_move_primary_command.cpp index a0502a83fb4..44533c91648 100644 --- a/src/mongo/db/s/config/configsvr_commit_move_primary_command.cpp +++ b/src/mongo/db/s/config/configsvr_commit_move_primary_command.cpp @@ -74,11 +74,9 @@ public: const std::string& dbName_unused, const BSONObj& cmdObj, BSONObjBuilder& result) override { - - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrCommitMovePrimary can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrCommitMovePrimary can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_drop_database_command.cpp b/src/mongo/db/s/config/configsvr_drop_database_command.cpp index cbd5d013755..b4c69aa8fcb 100644 --- a/src/mongo/db/s/config/configsvr_drop_database_command.cpp +++ b/src/mongo/db/s/config/configsvr_drop_database_command.cpp @@ -83,15 +83,13 @@ public: return cmdObj.firstElement().str(); } - bool run(OperationContext* opCtx, const std::string& dbname_unused, const BSONObj& cmdObj, BSONObjBuilder& result) { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrDropDatabase can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrDropDatabase can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = @@ -178,7 +176,7 @@ public: dbname, BSONObj(), ShardingCatalogClient::kMajorityWriteConcern) - .transitional_ignore(); + .ignore(); result.append("dropped", dbname); return true; diff --git a/src/mongo/db/s/config/configsvr_enable_sharding_command.cpp b/src/mongo/db/s/config/configsvr_enable_sharding_command.cpp index 198f108cc1d..64c0f462c3b 100644 --- a/src/mongo/db/s/config/configsvr_enable_sharding_command.cpp +++ b/src/mongo/db/s/config/configsvr_enable_sharding_command.cpp @@ -98,11 +98,9 @@ public: const std::string& dbname_unused, const BSONObj& cmdObj, BSONObjBuilder& result) { - - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrEnableSharding can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrEnableSharding can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp b/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp index 6c9fc840dad..495e68943a0 100644 --- a/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp +++ b/src/mongo/db/s/config/configsvr_merge_chunk_command.cpp @@ -46,8 +46,6 @@ namespace mongo { namespace { -using std::string; - /** * Internal sharding command run on config servers to merge a set of chunks. * @@ -103,10 +101,9 @@ public: const std::string& dbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrCommitChunkMerge can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrCommitChunkMerge can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = @@ -114,17 +111,17 @@ public: auto parsedRequest = uassertStatusOK(MergeChunkRequest::parseFromConfigCommand(cmdObj)); - Status mergeChunkResult = + uassertStatusOK( ShardingCatalogManager::get(opCtx)->commitChunkMerge(opCtx, parsedRequest.getNamespace(), parsedRequest.getEpoch(), parsedRequest.getChunkBoundaries(), parsedRequest.getShardName(), - parsedRequest.getValidAfter()); - - uassertStatusOK(mergeChunkResult); + parsedRequest.getValidAfter())); return true; } + } configsvrMergeChunkCmd; + } // namespace } // namespace mongo diff --git a/src/mongo/db/s/config/configsvr_move_chunk_command.cpp b/src/mongo/db/s/config/configsvr_move_chunk_command.cpp index 88748293160..f53426e9d1d 100644 --- a/src/mongo/db/s/config/configsvr_move_chunk_command.cpp +++ b/src/mongo/db/s/config/configsvr_move_chunk_command.cpp @@ -83,6 +83,9 @@ public: const std::string& unusedDbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { + uassert(ErrorCodes::IllegalOperation, + "_configsvrMoveChunk can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_move_primary_command.cpp b/src/mongo/db/s/config/configsvr_move_primary_command.cpp index 82b49d344af..478baa4cc97 100644 --- a/src/mongo/db/s/config/configsvr_move_primary_command.cpp +++ b/src/mongo/db/s/config/configsvr_move_primary_command.cpp @@ -107,11 +107,9 @@ public: const std::string& dbname_unused, const BSONObj& cmdObj, BSONObjBuilder& result) override { - - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrMovePrimary can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrMovePrimary can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_remove_shard_from_zone_command.cpp b/src/mongo/db/s/config/configsvr_remove_shard_from_zone_command.cpp index d6ebac6787a..8ccb7d93993 100644 --- a/src/mongo/db/s/config/configsvr_remove_shard_from_zone_command.cpp +++ b/src/mongo/db/s/config/configsvr_remove_shard_from_zone_command.cpp @@ -92,10 +92,9 @@ public: const std::string& unusedDbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrRemoveShardFromZone can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrRemoveShardFromZone can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_split_chunk_command.cpp b/src/mongo/db/s/config/configsvr_split_chunk_command.cpp index 6f5bd2dc10a..05b1cf32c80 100644 --- a/src/mongo/db/s/config/configsvr_split_chunk_command.cpp +++ b/src/mongo/db/s/config/configsvr_split_chunk_command.cpp @@ -101,10 +101,9 @@ public: const std::string& dbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrCommitChunkSplit can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrCommitChunkSplit can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/config/configsvr_update_zone_key_range_command.cpp b/src/mongo/db/s/config/configsvr_update_zone_key_range_command.cpp index 96a42bb7cb9..2a55e473701 100644 --- a/src/mongo/db/s/config/configsvr_update_zone_key_range_command.cpp +++ b/src/mongo/db/s/config/configsvr_update_zone_key_range_command.cpp @@ -94,10 +94,9 @@ public: const std::string& unusedDbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { - if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) { - uasserted(ErrorCodes::IllegalOperation, - "_configsvrAssignKeyRangeToZone can only be run on config servers"); - } + uassert(ErrorCodes::IllegalOperation, + "_configsvrAssignKeyRangeToZone can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); // Set the operation context read concern level to local for reads into the config database. repl::ReadConcernArgs::get(opCtx) = diff --git a/src/mongo/db/s/split_chunk_command.cpp b/src/mongo/db/s/split_chunk_command.cpp index 77b0cbacaf1..e092baa449a 100644 --- a/src/mongo/db/s/split_chunk_command.cpp +++ b/src/mongo/db/s/split_chunk_command.cpp @@ -141,19 +141,17 @@ public: OID expectedCollectionEpoch; uassertStatusOK(bsonExtractOIDField(cmdObj, "epoch", &expectedCollectionEpoch)); - auto statusWithOptionalChunkRange = splitChunk( - opCtx, nss, keyPatternObj, chunkRange, splitKeys, shardName, expectedCollectionEpoch); + auto topChunk = uassertStatusOK(splitChunk( + opCtx, nss, keyPatternObj, chunkRange, splitKeys, shardName, expectedCollectionEpoch)); - // If the split chunk returns something that is not Status::Ok(), then something failed. - uassertStatusOK(statusWithOptionalChunkRange.getStatus()); - - // Otherwise, we want to check whether or not top-chunk optimization should be performed. - // If yes, then we should have a ChunkRange that was returned. Regardless of whether it - // should be performed, we will return true. - if (auto topChunk = statusWithOptionalChunkRange.getValue()) { + // Otherwise, we want to check whether or not top-chunk optimization should be performed. If + // yes, then we should have a ChunkRange that was returned. Regardless of whether it should + // be performed, we will return true. + if (topChunk) { result.append("shouldMigrate", BSON("min" << topChunk->getMin() << "max" << topChunk->getMax())); } + return true; } |