summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Wahlin <james@mongodb.com>2018-11-06 16:18:20 -0500
committerJames Wahlin <james@mongodb.com>2018-11-16 14:17:51 -0500
commit410656e971aff8f491a87337a17d04bd866389ba (patch)
treef369934d0fc7b2b89095d2c77df1ecd460bc1ddf
parent63e43f1bb47f7bddf3dc37ad03a2bbee6d2a9423 (diff)
downloadmongo-410656e971aff8f491a87337a17d04bd866389ba.tar.gz
SERVER-37124 Disambiguate DuplicateKey error and return keyPattern details in errorInfo object
-rw-r--r--buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml4
-rw-r--r--src/mongo/base/error_codes.err2
-rw-r--r--src/mongo/base/initializer_dependency_graph.cpp2
-rw-r--r--src/mongo/base/initializer_dependency_graph_test.cpp4
-rw-r--r--src/mongo/bson/util/bson_check.h6
-rw-r--r--src/mongo/bson/util/bson_check_test.cpp5
-rw-r--r--src/mongo/db/auth/role_graph.cpp4
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp4
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp5
-rw-r--r--src/mongo/db/repl/apply_ops.cpp2
-rw-r--r--src/mongo/db/repl/database_cloner.cpp2
-rw-r--r--src/mongo/db/repl/database_cloner_test.cpp2
-rw-r--r--src/mongo/db/repl/repl_set_config.cpp2
-rw-r--r--src/mongo/db/repl/repl_set_config_checks.cpp2
-rw-r--r--src/mongo/db/repl/repl_set_config_checks_test.cpp6
-rw-r--r--src/mongo/db/repl/repl_set_config_test.cpp2
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp2
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp2
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp2
-rw-r--r--src/mongo/db/s/migration_destination_manager_test.cpp4
-rw-r--r--src/mongo/db/storage/SConscript11
-rw-r--r--src/mongo/db/storage/duplicate_key_error_info.cpp53
-rw-r--r--src/mongo/db/storage/duplicate_key_error_info.h67
-rw-r--r--src/mongo/db/storage/index_entry_comparison.cpp6
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp2
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp2
-rw-r--r--src/mongo/s/catalog/SConscript3
-rw-r--r--src/mongo/s/catalog/dist_lock_catalog_impl_test.cpp7
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.cpp9
-rw-r--r--src/mongo/s/catalog/sharding_catalog_test.cpp2
-rw-r--r--src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp13
-rw-r--r--src/mongo/s/write_ops/batch_downconvert.cpp11
-rw-r--r--src/mongo/scripting/SConscript1
-rw-r--r--src/mongo/util/fail_point_registry.cpp2
34 files changed, 194 insertions, 59 deletions
diff --git a/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml b/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml
index 62549ec9346..ca1b1aaba0d 100644
--- a/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml
+++ b/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml
@@ -169,8 +169,8 @@ executor:
assert.commandWorked(res);
} else {
// If 'username' already exists, then attempts to create a user with the same name
- // will fail with a duplicate key error.
- assert.commandFailedWithCode(res, ErrorCodes.DuplicateKey);
+ // will fail with error code 51003.
+ assert.commandFailedWithCode(res, 51003);
}
// Log out as the __system user and auth as the newly created user.
diff --git a/src/mongo/base/error_codes.err b/src/mongo/base/error_codes.err
index c46116b6c11..5dcfaf5d878 100644
--- a/src/mongo/base/error_codes.err
+++ b/src/mongo/base/error_codes.err
@@ -281,7 +281,7 @@ error_code("OBSOLETE_RecvStaleConfig", 9996)
error_code("NotMaster", 10107)
error_code("CannotGrowDocumentInCappedNamespace", 10003)
error_code("BSONObjectTooLarge", 10334)
-error_code("DuplicateKey", 11000)
+error_code("DuplicateKey", 11000, extra="DuplicateKeyErrorInfo")
error_code("InterruptedAtShutdown", 11600)
error_code("Interrupted", 11601)
error_code("InterruptedDueToStepDown", 11602)
diff --git a/src/mongo/base/initializer_dependency_graph.cpp b/src/mongo/base/initializer_dependency_graph.cpp
index 7469f7e1138..c07b993ce36 100644
--- a/src/mongo/base/initializer_dependency_graph.cpp
+++ b/src/mongo/base/initializer_dependency_graph.cpp
@@ -49,7 +49,7 @@ Status InitializerDependencyGraph::addInitializer(std::string name,
InitializerDependencyNode& newNode = _nodes[name];
if (newNode.initFn) {
- return Status(ErrorCodes::DuplicateKey, name);
+ return Status(ErrorCodes::Error(50999), name);
}
newNode.initFn = std::move(initFn);
diff --git a/src/mongo/base/initializer_dependency_graph_test.cpp b/src/mongo/base/initializer_dependency_graph_test.cpp
index 20bb5c6ebb3..890ddba60c1 100644
--- a/src/mongo/base/initializer_dependency_graph_test.cpp
+++ b/src/mongo/base/initializer_dependency_graph_test.cpp
@@ -75,8 +75,8 @@ TEST(InitializerDependencyGraphTest, InsertSameNameTwiceFails) {
InitializerDependencyGraph graph;
ASSERT_ADD_INITIALIZER(graph, "A", doNothing, MONGO_NO_PREREQUISITES, MONGO_NO_DEPENDENTS);
ASSERT_EQUALS(
- ErrorCodes::DuplicateKey,
- ADD_INITIALIZER(graph, "A", doNothing, MONGO_NO_PREREQUISITES, MONGO_NO_DEPENDENTS));
+ 50999,
+ ADD_INITIALIZER(graph, "A", doNothing, MONGO_NO_PREREQUISITES, MONGO_NO_DEPENDENTS).code());
}
TEST(InitializerDependencyGraphTest, TopSortEmptyGraph) {
diff --git a/src/mongo/bson/util/bson_check.h b/src/mongo/bson/util/bson_check.h
index 250256208ba..ba9407353cf 100644
--- a/src/mongo/bson/util/bson_check.h
+++ b/src/mongo/bson/util/bson_check.h
@@ -43,8 +43,8 @@ namespace mongo {
* Confirms that obj only contains field names where allowed(name) returns true,
* and that no field name occurs multiple times.
*
- * On failure, returns BadValue and a message naming the unexpected field or DuplicateKey and a
- * message naming the repeated field. "objectName" is included in the message, for reporting
+ * On failure, returns BadValue and a message naming the unexpected field or error code 51000 with
+ * a message naming a repeated field. "objectName" is included in the message, for reporting
* purposes.
*/
template <typename Condition>
@@ -65,7 +65,7 @@ Status bsonCheckOnlyHasFieldsImpl(StringData objectName,
if (!seenBefore) {
seenBefore = true;
} else {
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(51000),
str::stream() << "Field " << name << " appears multiple times in "
<< objectName);
}
diff --git a/src/mongo/bson/util/bson_check_test.cpp b/src/mongo/bson/util/bson_check_test.cpp
index 6c2fa1e0ca7..955af664a21 100644
--- a/src/mongo/bson/util/bson_check_test.cpp
+++ b/src/mongo/bson/util/bson_check_test.cpp
@@ -77,9 +77,10 @@ TEST(BsonCheck, CheckHasOnlyLegalFields) {
}
TEST(BsonCheck, CheckNoDuplicates) {
- ASSERT_EQUALS(ErrorCodes::DuplicateKey,
+ ASSERT_EQUALS(51000,
bsonCheckOnlyHasFields(
- "", BSON("aField" << 1 << "anotherField" << 2 << "aField" << 3), legals));
+ "", BSON("aField" << 1 << "anotherField" << 2 << "aField" << 3), legals)
+ .code());
}
} // namespace
diff --git a/src/mongo/db/auth/role_graph.cpp b/src/mongo/db/auth/role_graph.cpp
index 0ed793d1052..db93d71ab00 100644
--- a/src/mongo/db/auth/role_graph.cpp
+++ b/src/mongo/db/auth/role_graph.cpp
@@ -81,7 +81,7 @@ bool RoleGraph::_roleExistsDontCreateBuiltin(const RoleName& role) {
Status RoleGraph::createRole(const RoleName& role) {
if (roleExists(role)) {
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(51007),
mongoutils::str::stream() << "Role: " << role.getFullName()
<< " already exists");
}
@@ -403,7 +403,7 @@ Status RoleGraph::replaceRole(const RoleName& roleName,
for (size_t i = 0; i < roles.size(); ++i) {
const RoleName& grantedRole = roles[i];
status = createRole(grantedRole);
- fassert(17170, status.isOK() || status == ErrorCodes::DuplicateKey);
+ fassert(17170, status.isOK() || status.code() == 51007);
fassert(17171, addRoleToRole(roleName, grantedRole));
}
fassert(17172, addPrivilegesToRole(roleName, privileges));
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index f190e6c41e4..18d112112b9 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -419,7 +419,7 @@ Status insertRoleDocument(OperationContext* opCtx, const BSONObj& roleObj) {
if (status.code() == ErrorCodes::DuplicateKey) {
std::string name = roleObj[AuthorizationManager::ROLE_NAME_FIELD_NAME].String();
std::string source = roleObj[AuthorizationManager::ROLE_DB_FIELD_NAME].String();
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(51002),
str::stream() << "Role \"" << name << "@" << source << "\" already exists");
}
if (status.code() == ErrorCodes::UnknownError) {
@@ -478,7 +478,7 @@ Status insertPrivilegeDocument(OperationContext* opCtx, const BSONObj& userObj)
if (status.code() == ErrorCodes::DuplicateKey) {
std::string name = userObj[AuthorizationManager::USER_NAME_FIELD_NAME].String();
std::string source = userObj[AuthorizationManager::USER_DB_FIELD_NAME].String();
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(51003),
str::stream() << "User \"" << name << "@" << source << "\" already exists");
}
if (status.code() == ErrorCodes::UnknownError) {
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index 5d980e5814c..ed2fee3df8a 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -51,6 +51,7 @@
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/server_parameters.h"
#include "mongo/db/stats/counters.h"
+#include "mongo/db/storage/duplicate_key_error_info.h"
#include "mongo/db/transaction_participant.h"
#include "mongo/db/write_concern.h"
#include "mongo/s/stale_exception.h"
@@ -150,7 +151,11 @@ void serializeReply(OperationContext* opCtx,
}
} else {
error.append("code", int(status.code()));
+ if (auto const extraInfo = status.extraInfo()) {
+ extraInfo->serialize(&error);
+ }
}
+
error.append("errmsg", errorMessage(status.reason()));
errors.push_back(error.obj());
}
diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp
index 9edb6be9bc8..ff37a113538 100644
--- a/src/mongo/db/repl/apply_ops.cpp
+++ b/src/mongo/db/repl/apply_ops.cpp
@@ -551,7 +551,7 @@ Status applyOps(OperationContext* opCtx,
result->append("codeName", ErrorCodes::errorString(ex.code()));
result->append("errmsg", ex.what());
result->append("results", ab.arr());
- return Status(ex.code(), ex.what());
+ return ex.toStatus();
}
return Status::OK();
diff --git a/src/mongo/db/repl/database_cloner.cpp b/src/mongo/db/repl/database_cloner.cpp
index b9c1e23edea..e23e2ea145e 100644
--- a/src/mongo/db/repl/database_cloner.cpp
+++ b/src/mongo/db/repl/database_cloner.cpp
@@ -346,7 +346,7 @@ void DatabaseCloner::_listCollectionsCallback(const StatusWith<Fetcher::QueryRes
const std::string collectionName = nameElement.String();
if (seen.find(collectionName) != seen.end()) {
_finishCallback_inlock(lk,
- {ErrorCodes::DuplicateKey,
+ {ErrorCodes::Error(51005),
str::stream()
<< "collection info contains duplicate collection name "
<< "'"
diff --git a/src/mongo/db/repl/database_cloner_test.cpp b/src/mongo/db/repl/database_cloner_test.cpp
index 83c428340a7..7e594adbc59 100644
--- a/src/mongo/db/repl/database_cloner_test.cpp
+++ b/src/mongo/db/repl/database_cloner_test.cpp
@@ -541,7 +541,7 @@ TEST_F(DatabaseClonerTest, CollectionInfoNameDuplicate) {
<< _options2.toBSON()))));
}
- ASSERT_EQUALS(ErrorCodes::DuplicateKey, getStatus().code());
+ ASSERT_EQUALS(51005, getStatus().code());
ASSERT_STRING_CONTAINS(getStatus().reason(), "duplicate collection name 'a'");
ASSERT_FALSE(_databaseCloner->isActive());
ASSERT_EQUALS(DatabaseCloner::State::kComplete, _databaseCloner->getState_forTest());
diff --git a/src/mongo/db/repl/repl_set_config.cpp b/src/mongo/db/repl/repl_set_config.cpp
index e79ffa8fe89..731b2ed8f9f 100644
--- a/src/mongo/db/repl/repl_set_config.cpp
+++ b/src/mongo/db/repl/repl_set_config.cpp
@@ -353,7 +353,7 @@ Status ReplSetConfig::_parseSettingsSubdocument(const BSONObj& settings) {
for (auto&& modeElement : gleModes) {
if (_customWriteConcernModes.find(modeElement.fieldNameStringData()) !=
_customWriteConcernModes.end()) {
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(51001),
str::stream() << kSettingsFieldName << '.' << kGetLastErrorModesFieldName
<< " contains multiple fields named "
<< modeElement.fieldName());
diff --git a/src/mongo/db/repl/repl_set_config_checks.cpp b/src/mongo/db/repl/repl_set_config_checks.cpp
index 4105db31efe..07cff16f595 100644
--- a/src/mongo/db/repl/repl_set_config_checks.cpp
+++ b/src/mongo/db/repl/repl_set_config_checks.cpp
@@ -79,7 +79,7 @@ StatusWith<int> findSelfInConfig(ReplicationCoordinatorExternalState* externalSt
<< " all map to this node in new configuration version "
<< newConfig.getConfigVersion() << " for replica set "
<< newConfig.getReplSetName();
- return StatusWith<int>(ErrorCodes::DuplicateKey, message);
+ return StatusWith<int>(ErrorCodes::InvalidReplicaSetConfig, message);
}
int myIndex = std::distance(newConfig.membersBegin(), meConfigs.front());
diff --git a/src/mongo/db/repl/repl_set_config_checks_test.cpp b/src/mongo/db/repl/repl_set_config_checks_test.cpp
index 482ca06e992..edea5453109 100644
--- a/src/mongo/db/repl/repl_set_config_checks_test.cpp
+++ b/src/mongo/db/repl/repl_set_config_checks_test.cpp
@@ -90,7 +90,7 @@ TEST_F(ServiceContextTest, ValidateConfigForInitiate_MustFindSelf) {
validateConfigForInitiate(&notPresentExternalState, config, getGlobalServiceContext())
.getStatus());
ASSERT_EQUALS(
- ErrorCodes::DuplicateKey,
+ ErrorCodes::InvalidReplicaSetConfig,
validateConfigForInitiate(&presentTwiceExternalState, config, getGlobalServiceContext())
.getStatus());
ASSERT_EQUALS(1,
@@ -703,7 +703,7 @@ TEST_F(ServiceContextTest, ValidateConfigForReconfig_MustFindSelf) {
&notPresentExternalState, oldConfig, newConfig, getGlobalServiceContext(), false)
.getStatus());
ASSERT_EQUALS(
- ErrorCodes::DuplicateKey,
+ ErrorCodes::InvalidReplicaSetConfig,
validateConfigForReconfig(
&presentThriceExternalState, oldConfig, newConfig, getGlobalServiceContext(), false)
.getStatus());
@@ -718,7 +718,7 @@ TEST_F(ServiceContextTest, ValidateConfigForReconfig_MustFindSelf) {
&notPresentExternalState, oldConfig, newConfig, getGlobalServiceContext(), true)
.getStatus());
ASSERT_EQUALS(
- ErrorCodes::DuplicateKey,
+ ErrorCodes::InvalidReplicaSetConfig,
validateConfigForReconfig(
&presentThriceExternalState, oldConfig, newConfig, getGlobalServiceContext(), true)
.getStatus());
diff --git a/src/mongo/db/repl/repl_set_config_test.cpp b/src/mongo/db/repl/repl_set_config_test.cpp
index ebcc4b62773..8da994e68d7 100644
--- a/src/mongo/db/repl/repl_set_config_test.cpp
+++ b/src/mongo/db/repl/repl_set_config_test.cpp
@@ -820,7 +820,7 @@ TEST(ReplSetConfig, ParseFailsWithDuplicateGetLastErrorModesField) {
<< BSON("getLastErrorModes"
<< BSON("one" << BSON("tag" << 1) << "one"
<< BSON("tag" << 1)))));
- ASSERT_EQUALS(ErrorCodes::DuplicateKey, status);
+ ASSERT_EQUALS(51001, status.code());
}
TEST(ReplSetConfig, ParseFailsWithNonObjectGetLastErrorModesEntryField) {
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp
index eaca1134471..3f237917497 100644
--- a/src/mongo/db/repl/replication_coordinator_impl.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl.cpp
@@ -556,7 +556,7 @@ void ReplicationCoordinatorImpl::_finishLoadLocalConfig(
validateConfigForStartUp(_externalState.get(), localConfig, getServiceContext());
if (!myIndex.isOK()) {
if (myIndex.getStatus() == ErrorCodes::NodeNotFound ||
- myIndex.getStatus() == ErrorCodes::DuplicateKey) {
+ myIndex.getStatus() == ErrorCodes::InvalidReplicaSetConfig) {
warning() << "Locally stored replica set configuration does not have a valid entry "
"for the current node; waiting for reconfig or remote heartbeat; Got \""
<< myIndex.getStatus() << "\" while validating " << localConfig.toBSON();
diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
index f61fcd057b6..72fc9a9cbfe 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
@@ -594,7 +594,7 @@ void ReplicationCoordinatorImpl::_heartbeatReconfigFinish(
log() << "Cannot find self in new replica set configuration; I must be removed; "
<< myIndex.getStatus();
break;
- case ErrorCodes::DuplicateKey:
+ case ErrorCodes::InvalidReplicaSetConfig:
error() << "Several entries in new config represent this node; "
"Removing self until an acceptable configuration arrives; "
<< myIndex.getStatus();
diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp
index 8e19ad74a65..4511d070a79 100644
--- a/src/mongo/db/s/migration_destination_manager.cpp
+++ b/src/mongo/db/s/migration_destination_manager.cpp
@@ -401,7 +401,7 @@ void MigrationDestinationManager::cloneDocumentsFromDonor(
}
} catch (...) {
stdx::lock_guard<Client> lk(*opCtx->getClient());
- opCtx->getServiceContext()->killOperation(opCtx, exceptionToStatus().code());
+ opCtx->getServiceContext()->killOperation(opCtx, ErrorCodes::Error(51008));
log() << "Batch insertion failed " << causedBy(redact(exceptionToStatus()));
}
}};
diff --git a/src/mongo/db/s/migration_destination_manager_test.cpp b/src/mongo/db/s/migration_destination_manager_test.cpp
index 3d2b7fb4ba3..1b1cf8e12f3 100644
--- a/src/mongo/db/s/migration_destination_manager_test.cpp
+++ b/src/mongo/db/s/migration_destination_manager_test.cpp
@@ -152,10 +152,10 @@ TEST_F(MigrationDestinationManagerTest, CloneDocumentsCatchesInsertErrors) {
ASSERT_THROWS_CODE_AND_WHAT(MigrationDestinationManager::cloneDocumentsFromDonor(
operationContext(), insertBatchFn, fetchBatchFn),
DBException,
- ErrorCodes::FailedToParse,
+ 51008,
"operation was interrupted");
- ASSERT_EQ(operationContext()->getKillStatus(), ErrorCodes::FailedToParse);
+ ASSERT_EQ(operationContext()->getKillStatus(), 51008);
}
} // namespace
diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript
index ad1295dfb0a..f25c138ced7 100644
--- a/src/mongo/db/storage/SConscript
+++ b/src/mongo/db/storage/SConscript
@@ -33,6 +33,17 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ 'duplicate_key_error_info',
+ ],
+ )
+
+env.Library(
+ target='duplicate_key_error_info',
+ source=[
+ 'duplicate_key_error_info.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
],
)
diff --git a/src/mongo/db/storage/duplicate_key_error_info.cpp b/src/mongo/db/storage/duplicate_key_error_info.cpp
new file mode 100644
index 00000000000..911b3de0381
--- /dev/null
+++ b/src/mongo/db/storage/duplicate_key_error_info.cpp
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * 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
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * 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 Server Side 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/storage/duplicate_key_error_info.h"
+
+#include "mongo/base/init.h"
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/util/assert_util.h"
+
+namespace mongo {
+namespace {
+
+MONGO_INIT_REGISTER_ERROR_EXTRA_INFO(DuplicateKeyErrorInfo);
+
+} // namespace
+
+void DuplicateKeyErrorInfo::serialize(BSONObjBuilder* bob) const {
+ bob->append("keyPattern", _keyPattern);
+}
+
+std::shared_ptr<const ErrorExtraInfo> DuplicateKeyErrorInfo::parse(const BSONObj& obj) {
+ return std::make_shared<DuplicateKeyErrorInfo>(obj["keyPattern"].Obj());
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/storage/duplicate_key_error_info.h b/src/mongo/db/storage/duplicate_key_error_info.h
new file mode 100644
index 00000000000..06a17cce94c
--- /dev/null
+++ b/src/mongo/db/storage/duplicate_key_error_info.h
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * 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
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * 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 Server Side 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 "mongo/base/error_extra_info.h"
+#include "mongo/bson/bsonobj.h"
+#include "mongo/bson/bsonobjbuilder.h"
+
+namespace mongo {
+
+/**
+ * Represents an error returned from the storage engine when an attempt to insert a
+ * key into a unique index fails because the same key already exists.
+ */
+class DuplicateKeyErrorInfo final : public ErrorExtraInfo {
+public:
+ static constexpr auto code = ErrorCodes::DuplicateKey;
+
+ static std::shared_ptr<const ErrorExtraInfo> parse(const BSONObj&);
+
+ explicit DuplicateKeyErrorInfo(const BSONObj& keyPattern)
+ : _keyPattern(keyPattern.getOwned()) {}
+
+ void serialize(BSONObjBuilder* bob) const override;
+
+ BSONObj toBSON() const {
+ BSONObjBuilder bob;
+ serialize(&bob);
+ return bob.obj();
+ }
+
+ const BSONObj& getKeyPattern() const {
+ return _keyPattern;
+ }
+
+private:
+ const BSONObj _keyPattern;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/storage/index_entry_comparison.cpp b/src/mongo/db/storage/index_entry_comparison.cpp
index 242df839462..67613639633 100644
--- a/src/mongo/db/storage/index_entry_comparison.cpp
+++ b/src/mongo/db/storage/index_entry_comparison.cpp
@@ -29,10 +29,12 @@
*/
#include "mongo/platform/basic.h"
+#include "mongo/db/storage/index_entry_comparison.h"
+
#include <ostream>
#include "mongo/db/jsobj.h"
-#include "mongo/db/storage/index_entry_comparison.h"
+#include "mongo/db/storage/duplicate_key_error_info.h"
namespace mongo {
@@ -193,7 +195,7 @@ Status buildDupKeyErrorStatus(const BSONObj& key,
}
sb << builder.obj();
- return Status(ErrorCodes::DuplicateKey, sb.str());
+ return Status(DuplicateKeyErrorInfo(keyPattern), sb.str());
}
} // namespace mongo
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
index f02781c956d..fb524735923 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
@@ -188,7 +188,7 @@ Status WiredTigerUtil::getApplicationMetadata(OperationContext* opCtx,
while ((ret = parser.next(&keyItem, &valueItem)) == 0) {
const StringData key(keyItem.str, keyItem.len);
if (keysSeen.count(key)) {
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(50998),
str::stream() << "app_metadata must not contain duplicate keys. "
<< "Found multiple instances of key '"
<< key
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
index 58f9aa63548..a3431d77cd3 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
@@ -186,7 +186,7 @@ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataDuplicateKeys) {
StatusWith<BSONObj> result =
WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
ASSERT_NOT_OK(result.getStatus());
- ASSERT_EQUALS(ErrorCodes::DuplicateKey, result.getStatus().code());
+ ASSERT_EQUALS(50998, result.getStatus().code());
}
TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataTypes) {
diff --git a/src/mongo/s/catalog/SConscript b/src/mongo/s/catalog/SConscript
index f37bf3fefc6..72d095847c9 100644
--- a/src/mongo/s/catalog/SConscript
+++ b/src/mongo/s/catalog/SConscript
@@ -77,6 +77,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/repl/read_concern_args',
+ '$BUILD_DIR/mongo/db/storage/duplicate_key_error_info',
'$BUILD_DIR/mongo/executor/network_interface',
'$BUILD_DIR/mongo/s/client/sharding_client',
'$BUILD_DIR/mongo/s/coreshard',
@@ -127,6 +128,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/auth/authmocks',
+ '$BUILD_DIR/mongo/db/storage/duplicate_key_error_info',
'$BUILD_DIR/mongo/s/catalog/dist_lock_catalog_mock',
'$BUILD_DIR/mongo/s/catalog/sharding_catalog_client_mock',
'$BUILD_DIR/mongo/s/shard_server_test_fixture',
@@ -142,6 +144,7 @@ env.CppUnitTest(
'sharding_catalog_write_retry_test.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/storage/duplicate_key_error_info',
'$BUILD_DIR/mongo/s/sharding_router_test_fixture',
]
)
diff --git a/src/mongo/s/catalog/dist_lock_catalog_impl_test.cpp b/src/mongo/s/catalog/dist_lock_catalog_impl_test.cpp
index f09b53fa36a..8eac156a8ba 100644
--- a/src/mongo/s/catalog/dist_lock_catalog_impl_test.cpp
+++ b/src/mongo/s/catalog/dist_lock_catalog_impl_test.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/commands.h"
#include "mongo/db/query/find_and_modify_request.h"
#include "mongo/db/repl/read_concern_args.h"
+#include "mongo/db/storage/duplicate_key_error_info.h"
#include "mongo/executor/network_interface_mock.h"
#include "mongo/executor/network_test_env.h"
#include "mongo/s/catalog/dist_lock_catalog_impl.h"
@@ -437,11 +438,7 @@ TEST_F(DistLockCatalogTest, GrabLockDupKeyError) {
});
onCommand([](const RemoteCommandRequest& request) -> StatusWith<BSONObj> {
- return fromjson(R"({
- ok: 0,
- errmsg: "duplicate key error",
- code: 11000
- })");
+ return Status({DuplicateKeyErrorInfo(BSON("x" << 1)), "Mock duplicate key error"});
});
future.timed_get(kFutureTimeout);
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
index 048656f4426..b0370563860 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
@@ -793,11 +793,10 @@ Status ShardingCatalogClientImpl::insertConfigDocument(OperationContext* opCtx,
auto existingDocs = fetchDuplicate.getValue().value;
if (existingDocs.empty()) {
- return {ErrorCodes::DuplicateKey,
- stream() << "DuplicateKey error was returned after a retry attempt, but no "
- "documents were found. This means a concurrent change occurred "
- "together with the retries. Original error was "
- << status.toString()};
+ return {status.withContext(
+ stream() << "DuplicateKey error was returned after a retry attempt, but no "
+ "documents were found. This means a concurrent change occurred "
+ "together with the retries.")};
}
invariant(existingDocs.size() == 1);
diff --git a/src/mongo/s/catalog/sharding_catalog_test.cpp b/src/mongo/s/catalog/sharding_catalog_test.cpp
index af95c186612..5b7703dd0f7 100644
--- a/src/mongo/s/catalog/sharding_catalog_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_test.cpp
@@ -1221,7 +1221,7 @@ TEST_F(ShardingCatalogClientTest, ApplyChunkOpsDeprecatedSuccessfulWithCheck) {
onCommand([&](const RemoteCommandRequest& request) {
BSONObjBuilder responseBuilder;
CommandHelpers::appendCommandStatusNoThrow(
- responseBuilder, Status(ErrorCodes::DuplicateKey, "precondition failed"));
+ responseBuilder, Status(ErrorCodes::Error(51004), "precondition failed"));
return responseBuilder.obj();
});
diff --git a/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp b/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp
index 03aa7a924e6..7ce5acce70c 100644
--- a/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp
@@ -40,6 +40,7 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/ops/write_ops.h"
+#include "mongo/db/storage/duplicate_key_error_info.h"
#include "mongo/db/write_concern.h"
#include "mongo/executor/network_interface_mock.h"
#include "mongo/executor/task_executor.h"
@@ -78,6 +79,10 @@ const NamespaceString kTestNamespace("config.TestColl");
const HostAndPort kTestHosts[] = {
HostAndPort("TestHost1:12345"), HostAndPort("TestHost2:12345"), HostAndPort("TestHost3:12345")};
+Status getMockDuplicateKeyError() {
+ return {DuplicateKeyErrorInfo(BSON("mock" << 1)), "Mock duplicate key error"};
+}
+
TEST_F(InsertRetryTest, RetryOnInterruptedAndNetworkErrorSuccess) {
configTargeter()->setFindHostReturnValue({kTestHosts[0]});
@@ -168,7 +173,7 @@ TEST_F(InsertRetryTest, DuplicateKeyErrorAfterNetworkErrorMatch) {
onCommand([&](const RemoteCommandRequest& request) {
ASSERT_EQ(request.target, kTestHosts[1]);
- return Status(ErrorCodes::DuplicateKey, "Duplicate key");
+ return getMockDuplicateKeyError();
});
onFindCommand([&](const RemoteCommandRequest& request) {
@@ -206,7 +211,7 @@ TEST_F(InsertRetryTest, DuplicateKeyErrorAfterNetworkErrorNotFound) {
onCommand([&](const RemoteCommandRequest& request) {
ASSERT_EQ(request.target, kTestHosts[1]);
- return Status(ErrorCodes::DuplicateKey, "Duplicate key");
+ return getMockDuplicateKeyError();
});
onFindCommand([&](const RemoteCommandRequest& request) {
@@ -244,7 +249,7 @@ TEST_F(InsertRetryTest, DuplicateKeyErrorAfterNetworkErrorMismatch) {
onCommand([&](const RemoteCommandRequest& request) {
ASSERT_EQ(request.target, kTestHosts[1]);
- return Status(ErrorCodes::DuplicateKey, "Duplicate key");
+ return getMockDuplicateKeyError();
});
onFindCommand([&](const RemoteCommandRequest& request) {
@@ -300,7 +305,7 @@ TEST_F(InsertRetryTest, DuplicateKeyErrorAfterWriteConcernFailureMatch) {
onCommand([&](const RemoteCommandRequest& request) {
ASSERT_EQ(request.target, kTestHosts[0]);
- return Status(ErrorCodes::DuplicateKey, "Duplicate key");
+ return getMockDuplicateKeyError();
});
onFindCommand([&](const RemoteCommandRequest& request) {
diff --git a/src/mongo/s/write_ops/batch_downconvert.cpp b/src/mongo/s/write_ops/batch_downconvert.cpp
index 58b1a6fdd25..cb34dc39b44 100644
--- a/src/mongo/s/write_ops/batch_downconvert.cpp
+++ b/src/mongo/s/write_ops/batch_downconvert.cpp
@@ -33,6 +33,7 @@
#include "mongo/s/write_ops/batch_downconvert.h"
#include "mongo/bson/bsonmisc.h"
+#include "mongo/db/storage/duplicate_key_error_info.h"
namespace mongo {
@@ -100,16 +101,6 @@ Status extractGLEErrors(const BSONObj& gleResponse, GLEErrors* errors) {
// Write error
errors->writeError.reset(new WriteErrorDetail);
int writeErrorCode = code == 0 ? ErrorCodes::UnknownError : code;
-
- // COMPATIBILITY
- // Certain clients expect write commands to always report 11000 for duplicate key
- // errors, while legacy GLE can return additional codes.
- if (writeErrorCode == 11001 /* dup key in update */
- ||
- writeErrorCode == 12582 /* dup key capped */) {
- writeErrorCode = ErrorCodes::DuplicateKey;
- }
-
errors->writeError->setStatus({ErrorCodes::Error(writeErrorCode), err});
} else if (!jNote.empty()) {
// Know this is legacy gle and the journaling not enforced - write concern error in 2.4
diff --git a/src/mongo/scripting/SConscript b/src/mongo/scripting/SConscript
index edbc90ce365..75d36873081 100644
--- a/src/mongo/scripting/SConscript
+++ b/src/mongo/scripting/SConscript
@@ -153,6 +153,7 @@ if usemozjs:
'scripting_common',
'$BUILD_DIR/mongo/shell/mongojs',
'$BUILD_DIR/mongo/db/service_context',
+ '$BUILD_DIR/mongo/db/storage/duplicate_key_error_info',
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/client/clientdriver_network',
diff --git a/src/mongo/util/fail_point_registry.cpp b/src/mongo/util/fail_point_registry.cpp
index e00afc617a2..0a71e4a5f82 100644
--- a/src/mongo/util/fail_point_registry.cpp
+++ b/src/mongo/util/fail_point_registry.cpp
@@ -48,7 +48,7 @@ Status FailPointRegistry::addFailPoint(const string& name, FailPoint* failPoint)
}
if (_fpMap.count(name) > 0) {
- return Status(ErrorCodes::DuplicateKey,
+ return Status(ErrorCodes::Error(51006),
stream() << "Fail point already registered: " << name);
}