summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2019-08-26 22:49:27 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-04-06 20:05:00 +0000
commit6894f176cac940406c9de66b3d091c2e6044afc3 (patch)
treefafc4f9f50875043b3e0d5cc90df2639a3861e82
parentf49bac6306ed96f3cb0db2e1895d706710eeb8a3 (diff)
downloadmongo-6894f176cac940406c9de66b3d091c2e6044afc3.tar.gz
SERVER-43011 Add optional namespace restriction to failCommand failpoint
(cherry picked from commit f7cd49a1930516cea21437bd7a32e7f8bbf0a006)
-rw-r--r--jstests/core/failcommand_failpoint.js43
-rw-r--r--src/mongo/db/commands.cpp13
-rw-r--r--src/mongo/db/commands.h7
-rw-r--r--src/mongo/db/service_entry_point_common.cpp4
-rw-r--r--src/mongo/s/commands/strategy.cpp4
5 files changed, 62 insertions, 9 deletions
diff --git a/jstests/core/failcommand_failpoint.js b/jstests/core/failcommand_failpoint.js
index e78d39e3d50..4e94e052f8a 100644
--- a/jstests/core/failcommand_failpoint.js
+++ b/jstests/core/failcommand_failpoint.js
@@ -285,4 +285,47 @@ res = testDB.runCommand({insert: "test", documents: [{a: "something else"}]});
assert.commandWorkedIgnoringWriteConcernErrors(res);
assert.eq(res.writeConcernError, {code: 12345, errmsg: "hello"});
assert.commandWorked(testDB.runCommand({insert: "test", documents: [{b: "or_other"}]}));
+
+//
+// Test that the namespace parameter is obeyed.
+//
+assert.commandWorked(adminDB.runCommand({
+ configureFailPoint: "failCommand",
+ mode: {times: 1},
+ data: {
+ errorCode: ErrorCodes.InternalError,
+ failCommands: ["find"],
+ namespace: testDB.getName() + ".foo",
+ threadName: threadName,
+ }
+}));
+
+// A find against a different namespace should not trigger the failpoint.
+assert.commandWorked(testDB.runCommand({find: "test"}));
+
+// A find against the namespace given to the failpoint should trigger the failpoint.
+assert.commandFailedWithCode(testDB.runCommand({find: "foo"}), ErrorCodes.InternalError);
+
+//
+// Test that the namespace parameter is obeyed for write concern errors.
+//
+assert.commandWorked(adminDB.runCommand({
+ configureFailPoint: "failCommand",
+ mode: {times: 1},
+ data: {
+ failCommands: ["insert"],
+ namespace: testDB.getName() + ".foo",
+ threadName: threadName,
+ writeConcernError: {code: ErrorCodes.InternalError, errmsg: "foo"},
+ }
+}));
+
+// An insert to a different namespace should not trigger the failpoint.
+assert.commandWorked(
+ testDB.runCommand({insert: "test", documents: [{x: "doc_for_namespace_no_wce"}]}));
+
+// An insert to the namespace given to the failpoint should trigger the failpoint.
+res = assert.commandWorkedIgnoringWriteConcernErrors(testDB.runCommand(
+ {insert: "foo", documents: [{x: "doc_for_namespace_case_should_trigger_wce"}]}));
+assert.eq(res.writeConcernError, {code: ErrorCodes.InternalError, errmsg: "foo"});
}());
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 89ae334d63b..fc356126564 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -460,7 +460,8 @@ MONGO_FAIL_POINT_DEFINE(waitInCommandMarkKillOnClientDisconnect);
bool CommandHelpers::shouldActivateFailCommandFailPoint(const BSONObj& data,
StringData cmdName,
- Client* client) {
+ Client* client,
+ const NamespaceString& nss) {
if (cmdName == "configureFailPoint"_sd) // Banned even if in failCommands.
return false;
@@ -481,6 +482,10 @@ bool CommandHelpers::shouldActivateFailCommandFailPoint(const BSONObj& data,
return false;
}
+ if (data.hasField("namespace") && nss != NamespaceString(data.getStringField("namespace"))) {
+ return false;
+ }
+
for (auto&& failCommand : data.getObjectField("failCommands")) {
if (failCommand.type() == String && failCommand.valueStringData() == cmdName) {
return true;
@@ -490,7 +495,9 @@ bool CommandHelpers::shouldActivateFailCommandFailPoint(const BSONObj& data,
return false;
}
-void CommandHelpers::evaluateFailCommandFailPoint(OperationContext* opCtx, StringData commandName) {
+void CommandHelpers::evaluateFailCommandFailPoint(OperationContext* opCtx,
+ StringData commandName,
+ const NamespaceString& nss) {
bool closeConnection, hasErrorCode;
long long errorCode;
@@ -501,7 +508,7 @@ void CommandHelpers::evaluateFailCommandFailPoint(OperationContext* opCtx, Strin
hasErrorCode = data.hasField("errorCode") &&
bsonExtractIntegerField(data, "errorCode", &errorCode).isOK();
- return shouldActivateFailCommandFailPoint(data, commandName, opCtx->getClient()) &&
+ return shouldActivateFailCommandFailPoint(data, commandName, opCtx->getClient(), nss) &&
(closeConnection || hasErrorCode);
}) {
if (closeConnection) {
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 0715354ba07..09a02bbeb28 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -222,12 +222,15 @@ struct CommandHelpers {
*/
static bool shouldActivateFailCommandFailPoint(const BSONObj& data,
StringData cmdName,
- Client* client);
+ Client* client,
+ const NamespaceString& nss);
/**
* Possibly uasserts according to the "failCommand" fail point.
*/
- static void evaluateFailCommandFailPoint(OperationContext* opCtx, StringData commandName);
+ static void evaluateFailCommandFailPoint(OperationContext* opCtx,
+ StringData commandName,
+ const NamespaceString& nss);
/**
* Handles marking kill on client disconnect.
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index 4b0216aac4a..82cf2169c7f 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -571,7 +571,7 @@ bool runCommandImpl(OperationContext* opCtx,
auto waitForWriteConcern = [&](auto&& bb) {
MONGO_FAIL_POINT_BLOCK_IF(failCommand, data, [&](const BSONObj& data) {
return CommandHelpers::shouldActivateFailCommandFailPoint(
- data, request.getCommandName(), opCtx->getClient()) &&
+ data, request.getCommandName(), opCtx->getClient(), invocation->ns()) &&
data.hasField("writeConcernError");
}) {
bb.append(data.getData()["writeConcernError"]);
@@ -716,7 +716,7 @@ void execCommandDatabase(OperationContext* opCtx,
replCoord->getReplicationMode() == repl::ReplicationCoordinator::modeReplSet,
opCtx->getServiceContext()->getStorageEngine()->supportsDocLocking());
- CommandHelpers::evaluateFailCommandFailPoint(opCtx, command->getName());
+ CommandHelpers::evaluateFailCommandFailPoint(opCtx, command->getName(), invocation->ns());
const auto dbname = request.getDatabase().toString();
uassert(
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index 9228f0c0ef3..76e2d0d2fc9 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -300,7 +300,7 @@ void execCommandClient(OperationContext* opCtx,
MONGO_FAIL_POINT_BLOCK_IF(failCommand, data, [&](const BSONObj& data) {
return CommandHelpers::shouldActivateFailCommandFailPoint(
- data, request.getCommandName(), opCtx->getClient()) &&
+ data, request.getCommandName(), opCtx->getClient(), invocation->ns()) &&
data.hasField("writeConcernError");
}) {
body.append(data.getData()["writeConcernError"]);
@@ -407,7 +407,7 @@ void runCommand(OperationContext* opCtx,
boost::optional<RouterOperationContextSession> routerSession;
try {
- CommandHelpers::evaluateFailCommandFailPoint(opCtx, commandName);
+ CommandHelpers::evaluateFailCommandFailPoint(opCtx, commandName, invocation->ns());
if (osi.getAutocommit()) {
routerSession.emplace(opCtx);