summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@mongodb.com>2014-09-11 14:10:18 -0400
committerSpencer T Brody <spencer@mongodb.com>2014-09-14 18:29:20 -0400
commitfdfcb2b6922bcd64982659f82f1a47cc31de7929 (patch)
tree84394a01e6332d5b26ec5a100eaed982a4ae76c2
parent93f961084fa9c9969b0a04445d364ea7056d8efc (diff)
downloadmongo-fdfcb2b6922bcd64982659f82f1a47cc31de7929.tar.gz
SERVER-14567 Implement checkIfWriteConcernCanBeSatisfied in ReplicationCoordinatorImpl
-rw-r--r--src/mongo/db/commands/cleanup_orphaned_cmd.cpp2
-rw-r--r--src/mongo/db/repl/repl_coordinator.h6
-rw-r--r--src/mongo/db/repl/repl_coordinator_hybrid.cpp4
-rw-r--r--src/mongo/db/repl/repl_coordinator_impl.cpp20
-rw-r--r--src/mongo/db/repl/replica_set_config.cpp39
-rw-r--r--src/mongo/db/repl/replica_set_config.h10
-rw-r--r--src/mongo/db/repl/replica_set_config_test.cpp66
-rw-r--r--src/mongo/s/d_migrate.cpp4
8 files changed, 135 insertions, 16 deletions
diff --git a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp
index 83dbea1166b..fe468c0b166 100644
--- a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp
+++ b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp
@@ -248,7 +248,7 @@ namespace mongo {
repl::ReplicationCoordinator* replCoordinator =
repl::getGlobalReplicationCoordinator();
Status status = replCoordinator->checkIfWriteConcernCanBeSatisfied(writeConcern);
- if (!status.isOK()) {
+ if (!status.isOK() && status != ErrorCodes::NoReplicationEnabled) {
return appendCommandStatus(result, status);
}
}
diff --git a/src/mongo/db/repl/repl_coordinator.h b/src/mongo/db/repl/repl_coordinator.h
index b4d91704039..683a8ea00ca 100644
--- a/src/mongo/db/repl/repl_coordinator.h
+++ b/src/mongo/db/repl/repl_coordinator.h
@@ -208,9 +208,9 @@ namespace repl {
* Checks if the current replica set configuration can satisfy the given write concern.
*
* Things that are taken into consideration include:
- * 1. If the set has enough members.
- * 2. If the tag exists.
- * 3. If there are enough members for the tag specified.
+ * 1. If the set has enough data-bearing members.
+ * 2. If the write concern mode exists.
+ * 3. If there are enough members for the write concern mode specified.
*/
virtual Status checkIfWriteConcernCanBeSatisfied(
const WriteConcernOptions& writeConcern) const = 0;
diff --git a/src/mongo/db/repl/repl_coordinator_hybrid.cpp b/src/mongo/db/repl/repl_coordinator_hybrid.cpp
index f8c9f1241d1..a6544a487d0 100644
--- a/src/mongo/db/repl/repl_coordinator_hybrid.cpp
+++ b/src/mongo/db/repl/repl_coordinator_hybrid.cpp
@@ -383,9 +383,7 @@ namespace repl {
Status HybridReplicationCoordinator::checkIfWriteConcernCanBeSatisfied(
const WriteConcernOptions& writeConcern) const {
- Status legacyStatus = _legacy.checkIfWriteConcernCanBeSatisfied(writeConcern);
- Status implStatus = _impl.checkIfWriteConcernCanBeSatisfied(writeConcern);
- return legacyStatus;
+ return _impl.checkIfWriteConcernCanBeSatisfied(writeConcern);
}
BSONObj HybridReplicationCoordinator::getGetLastErrorDefault() {
diff --git a/src/mongo/db/repl/repl_coordinator_impl.cpp b/src/mongo/db/repl/repl_coordinator_impl.cpp
index bc0ff5fedd5..3aa7c9a1a32 100644
--- a/src/mongo/db/repl/repl_coordinator_impl.cpp
+++ b/src/mongo/db/repl/repl_coordinator_impl.cpp
@@ -1251,16 +1251,22 @@ namespace {
Status ReplicationCoordinatorImpl::_checkIfWriteConcernCanBeSatisfied_inlock(
const WriteConcernOptions& writeConcern) const {
- // TODO Finish implementing this
+ if (_getReplicationMode_inlock() == modeNone) {
+ return Status(ErrorCodes::NoReplicationEnabled,
+ "No replication enabled when checking if write concern can be satisfied");
+ }
- if (!writeConcern.wMode.empty() && writeConcern.wMode != "majority") {
- StatusWith<ReplicaSetTagPattern> tagPatternStatus =
- _rsConfig.findCustomWriteMode(writeConcern.wMode);
- if (!tagPatternStatus.isOK()) {
- return tagPatternStatus.getStatus();
+ if (_getReplicationMode_inlock() == modeMasterSlave) {
+ if (!writeConcern.wMode.empty()) {
+ return Status(ErrorCodes::UnknownReplWriteConcern,
+ "Cannot used named write concern modes in master-slave");
}
+ // No way to know how many slaves there are, so assume any numeric mode is possible.
+ return Status::OK();
}
- return Status::OK();
+
+ invariant(_getReplicationMode_inlock() == modeReplSet);
+ return _rsConfig.checkIfWriteConcernCanBeSatisfied(writeConcern);
}
BSONObj ReplicationCoordinatorImpl::getGetLastErrorDefault() {
diff --git a/src/mongo/db/repl/replica_set_config.cpp b/src/mongo/db/repl/replica_set_config.cpp
index 4e76121a3ca..fe6715365a9 100644
--- a/src/mongo/db/repl/replica_set_config.cpp
+++ b/src/mongo/db/repl/replica_set_config.cpp
@@ -345,6 +345,45 @@ namespace {
return Status::OK();
}
+ Status ReplicaSetConfig::checkIfWriteConcernCanBeSatisfied(
+ const WriteConcernOptions& writeConcern) const {
+ if (!writeConcern.wMode.empty() && writeConcern.wMode != "majority") {
+ StatusWith<ReplicaSetTagPattern> tagPatternStatus =
+ findCustomWriteMode(writeConcern.wMode);
+ if (!tagPatternStatus.isOK()) {
+ return tagPatternStatus.getStatus();
+ }
+
+ ReplicaSetTagMatch matcher(tagPatternStatus.getValue());
+ for (size_t j = 0; j < _members.size(); ++j) {
+ const MemberConfig& memberConfig = _members[j];
+ for (MemberConfig::TagIterator it = memberConfig.tagsBegin();
+ it != memberConfig.tagsEnd(); ++it) {
+ if (matcher.update(*it)) {
+ return Status::OK();
+ }
+ }
+ }
+ // Even if all the nodes in the set had a given write it still would not satisfy this
+ // write concern mode.
+ return Status(ErrorCodes::CannotSatisfyWriteConcern,
+ str::stream() << "Not enough nodes match write concern mode \""
+ << writeConcern.wMode << "\"");
+ }
+ else {
+ int nodesRemaining = writeConcern.wNumNodes;
+ for (size_t j = 0; j < _members.size(); ++j) {
+ if (!_members[j].isArbiter()) { // Only count data-bearing nodes
+ --nodesRemaining;
+ if (nodesRemaining <= 0) {
+ return Status::OK();
+ }
+ }
+ }
+ return Status(ErrorCodes::CannotSatisfyWriteConcern, "Not enough data-bearing nodes");
+ }
+ }
+
const MemberConfig& ReplicaSetConfig::getMemberAt(size_t i) const {
invariant(i < _members.size());
return _members[i];
diff --git a/src/mongo/db/repl/replica_set_config.h b/src/mongo/db/repl/replica_set_config.h
index 73571d780e1..0b16386a565 100644
--- a/src/mongo/db/repl/replica_set_config.h
+++ b/src/mongo/db/repl/replica_set_config.h
@@ -80,6 +80,16 @@ namespace repl {
Status validate() const;
/**
+ * Checks if this configuration can satisfy the given write concern.
+ *
+ * Things that are taken into consideration include:
+ * 1. If the set has enough data-bearing members.
+ * 2. If the write concern mode exists.
+ * 3. If there are enough members for the write concern mode specified.
+ */
+ Status checkIfWriteConcernCanBeSatisfied(const WriteConcernOptions& writeConcern) const;
+
+ /**
* Gets the version of this configuration.
*
* The version number sequences configurations of the replica set, so that
diff --git a/src/mongo/db/repl/replica_set_config_test.cpp b/src/mongo/db/repl/replica_set_config_test.cpp
index 12db516089f..fc1ba7ff8ed 100644
--- a/src/mongo/db/repl/replica_set_config_test.cpp
+++ b/src/mongo/db/repl/replica_set_config_test.cpp
@@ -540,6 +540,72 @@ namespace {
ASSERT_TRUE(configA == configB);
}
+ TEST(ReplicaSetConfig, CheckIfWriteConcernCanBeSatisfied) {
+ ReplicaSetConfig configA;
+ ASSERT_OK(configA.initialize(
+ BSON("_id" << "rs0" <<
+ "version" << 1 <<
+ "members" << BSON_ARRAY(BSON("_id" << 0 <<
+ "host" << "node0" <<
+ "tags" << BSON("dc" << "NA" <<
+ "rack" << "rackNA1")) <<
+ BSON("_id" << 1 <<
+ "host" << "node1" <<
+ "tags" << BSON("dc" << "NA" <<
+ "rack" << "rackNA2")) <<
+ BSON("_id" << 2 <<
+ "host" << "node2" <<
+ "tags" << BSON("dc" << "NA" <<
+ "rack" << "rackNA3")) <<
+ BSON("_id" << 3 <<
+ "host" << "node3" <<
+ "tags" << BSON("dc" << "EU" <<
+ "rack" << "rackEU1")) <<
+ BSON("_id" << 4 <<
+ "host" << "node4" <<
+ "tags" << BSON("dc" << "EU" <<
+ "rack" << "rackEU2")) <<
+ BSON("_id" << 5 <<
+ "host" << "node5" <<
+ "arbiterOnly" << true)) <<
+ "settings" << BSON("getLastErrorModes" <<
+ BSON("valid" << BSON("dc" << 2 << "rack" << 3) <<
+ "invalidNotEnoughValues" << BSON("dc" << 3) <<
+ "invalidNotEnoughNodes" << BSON("rack" << 6))))));
+
+ WriteConcernOptions validNumberWC;
+ validNumberWC.wNumNodes = 5;
+ ASSERT_OK(configA.checkIfWriteConcernCanBeSatisfied(validNumberWC));
+
+ WriteConcernOptions invalidNumberWC;
+ invalidNumberWC.wNumNodes = 6;
+ ASSERT_EQUALS(ErrorCodes::CannotSatisfyWriteConcern,
+ configA.checkIfWriteConcernCanBeSatisfied(invalidNumberWC));
+
+ WriteConcernOptions majorityWC;
+ majorityWC.wMode = "majority";
+ ASSERT_OK(configA.checkIfWriteConcernCanBeSatisfied(majorityWC));
+
+ WriteConcernOptions validModeWC;
+ validModeWC.wMode = "valid";
+ ASSERT_OK(configA.checkIfWriteConcernCanBeSatisfied(validModeWC));
+
+ WriteConcernOptions fakeModeWC;
+ fakeModeWC.wMode = "fake";
+ ASSERT_EQUALS(ErrorCodes::UnknownReplWriteConcern,
+ configA.checkIfWriteConcernCanBeSatisfied(fakeModeWC));
+
+ WriteConcernOptions invalidModeNotEnoughValuesWC;
+ invalidModeNotEnoughValuesWC.wMode = "invalidNotEnoughValues";
+ ASSERT_EQUALS(ErrorCodes::CannotSatisfyWriteConcern,
+ configA.checkIfWriteConcernCanBeSatisfied(invalidModeNotEnoughValuesWC));
+
+ WriteConcernOptions invalidModeNotEnoughNodesWC;
+ invalidModeNotEnoughNodesWC.wMode = "invalidNotEnoughNodes";
+ ASSERT_EQUALS(ErrorCodes::CannotSatisfyWriteConcern,
+ configA.checkIfWriteConcernCanBeSatisfied(invalidModeNotEnoughNodesWC));
+ }
+
} // namespace
} // namespace repl
} // namespace mongo
diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp
index 4ae6c54bfa8..2c36511c602 100644
--- a/src/mongo/s/d_migrate.cpp
+++ b/src/mongo/s/d_migrate.cpp
@@ -864,7 +864,7 @@ namespace mongo {
repl::ReplicationCoordinator* replCoordinator =
repl::getGlobalReplicationCoordinator();
Status status = replCoordinator->checkIfWriteConcernCanBeSatisfied(writeConcern);
- if (!status.isOK()) {
+ if (!status.isOK() && status != ErrorCodes::NoReplicationEnabled) {
warning() << status.toString() << endl;
return appendCommandStatus(result, status);
}
@@ -2435,7 +2435,7 @@ namespace mongo {
repl::ReplicationCoordinator* replCoordinator =
repl::getGlobalReplicationCoordinator();
Status status = replCoordinator->checkIfWriteConcernCanBeSatisfied(writeConcern);
- if (!status.isOK()) {
+ if (!status.isOK() && status != ErrorCodes::NoReplicationEnabled) {
warning() << status.toString() << endl;
return appendCommandStatus(result, status);
}