summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/replsets/write_concern_bulkWrite_to_local.js69
-rw-r--r--src/mongo/db/service_entry_point_mongod.cpp11
-rw-r--r--src/mongo/s/commands/strategy.cpp16
3 files changed, 91 insertions, 5 deletions
diff --git a/jstests/replsets/write_concern_bulkWrite_to_local.js b/jstests/replsets/write_concern_bulkWrite_to_local.js
new file mode 100644
index 00000000000..dee157a3e26
--- /dev/null
+++ b/jstests/replsets/write_concern_bulkWrite_to_local.js
@@ -0,0 +1,69 @@
+/**
+ * Tests that we are silently ignoring writeConcern when we write to local db.
+ *
+ * @tags: [
+ * # TODO SERVER-52419 Remove this tag.
+ * featureFlagBulkWriteCommand,
+ * ]
+ */
+
+import {
+ restartReplicationOnSecondaries,
+ stopReplicationOnSecondaries
+} from "jstests/libs/write_concern_util.js";
+
+const rst = new ReplSetTest(
+ {nodes: [{}, {rsConfig: {priority: 0}}], nodeOptions: {setParameter: {logLevel: 1}}});
+rst.startSet();
+rst.initiate();
+const primary = rst.getPrimary();
+
+const secondary = rst.getSecondary();
+
+jsTestLog("Write to local db on the secondary node should succeed.");
+secondary.adminCommand({
+ bulkWrite: 1,
+ ops: [{insert: 0, document: {x: 1}}, {insert: 1, document: {x: 1}}],
+ nsInfos: [{ns: "local.test"}, {ns: "local.test1"}]
+});
+secondary.adminCommand({
+ bulkWrite: 1,
+ ops: [{insert: 0, document: {x: 2}}, {insert: 1, document: {x: 2}}],
+ nsInfos: [{ns: "local.test"}, {ns: "local.test1"}],
+ writeConcern: {w: 1}
+});
+secondary.adminCommand({
+ bulkWrite: 1,
+ ops: [{insert: 0, document: {x: 3}}, {insert: 1, document: {x: 3}}],
+ nsInfos: [{ns: "local.test"}, {ns: "local.test1"}],
+ writeConcern: {w: 2}
+});
+
+jsTestLog("Stop replication to prevent primary from satisfying majority write-concern.");
+stopReplicationOnSecondaries(rst, false /* changeReplicaSetDefaultWCToLocal */);
+
+// Advance the primary opTime by doing local dummy write.
+assert.commandWorked(
+ rst.getPrimary().getDB("dummy")["dummy"].insert({x: 'dummy'}, {writeConcern: {w: 1}}));
+
+jsTestLog("Write to local db on the primary node should succeed.");
+primary.adminCommand({
+ bulkWrite: 1,
+ ops: [{insert: 0, document: {x: 4}}, {insert: 1, document: {x: 4}}],
+ nsInfos: [{ns: "local.test"}, {ns: "local.test1"}]
+});
+primary.adminCommand({
+ bulkWrite: 1,
+ ops: [{insert: 0, document: {x: 5}}, {insert: 1, document: {x: 5}}],
+ nsInfos: [{ns: "local.test"}, {ns: "local.test1"}],
+ writeConcern: {w: 1}
+});
+primary.adminCommand({
+ bulkWrite: 1,
+ ops: [{insert: 0, document: {x: 6}}, {insert: 1, document: {x: 6}}],
+ nsInfos: [{ns: "local.test"}, {ns: "local.test1"}],
+ writeConcern: {w: 2}
+});
+
+restartReplicationOnSecondaries(rst);
+rst.stopSet();
diff --git a/src/mongo/db/service_entry_point_mongod.cpp b/src/mongo/db/service_entry_point_mongod.cpp
index d051dd015d5..9967fa79278 100644
--- a/src/mongo/db/service_entry_point_mongod.cpp
+++ b/src/mongo/db/service_entry_point_mongod.cpp
@@ -146,9 +146,16 @@ public:
const repl::OpTime& lastOpBeforeRun,
BSONObjBuilder& commandResponseBuilder) const override {
- // Prevent waiting for writeConcern if the command is changing an unreplicated namespace.
+ // Prevent waiting for writeConcern if the command is changing only unreplicated namespaces.
invariant(invocation);
- if (!invocation->ns().isReplicated()) {
+ bool anyReplicatedNamespace = false;
+ for (auto& ns : invocation->allNamespaces()) {
+ if (ns.isReplicated()) {
+ anyReplicatedNamespace = true;
+ break;
+ }
+ }
+ if (!anyReplicatedNamespace) {
return;
}
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index a643d23f06d..66126bea0ae 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -604,9 +604,19 @@ void ParseAndRunCommand::_parseCommand() {
auto allowTransactionsOnConfigDatabase =
!serverGlobalParams.clusterRole.hasExclusively(ClusterRole::RouterServer) ||
client->isFromSystemConnection();
- // TODO (SERVER-79644): Make this call also use allNamespaces() when applicable.
- validateSessionOptions(
- _osi, opCtx->getService(), command->getName(), {nss}, allowTransactionsOnConfigDatabase);
+
+ // If there are multiple namespaces this command operates on we need to validate them all
+ // explicitly. Otherwise we can use the nss defined above which may be the generic command
+ // namespace.
+ std::vector<NamespaceString> namespaces = {nss};
+ if (_invocation->allNamespaces().size() > 1) {
+ namespaces = _invocation->allNamespaces();
+ }
+ validateSessionOptions(_osi,
+ opCtx->getService(),
+ command->getName(),
+ namespaces,
+ allowTransactionsOnConfigDatabase);
_wc.emplace(uassertStatusOK(WriteConcernOptions::extractWCFromCommand(request.body)));