summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/base/error_codes.err1
-rw-r--r--src/mongo/db/s/chunk_move_write_concern_options.cpp58
-rw-r--r--src/mongo/db/s/chunk_move_write_concern_options.h43
-rw-r--r--src/mongo/db/s/cleanup_orphaned_cmd.cpp44
-rw-r--r--src/mongo/db/s/move_chunk_command.cpp20
-rw-r--r--src/mongo/db/write_concern_options.cpp62
-rw-r--r--src/mongo/db/write_concern_options.h29
-rw-r--r--src/mongo/s/SConscript15
-rw-r--r--src/mongo/s/chunk_diff_test.cpp5
-rw-r--r--src/mongo/s/chunk_version.h1
-rw-r--r--src/mongo/s/commands/cluster_move_chunk_cmd.cpp18
-rw-r--r--src/mongo/s/d_migrate.cpp8
-rw-r--r--src/mongo/s/migration_secondary_throttle_options.cpp147
-rw-r--r--src/mongo/s/migration_secondary_throttle_options.h127
-rw-r--r--src/mongo/s/migration_secondary_throttle_options_test.cpp137
15 files changed, 502 insertions, 213 deletions
diff --git a/src/mongo/base/error_codes.err b/src/mongo/base/error_codes.err
index 43fdefa1c50..d541dfa42d5 100644
--- a/src/mongo/base/error_codes.err
+++ b/src/mongo/base/error_codes.err
@@ -98,7 +98,6 @@ error_code("NotSecondary", 95)
error_code("OperationFailed", 96)
error_code("NoProjectionFound", 97)
error_code("DBPathInUse", 98)
-error_code("WriteConcernNotDefined", 99)
error_code("CannotSatisfyWriteConcern", 100)
error_code("OutdatedClient", 101)
error_code("IncompatibleAuditMetadata", 102)
diff --git a/src/mongo/db/s/chunk_move_write_concern_options.cpp b/src/mongo/db/s/chunk_move_write_concern_options.cpp
index c417ac0e6f1..4005e50106c 100644
--- a/src/mongo/db/s/chunk_move_write_concern_options.cpp
+++ b/src/mongo/db/s/chunk_move_write_concern_options.cpp
@@ -33,74 +33,72 @@
#include "mongo/db/s/chunk_move_write_concern_options.h"
#include "mongo/base/status_with.h"
-#include "mongo/bson/util/bson_extract.h"
#include "mongo/db/repl/replication_coordinator_global.h"
+#include "mongo/s/migration_secondary_throttle_options.h"
#include "mongo/util/log.h"
namespace mongo {
namespace {
-const int kDefaultWriteTimeoutForMigrationMs = 60 * 1000;
-const WriteConcernOptions DefaultWriteConcernForMigration(2,
- WriteConcernOptions::SyncMode::NONE,
- kDefaultWriteTimeoutForMigrationMs);
+const Seconds kDefaultWriteTimeoutForMigration(60);
+const WriteConcernOptions kDefaultWriteConcernForMigration(2,
+ WriteConcernOptions::SyncMode::NONE,
+ kDefaultWriteTimeoutForMigration);
+const WriteConcernOptions kWriteConcernLocal(1,
+ WriteConcernOptions::SyncMode::NONE,
+ WriteConcernOptions::kNoTimeout);
WriteConcernOptions getDefaultWriteConcernForMigration() {
repl::ReplicationCoordinator* replCoordinator = repl::getGlobalReplicationCoordinator();
if (replCoordinator->getReplicationMode() == mongo::repl::ReplicationCoordinator::modeReplSet) {
Status status =
- replCoordinator->checkIfWriteConcernCanBeSatisfied(DefaultWriteConcernForMigration);
+ replCoordinator->checkIfWriteConcernCanBeSatisfied(kDefaultWriteConcernForMigration);
if (status.isOK()) {
- return DefaultWriteConcernForMigration;
+ return kDefaultWriteConcernForMigration;
}
}
- return WriteConcernOptions(1, WriteConcernOptions::SyncMode::NONE, 0);
+ return kWriteConcernLocal;
}
} // namespace
-ChunkMoveWriteConcernOptions::ChunkMoveWriteConcernOptions(BSONObj secThrottleObj,
- WriteConcernOptions writeConcernOptions)
- : _secThrottleObj(std::move(secThrottleObj)),
- _writeConcernOptions(std::move(writeConcernOptions)) {}
+StatusWith<WriteConcernOptions> ChunkMoveWriteConcernOptions::getEffectiveWriteConcern(
+ const MigrationSecondaryThrottleOptions& options) {
+ if (options.getSecondaryThrottle() == MigrationSecondaryThrottleOptions::kOff) {
+ return kWriteConcernLocal;
+ }
-StatusWith<ChunkMoveWriteConcernOptions> ChunkMoveWriteConcernOptions::initFromCommand(
- const BSONObj& obj) {
- BSONObj secThrottleObj;
- WriteConcernOptions writeConcernOptions;
+ WriteConcernOptions writeConcern;
- Status status = writeConcernOptions.parseSecondaryThrottle(obj, &secThrottleObj);
- if (!status.isOK()) {
- if (status.code() != ErrorCodes::WriteConcernNotDefined) {
- return status;
- }
+ if (options.isWriteConcernSpecified()) {
+ writeConcern = options.getWriteConcern();
- writeConcernOptions = getDefaultWriteConcernForMigration();
- } else {
repl::ReplicationCoordinator* replCoordinator = repl::getGlobalReplicationCoordinator();
if (replCoordinator->getReplicationMode() ==
repl::ReplicationCoordinator::modeMasterSlave &&
- writeConcernOptions.shouldWaitForOtherNodes()) {
+ writeConcern.shouldWaitForOtherNodes()) {
warning() << "moveChunk cannot check if secondary throttle setting "
- << writeConcernOptions.toBSON()
+ << writeConcern.toBSON()
<< " can be enforced in a master slave configuration";
}
- Status status = replCoordinator->checkIfWriteConcernCanBeSatisfied(writeConcernOptions);
+ Status status = replCoordinator->checkIfWriteConcernCanBeSatisfied(writeConcern);
if (!status.isOK() && status != ErrorCodes::NoReplicationEnabled) {
return status;
}
+ } else {
+ writeConcern = getDefaultWriteConcernForMigration();
}
- if (writeConcernOptions.shouldWaitForOtherNodes() &&
- writeConcernOptions.wTimeout == WriteConcernOptions::kNoTimeout) {
+ if (writeConcern.shouldWaitForOtherNodes() &&
+ writeConcern.wTimeout == WriteConcernOptions::kNoTimeout) {
// Don't allow no timeout
- writeConcernOptions.wTimeout = kDefaultWriteTimeoutForMigrationMs;
+ writeConcern.wTimeout = durationCount<Milliseconds>(kDefaultWriteTimeoutForMigration);
}
- return ChunkMoveWriteConcernOptions(secThrottleObj, writeConcernOptions);
+ return writeConcern;
}
} // namespace mongo
diff --git a/src/mongo/db/s/chunk_move_write_concern_options.h b/src/mongo/db/s/chunk_move_write_concern_options.h
index 7258e093198..1ff445d9894 100644
--- a/src/mongo/db/s/chunk_move_write_concern_options.h
+++ b/src/mongo/db/s/chunk_move_write_concern_options.h
@@ -32,8 +32,7 @@
namespace mongo {
-class BSONObj;
-class BSONObjBuilder;
+class MigrationSecondaryThrottleOptions;
template <typename T>
class StatusWith;
@@ -44,31 +43,23 @@ class StatusWith;
class ChunkMoveWriteConcernOptions {
public:
/**
- * Parses the chunk move options expecting the format, which mongod should be getting and if
- * none is available, assigns defaults.
+ * Based on the type of the server (standalone or replica set) and the requested secondary
+ * throttle options returns what write concern should be used locally both for writing migrated
+ * documents and for performing range deletions.
+ *
+ * Returns a non-OK status if the requested write concern cannot be satisfied for some reason.
+ *
+ * These are the rules for determining the local write concern to be used:
+ * - secondaryThrottle is not specified (kDefault) or it is on (kOn), but there is no custom
+ * write concern:
+ * - if replication is enabled and there are 2 or more nodes - w:2, j:false, timeout:60000
+ * - if replication is not enabled or less than 2 nodes - w:1, j:false, timeout:0
+ * - secondaryThrottle is off (kOff): w:1, j:false, timeout:0
+ * - secondaryThrottle is on (kOn) and there is custom write concern, use the custom write
+ * concern.
*/
- static StatusWith<ChunkMoveWriteConcernOptions> initFromCommand(const BSONObj& obj);
-
- /**
- * Returns the throttle options to be used when committing migrated documents on the recipient
- * shard's seconary.
- */
- const BSONObj& getSecThrottle() const {
- return _secThrottleObj;
- }
-
- /**
- * Returns the write concern options.
- */
- const WriteConcernOptions& getWriteConcern() const {
- return _writeConcernOptions;
- }
-
-private:
- ChunkMoveWriteConcernOptions(BSONObj secThrottleObj, WriteConcernOptions writeConcernOptions);
-
- BSONObj _secThrottleObj;
- WriteConcernOptions _writeConcernOptions;
+ static StatusWith<WriteConcernOptions> getEffectiveWriteConcern(
+ const MigrationSecondaryThrottleOptions& options);
};
} // namespace mongo
diff --git a/src/mongo/db/s/cleanup_orphaned_cmd.cpp b/src/mongo/db/s/cleanup_orphaned_cmd.cpp
index e3d36168a1f..0694335b79d 100644
--- a/src/mongo/db/s/cleanup_orphaned_cmd.cpp
+++ b/src/mongo/db/s/cleanup_orphaned_cmd.cpp
@@ -47,6 +47,8 @@
#include "mongo/db/service_context.h"
#include "mongo/db/s/collection_metadata.h"
#include "mongo/db/s/sharding_state.h"
+#include "mongo/db/s/chunk_move_write_concern_options.h"
+#include "mongo/s/migration_secondary_throttle_options.h"
#include "mongo/util/log.h"
namespace mongo {
@@ -56,11 +58,6 @@ using str::stream;
namespace {
-const int kDefaultWTimeoutMs = 60 * 1000;
-const WriteConcernOptions DefaultWriteConcern(WriteConcernOptions::kMajority,
- WriteConcernOptions::SyncMode::UNSET,
- kDefaultWTimeoutMs);
-
enum CleanupResult { CleanupResult_Done, CleanupResult_Continue, CleanupResult_Error };
/**
@@ -228,37 +225,10 @@ public:
return false;
}
- WriteConcernOptions writeConcern;
- Status status = writeConcern.parseSecondaryThrottle(cmdObj, NULL);
-
- if (!status.isOK()) {
- if (status.code() != ErrorCodes::WriteConcernNotDefined) {
- return appendCommandStatus(result, status);
- }
-
- writeConcern = DefaultWriteConcern;
- } else {
- repl::ReplicationCoordinator* replCoordinator = repl::getGlobalReplicationCoordinator();
- Status status = replCoordinator->checkIfWriteConcernCanBeSatisfied(writeConcern);
-
- if (replCoordinator->getReplicationMode() ==
- repl::ReplicationCoordinator::modeMasterSlave &&
- writeConcern.shouldWaitForOtherNodes()) {
- warning() << "cleanupOrphaned cannot check if write concern setting "
- << writeConcern.toBSON()
- << " can be enforced in a master slave configuration";
- }
-
- if (!status.isOK() && status != ErrorCodes::NoReplicationEnabled) {
- return appendCommandStatus(result, status);
- }
- }
-
- if (writeConcern.shouldWaitForOtherNodes() &&
- writeConcern.wTimeout == WriteConcernOptions::kNoTimeout) {
- // Don't allow no timeout.
- writeConcern.wTimeout = kDefaultWTimeoutMs;
- }
+ const auto secondaryThrottle =
+ uassertStatusOK(MigrationSecondaryThrottleOptions::createFromCommand(cmdObj));
+ const auto writeConcern = uassertStatusOK(
+ ChunkMoveWriteConcernOptions::getEffectiveWriteConcern(secondaryThrottle));
ShardingState* const shardingState = ShardingState::get(txn);
@@ -269,7 +239,7 @@ public:
}
ChunkVersion shardVersion;
- status = shardingState->refreshMetadataNow(txn, ns, &shardVersion);
+ Status status = shardingState->refreshMetadataNow(txn, ns, &shardVersion);
if (!status.isOK()) {
if (status.code() == ErrorCodes::RemoteChangeDetected) {
warning() << "Shard version in transition detected while refreshing "
diff --git a/src/mongo/db/s/move_chunk_command.cpp b/src/mongo/db/s/move_chunk_command.cpp
index 79bf24b320c..9fdc8114f45 100644
--- a/src/mongo/db/s/move_chunk_command.cpp
+++ b/src/mongo/db/s/move_chunk_command.cpp
@@ -47,6 +47,7 @@
#include "mongo/s/client/shard_connection.h"
#include "mongo/s/chunk_version.h"
#include "mongo/s/grid.h"
+#include "mongo/s/migration_secondary_throttle_options.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
@@ -178,10 +179,10 @@ public:
// Initialize our current shard name in the shard state if needed
shardingState->setShardName(chunkMoveState.getFromShard());
- const auto moveWriteConcernOptions =
- uassertStatusOK(ChunkMoveWriteConcernOptions::initFromCommand(cmdObj));
- const auto& secThrottleObj = moveWriteConcernOptions.getSecThrottle();
- const auto& writeConcern = moveWriteConcernOptions.getWriteConcern();
+ const auto secondaryThrottle =
+ uassertStatusOK(MigrationSecondaryThrottleOptions::createFromCommand(cmdObj));
+ const auto writeConcernForRangeDeleter = uassertStatusOK(
+ ChunkMoveWriteConcernOptions::getEffectiveWriteConcern(secondaryThrottle));
// Do inline deletion
bool waitForDelete = cmdObj["waitForDelete"].trueValue();
@@ -267,8 +268,6 @@ public:
return false;
}
- const bool isSecondaryThrottle(writeConcern.shouldWaitForOtherNodes());
-
BSONObjBuilder recvChunkStartBuilder;
recvChunkStartBuilder.append("_recvChunkStart", ns);
migrationSessionId.append(&recvChunkStartBuilder);
@@ -280,12 +279,7 @@ public:
recvChunkStartBuilder.append("shardKeyPattern", shardKeyPattern);
recvChunkStartBuilder.append("configServer",
shardingState->getConfigServer(txn).toString());
- recvChunkStartBuilder.append("secondaryThrottle", isSecondaryThrottle);
-
- // Follow the same convention in moveChunk.
- if (isSecondaryThrottle && !secThrottleObj.isEmpty()) {
- recvChunkStartBuilder.append("writeConcern", secThrottleObj);
- }
+ secondaryThrottle.append(&recvChunkStartBuilder);
BSONObj res;
@@ -481,7 +475,7 @@ public:
chunkMoveState.getMinKey().getOwned(),
chunkMoveState.getMaxKey().getOwned(),
shardKeyPattern));
- deleterOptions.writeConcern = writeConcern;
+ deleterOptions.writeConcern = writeConcernForRangeDeleter;
deleterOptions.waitForOpenCursors = true;
deleterOptions.fromMigrate = true;
deleterOptions.onlyRemoveOrphanedDocs = true;
diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp
index 58af7b36a9d..d0f003fb383 100644
--- a/src/mongo/db/write_concern_options.cpp
+++ b/src/mongo/db/write_concern_options.cpp
@@ -46,12 +46,11 @@ namespace {
*/
enum WriteConcern { W_NONE = 0, W_NORMAL = 1 };
-const BSONField<bool> mongosSecondaryThrottleField("_secondaryThrottle", true);
-const BSONField<bool> secondaryThrottleField("secondaryThrottle", true);
-const BSONField<BSONObj> writeConcernField("writeConcern");
-
} // namespace
+const int WriteConcernOptions::kNoTimeout(0);
+const int WriteConcernOptions::kNoWaiting(-1);
+
const char WriteConcernOptions::kMajority[] = "majority";
const BSONObj WriteConcernOptions::Default = BSONObj();
@@ -59,12 +58,14 @@ const BSONObj WriteConcernOptions::Acknowledged(BSON("w" << W_NORMAL));
const BSONObj WriteConcernOptions::Unacknowledged(BSON("w" << W_NONE));
const BSONObj WriteConcernOptions::Majority(BSON("w" << WriteConcernOptions::kMajority));
-
WriteConcernOptions::WriteConcernOptions(int numNodes, SyncMode sync, int timeout)
- : syncMode(sync), wNumNodes(numNodes), wTimeout(timeout) {}
+ : WriteConcernOptions(numNodes, sync, Milliseconds(timeout)) {}
WriteConcernOptions::WriteConcernOptions(const std::string& mode, SyncMode sync, int timeout)
- : syncMode(sync), wNumNodes(0), wMode(mode), wTimeout(timeout) {}
+ : WriteConcernOptions(mode, sync, Milliseconds(timeout)) {}
+
+WriteConcernOptions::WriteConcernOptions(int numNodes, SyncMode sync, Milliseconds timeout)
+ : syncMode(sync), wNumNodes(numNodes), wTimeout(durationCount<Milliseconds>(timeout)) {}
WriteConcernOptions::WriteConcernOptions(const std::string& mode,
SyncMode sync,
@@ -118,53 +119,6 @@ Status WriteConcernOptions::parse(const BSONObj& obj) {
return Status::OK();
}
-Status WriteConcernOptions::parseSecondaryThrottle(const BSONObj& doc,
- BSONObj* rawWriteConcernObj) {
- string errMsg;
- bool isSecondaryThrottle;
- FieldParser::FieldState fieldState =
- FieldParser::extract(doc, secondaryThrottleField, &isSecondaryThrottle, &errMsg);
- if (fieldState == FieldParser::FIELD_INVALID) {
- return Status(ErrorCodes::FailedToParse, errMsg);
- }
-
- if (fieldState != FieldParser::FIELD_SET) {
- fieldState =
- FieldParser::extract(doc, mongosSecondaryThrottleField, &isSecondaryThrottle, &errMsg);
-
- if (fieldState == FieldParser::FIELD_INVALID) {
- return Status(ErrorCodes::FailedToParse, errMsg);
- }
- }
-
- BSONObj dummyBSON;
- if (!rawWriteConcernObj) {
- rawWriteConcernObj = &dummyBSON;
- }
-
- fieldState = FieldParser::extract(doc, writeConcernField, rawWriteConcernObj, &errMsg);
- if (fieldState == FieldParser::FIELD_INVALID) {
- return Status(ErrorCodes::FailedToParse, errMsg);
- }
-
- if (!isSecondaryThrottle) {
- if (!rawWriteConcernObj->isEmpty()) {
- return Status(ErrorCodes::UnsupportedFormat,
- "Cannot have write concern when secondary throttle is false");
- }
-
- wNumNodes = 1;
- return Status::OK();
- }
-
- if (rawWriteConcernObj->isEmpty()) {
- return Status(ErrorCodes::WriteConcernNotDefined,
- "Secondary throttle is on, but write concern is not specified");
- }
-
- return parse(*rawWriteConcernObj);
-}
-
BSONObj WriteConcernOptions::toBSON() const {
BSONObjBuilder builder;
diff --git a/src/mongo/db/write_concern_options.h b/src/mongo/db/write_concern_options.h
index 5acc54e5294..91320b0d39a 100644
--- a/src/mongo/db/write_concern_options.h
+++ b/src/mongo/db/write_concern_options.h
@@ -39,8 +39,8 @@ struct WriteConcernOptions {
public:
enum class SyncMode { UNSET, NONE, FSYNC, JOURNAL };
- static const int kNoTimeout = 0;
- static const int kNoWaiting = -1;
+ static const int kNoTimeout;
+ static const int kNoWaiting;
static const BSONObj Default;
static const BSONObj Acknowledged;
@@ -58,6 +58,8 @@ public:
WriteConcernOptions(int numNodes, SyncMode sync, int timeout);
+ WriteConcernOptions(int numNodes, SyncMode sync, Milliseconds timeout);
+
WriteConcernOptions(const std::string& mode, SyncMode sync, int timeout);
WriteConcernOptions(const std::string& mode, SyncMode sync, Milliseconds timeout);
@@ -65,26 +67,6 @@ public:
Status parse(const BSONObj& obj);
/**
- * Extracts the write concern settings from the BSONObj. The BSON object should have
- * the format:
- *
- * {
- * ...
- * secondaryThrottle: <bool>, // optional
- * _secondaryThrottle: <bool>, // optional
- * writeConcern: <BSONObj> // optional
- * }
- *
- * Note: secondaryThrottle takes precedence over _secondaryThrottle.
- *
- * Also sets output parameter rawWriteConcernObj if the writeCocnern field exists.
- *
- * Returns OK if the parse was successful. Also returns ErrorCodes::WriteConcernNotDefined
- * when secondary throttle is true but write concern was not specified.
- */
- Status parseSecondaryThrottle(const BSONObj& doc, BSONObj* rawWriteConcernObj);
-
- /**
* Return true if the server needs to wait for other secondary nodes to satisfy this
* write concern setting. Errs on the false positive for non-empty wMode.
*/
@@ -117,4 +99,5 @@ public:
// Timeout in milliseconds.
int wTimeout;
};
-}
+
+} // namespace mongo
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 65f8a92be57..50ef4b485b5 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -38,11 +38,13 @@ env.Library(
source=[
'chunk_diff.cpp',
'chunk_version.cpp',
+ 'migration_secondary_throttle_options.cpp',
'set_shard_version_request.cpp',
],
LIBDEPS=[
'catalog/catalog_types',
'$BUILD_DIR/mongo/client/connection_string',
+ '$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/mongo/db/query/lite_parsed_query',
'$BUILD_DIR/mongo/db/repl/optime',
'$BUILD_DIR/mongo/rpc/metadata',
@@ -92,23 +94,14 @@ env.CppUnitTest(
],
LIBDEPS=[
'common',
- '$BUILD_DIR/mongo/db/service_context',
]
)
env.CppUnitTest(
- target='chunk_version_test',
+ target='sharding_request_types_test',
source=[
'chunk_version_test.cpp',
- ],
- LIBDEPS=[
- 'common',
- ]
-)
-
-env.CppUnitTest(
- target='set_shard_version_request_test',
- source=[
+ 'migration_secondary_throttle_options_test.cpp',
'set_shard_version_request_test.cpp',
],
LIBDEPS=[
diff --git a/src/mongo/s/chunk_diff_test.cpp b/src/mongo/s/chunk_diff_test.cpp
index 7c6bab7e94d..0e7674929fe 100644
--- a/src/mongo/s/chunk_diff_test.cpp
+++ b/src/mongo/s/chunk_diff_test.cpp
@@ -111,7 +111,6 @@ protected:
~ChunkDiffUnitTest() = default;
void runTest(bool isInverse) {
- OperationContextNoop txn;
int numShards = 10;
int numInitialChunks = 5;
@@ -177,7 +176,7 @@ protected:
convertBSONArrayToChunkTypes(chunks, &chunksVector);
// Validate initial load
- differ->calculateConfigDiff(&txn, chunksVector);
+ differ->calculateConfigDiff(nullptr, chunksVector);
validate(isInverse, chunksVector, ranges, maxVersion, maxShardVersions);
// Generate a lot of diffs, and keep validating that updating from the diffs always gives us
@@ -325,7 +324,7 @@ protected:
std::vector<ChunkType> chunksVector;
convertBSONArrayToChunkTypes(chunks, &chunksVector);
- differ->calculateConfigDiff(&txn, chunksVector);
+ differ->calculateConfigDiff(nullptr, chunksVector);
validate(isInverse, chunksVector, ranges, maxVersion, maxShardVersions);
}
diff --git a/src/mongo/s/chunk_version.h b/src/mongo/s/chunk_version.h
index 007e05f7353..cdc266fd613 100644
--- a/src/mongo/s/chunk_version.h
+++ b/src/mongo/s/chunk_version.h
@@ -29,7 +29,6 @@
#pragma once
#include "mongo/db/jsobj.h"
-#include "mongo/s/optime_pair.h"
namespace mongo {
diff --git a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
index a4b1efc62c6..62a08176f43 100644
--- a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
+++ b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
@@ -44,6 +44,7 @@
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/config.h"
#include "mongo/s/grid.h"
+#include "mongo/s/migration_secondary_throttle_options.h"
#include "mongo/util/log.h"
#include "mongo/util/timer.h"
@@ -224,18 +225,13 @@ public:
return false;
}
- unique_ptr<WriteConcernOptions> writeConcern(new WriteConcernOptions());
+ const auto secondaryThrottle =
+ uassertStatusOK(MigrationSecondaryThrottleOptions::createFromCommand(cmdObj));
- Status status = writeConcern->parseSecondaryThrottle(cmdObj, NULL);
- if (!status.isOK()) {
- if (status.code() != ErrorCodes::WriteConcernNotDefined) {
- errmsg = status.toString();
- return false;
- }
-
- // Let the shard decide what write concern to use.
- writeConcern.reset();
- }
+ const unique_ptr<WriteConcernOptions> writeConcern(
+ secondaryThrottle.isWriteConcernSpecified()
+ ? new WriteConcernOptions(secondaryThrottle.getWriteConcern())
+ : nullptr);
BSONObj res;
if (!chunk->moveAndCommit(txn,
diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp
index 552c853fbb7..e591735a525 100644
--- a/src/mongo/s/d_migrate.cpp
+++ b/src/mongo/s/d_migrate.cpp
@@ -50,6 +50,7 @@
#include "mongo/db/s/migration_impl.h"
#include "mongo/db/s/sharding_state.h"
#include "mongo/s/chunk_version.h"
+#include "mongo/s/migration_secondary_throttle_options.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
@@ -274,9 +275,10 @@ public:
}
// Process secondary throttle settings and assign defaults if necessary.
- const auto moveWriteConcernOptions =
- uassertStatusOK(ChunkMoveWriteConcernOptions::initFromCommand(cmdObj));
- const auto& writeConcern = moveWriteConcernOptions.getWriteConcern();
+ const auto secondaryThrottle =
+ uassertStatusOK(MigrationSecondaryThrottleOptions::createFromCommand(cmdObj));
+ const auto writeConcern = uassertStatusOK(
+ ChunkMoveWriteConcernOptions::getEffectiveWriteConcern(secondaryThrottle));
BSONObj shardKeyPattern = cmdObj["shardKeyPattern"].Obj().getOwned();
diff --git a/src/mongo/s/migration_secondary_throttle_options.cpp b/src/mongo/s/migration_secondary_throttle_options.cpp
new file mode 100644
index 00000000000..870daf767d3
--- /dev/null
+++ b/src/mongo/s/migration_secondary_throttle_options.cpp
@@ -0,0 +1,147 @@
+/**
+ * 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/migration_secondary_throttle_options.h"
+
+#include "mongo/base/status_with.h"
+#include "mongo/bson/util/bson_extract.h"
+#include "mongo/db/write_concern_options.h"
+
+namespace mongo {
+namespace {
+
+const char kSecondaryThrottleMongos[] = "_secondaryThrottle";
+const char kSecondaryThrottleMongod[] = "secondaryThrottle";
+const char kWriteConcern[] = "writeConcern";
+
+} // namespace
+
+MigrationSecondaryThrottleOptions::MigrationSecondaryThrottleOptions(
+ SecondaryThrottleOption secondaryThrottle, boost::optional<BSONObj> writeConcernBSON)
+ : _secondaryThrottle(secondaryThrottle), _writeConcernBSON(std::move(writeConcernBSON)) {}
+
+MigrationSecondaryThrottleOptions MigrationSecondaryThrottleOptions::create(
+ SecondaryThrottleOption option) {
+ return MigrationSecondaryThrottleOptions(option, boost::none);
+}
+
+MigrationSecondaryThrottleOptions MigrationSecondaryThrottleOptions::createWithWriteConcern(
+ const WriteConcernOptions& writeConcern) {
+ // Optimize on write concern, which makes no difference
+ if (writeConcern.wNumNodes <= 1 && writeConcern.wMode.empty()) {
+ return MigrationSecondaryThrottleOptions(kOff, boost::none);
+ }
+
+ return MigrationSecondaryThrottleOptions(kOn, writeConcern.toBSON());
+}
+
+StatusWith<MigrationSecondaryThrottleOptions> MigrationSecondaryThrottleOptions::createFromCommand(
+ const BSONObj& obj) {
+ SecondaryThrottleOption secondaryThrottle;
+ boost::optional<BSONObj> writeConcernBSON;
+
+ // Parse the two variants of the 'secondaryThrottle' option
+ {
+ bool isSecondaryThrottle;
+
+ Status status =
+ bsonExtractBooleanField(obj, kSecondaryThrottleMongod, &isSecondaryThrottle);
+ if (status == ErrorCodes::NoSuchKey) {
+ status = bsonExtractBooleanField(obj, kSecondaryThrottleMongos, &isSecondaryThrottle);
+ }
+
+ if (status == ErrorCodes::NoSuchKey) {
+ secondaryThrottle = kDefault;
+ } else if (status.isOK()) {
+ secondaryThrottle = (isSecondaryThrottle ? kOn : kOff);
+ } else {
+ return status;
+ }
+ }
+
+ // Extract the requested 'writeConcern' option
+ {
+ BSONElement writeConcernElem;
+ Status status = bsonExtractField(obj, kWriteConcern, &writeConcernElem);
+ if (status == ErrorCodes::NoSuchKey) {
+ return MigrationSecondaryThrottleOptions(secondaryThrottle, boost::none);
+ } else if (!status.isOK()) {
+ return status;
+ }
+
+ if (secondaryThrottle != kOn) {
+ return Status(ErrorCodes::UnsupportedFormat,
+ "Cannot specify write concern when secondaryThrottle is not set");
+ }
+
+ writeConcernBSON = writeConcernElem.Obj().getOwned();
+ }
+
+ invariant(writeConcernBSON.is_initialized());
+
+ // Make sure the write concern parses correctly
+ WriteConcernOptions writeConcern;
+ Status status = writeConcern.parse(*writeConcernBSON);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ return MigrationSecondaryThrottleOptions(secondaryThrottle, std::move(writeConcernBSON));
+}
+
+WriteConcernOptions MigrationSecondaryThrottleOptions::getWriteConcern() const {
+ invariant(_secondaryThrottle != kOff);
+ invariant(_writeConcernBSON);
+
+ WriteConcernOptions writeConcern;
+ fassertStatusOK(34414, writeConcern.parse(*_writeConcernBSON));
+
+ return writeConcern;
+}
+
+void MigrationSecondaryThrottleOptions::append(BSONObjBuilder* builder) const {
+ if (_secondaryThrottle == kDefault) {
+ return;
+ }
+
+ builder->appendBool(kSecondaryThrottleMongod, _secondaryThrottle == kOn);
+
+ if (_secondaryThrottle == kOn && _writeConcernBSON) {
+ builder->append(kWriteConcern, *_writeConcernBSON);
+ }
+}
+
+BSONObj MigrationSecondaryThrottleOptions::toBSON() const {
+ BSONObjBuilder builder;
+ append(&builder);
+ return builder.obj();
+}
+
+} // namespace mongo
diff --git a/src/mongo/s/migration_secondary_throttle_options.h b/src/mongo/s/migration_secondary_throttle_options.h
new file mode 100644
index 00000000000..b4f4cbe066a
--- /dev/null
+++ b/src/mongo/s/migration_secondary_throttle_options.h
@@ -0,0 +1,127 @@
+/**
+ * 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 <boost/optional.hpp>
+
+#include "mongo/bson/bsonobj.h"
+
+namespace mongo {
+
+class BSONObjBuilder;
+template <typename T>
+class StatusWith;
+struct WriteConcernOptions;
+
+/**
+ * Returns the default write concern for migration cleanup on the donor shard and for cloning
+ * documents on the destination shard.
+ */
+class MigrationSecondaryThrottleOptions {
+public:
+ enum SecondaryThrottleOption {
+ // The secondary throttle option is not set explicitly. Use the default for the service.
+ kDefault,
+
+ // The secondary throttle option is explicitly disabled.
+ kOff,
+
+ // The secondary throttle option is explicitly enabled and there potentially might be a
+ // write concern specified. If no write concern was specified, use the default.
+ kOn
+ };
+
+ /**
+ * Constructs an object with the specified secondary throttle option and no custom write
+ * concern.
+ */
+ static MigrationSecondaryThrottleOptions create(SecondaryThrottleOption option);
+
+ /**
+ * Constructs an object with the secondary throttle enabled and with the specified write
+ * concern.
+ */
+ static MigrationSecondaryThrottleOptions createWithWriteConcern(
+ const WriteConcernOptions& writeConcern);
+
+ /**
+ * Extracts the write concern settings from a BSON with the following format:
+ *
+ * {
+ * secondaryThrottle: <bool>, // optional
+ * _secondaryThrottle: <bool>, // optional
+ * writeConcern: <BSONObj> // optional
+ * }
+ *
+ * Note: secondaryThrottle takes precedence over _secondaryThrottle. If either of the two are
+ * missing, the secondaryThrottle enabled status defaults to true.
+ *
+ * Returns OK if the parse was successful.
+ */
+ static StatusWith<MigrationSecondaryThrottleOptions> createFromCommand(const BSONObj& obj);
+
+ /**
+ * Returns the selected secondary throttle option.
+ */
+ SecondaryThrottleOption getSecondaryThrottle() const {
+ return _secondaryThrottle;
+ }
+
+ /**
+ * Returns whether secondary throttle is enabled and write concern was requested.
+ */
+ bool isWriteConcernSpecified() const {
+ return _writeConcernBSON.is_initialized();
+ }
+
+ /**
+ * Returns the custom write concern, which was requested. Must only be called if
+ * isWriteConcernSpecified returns true.
+ */
+ WriteConcernOptions getWriteConcern() const;
+
+ /**
+ * Returns a BSON representation of the current secondary throttle settongs.
+ */
+ void append(BSONObjBuilder* builder) const;
+ BSONObj toBSON() const;
+
+private:
+ MigrationSecondaryThrottleOptions(SecondaryThrottleOption secondaryThrottle,
+ boost::optional<BSONObj> writeConcernBSON);
+
+ // What is the state of the secondaryThrottle option (kDefault means that it has not been set)
+ SecondaryThrottleOption _secondaryThrottle;
+
+ // Owned BSON object with the contents of the writeConcern. If this object is set, then
+ // secodaryThrottle must be true.
+ boost::optional<BSONObj> _writeConcernBSON;
+};
+
+} // namespace mongo
diff --git a/src/mongo/s/migration_secondary_throttle_options_test.cpp b/src/mongo/s/migration_secondary_throttle_options_test.cpp
new file mode 100644
index 00000000000..ea76fb28f06
--- /dev/null
+++ b/src/mongo/s/migration_secondary_throttle_options_test.cpp
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/bson/bsonmisc.h"
+#include "mongo/db/write_concern_options.h"
+#include "mongo/s/migration_secondary_throttle_options.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+
+using unittest::assertGet;
+
+namespace {
+
+TEST(MigrationSecondaryThrottleOptions, CreateDefault) {
+ MigrationSecondaryThrottleOptions options =
+ MigrationSecondaryThrottleOptions::create(MigrationSecondaryThrottleOptions::kDefault);
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kDefault, options.getSecondaryThrottle());
+ ASSERT(!options.isWriteConcernSpecified());
+ ASSERT_EQUALS(BSONObj(), options.toBSON());
+}
+
+TEST(MigrationSecondaryThrottleOptions, CreateOn) {
+ MigrationSecondaryThrottleOptions options =
+ MigrationSecondaryThrottleOptions::create(MigrationSecondaryThrottleOptions::kOn);
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kOn, options.getSecondaryThrottle());
+ ASSERT(!options.isWriteConcernSpecified());
+ ASSERT_EQUALS(BSON("secondaryThrottle" << true), options.toBSON());
+}
+
+TEST(MigrationSecondaryThrottleOptions, CreateOff) {
+ MigrationSecondaryThrottleOptions options =
+ MigrationSecondaryThrottleOptions::create(MigrationSecondaryThrottleOptions::kOff);
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kOff, options.getSecondaryThrottle());
+ ASSERT(!options.isWriteConcernSpecified());
+ ASSERT_EQUALS(BSON("secondaryThrottle" << false), options.toBSON());
+}
+
+TEST(MigrationSecondaryThrottleOptions, NotSpecifiedInCommandBSON) {
+ MigrationSecondaryThrottleOptions options = assertGet(
+ MigrationSecondaryThrottleOptions::createFromCommand(BSON("someOtherField" << 1)));
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kDefault, options.getSecondaryThrottle());
+ ASSERT_EQUALS(BSONObj(), options.toBSON());
+}
+
+TEST(MigrationSecondaryThrottleOptions, EnabledInCommandBSONWithoutWriteConcern) {
+ MigrationSecondaryThrottleOptions options =
+ assertGet(MigrationSecondaryThrottleOptions::createFromCommand(
+ BSON("someOtherField" << 1 << "secondaryThrottle" << true)));
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kOn, options.getSecondaryThrottle());
+ ASSERT(!options.isWriteConcernSpecified());
+}
+
+TEST(MigrationSecondaryThrottleOptions, EnabledInCommandBSONWithSimpleWriteConcern) {
+ MigrationSecondaryThrottleOptions options =
+ assertGet(MigrationSecondaryThrottleOptions::createFromCommand(
+ BSON("someOtherField" << 1 << "secondaryThrottle" << true << "writeConcern"
+ << BSON("w" << 2))));
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kOn, options.getSecondaryThrottle());
+ ASSERT(options.isWriteConcernSpecified());
+
+ WriteConcernOptions writeConcern = options.getWriteConcern();
+ ASSERT_EQ(2, writeConcern.wNumNodes);
+ ASSERT_EQ(static_cast<int>(WriteConcernOptions::SyncMode::UNSET),
+ static_cast<int>(writeConcern.syncMode));
+ ASSERT_EQ(WriteConcernOptions::kNoTimeout, writeConcern.wTimeout);
+}
+
+TEST(MigrationSecondaryThrottleOptions, EnabledInCommandBSONWithCompleteWriteConcern) {
+ MigrationSecondaryThrottleOptions options =
+ assertGet(MigrationSecondaryThrottleOptions::createFromCommand(
+ BSON("someOtherField" << 1 << "secondaryThrottle" << true << "writeConcern"
+ << BSON("w" << 3 << "j" << true))));
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kOn, options.getSecondaryThrottle());
+ ASSERT(options.isWriteConcernSpecified());
+
+ WriteConcernOptions writeConcern = options.getWriteConcern();
+ ASSERT_EQ(3, writeConcern.wNumNodes);
+ ASSERT_EQ(static_cast<int>(WriteConcernOptions::SyncMode::JOURNAL),
+ static_cast<int>(writeConcern.syncMode));
+ ASSERT_EQ(WriteConcernOptions::kNoTimeout, writeConcern.wTimeout);
+}
+
+TEST(MigrationSecondaryThrottleOptions, DisabledInCommandBSON) {
+ MigrationSecondaryThrottleOptions options =
+ assertGet(MigrationSecondaryThrottleOptions::createFromCommand(
+ BSON("someOtherField" << 1 << "secondaryThrottle" << false)));
+ ASSERT_EQ(MigrationSecondaryThrottleOptions::kOff, options.getSecondaryThrottle());
+}
+
+TEST(MigrationSecondaryThrottleOptions, ParseFailsDisabledInCommandBSONWriteConcernSpecified) {
+ auto status = MigrationSecondaryThrottleOptions::createFromCommand(
+ BSON("someOtherField" << 1 << "secondaryThrottle" << false << "writeConcern"
+ << BSON("w"
+ << "majority")));
+ ASSERT_EQ(ErrorCodes::UnsupportedFormat, status.getStatus().code());
+}
+
+TEST(MigrationSecondaryThrottleOptions, ParseFailsNotSpecifiedInCommandBSONWriteConcernSpecified) {
+ auto status = MigrationSecondaryThrottleOptions::createFromCommand(
+ BSON("someOtherField" << 1 << "writeConcern" << BSON("w"
+ << "majority")));
+ ASSERT_EQ(ErrorCodes::UnsupportedFormat, status.getStatus().code());
+}
+
+} // namespace
+} // namespace mongo