diff options
-rw-r--r-- | src/mongo/db/commands/cleanup_orphaned_cmd.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator.h | 6 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_hybrid.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_impl.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/repl/replica_set_config.cpp | 39 | ||||
-rw-r--r-- | src/mongo/db/repl/replica_set_config.h | 10 | ||||
-rw-r--r-- | src/mongo/db/repl/replica_set_config_test.cpp | 66 | ||||
-rw-r--r-- | src/mongo/s/d_migrate.cpp | 4 |
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); } |