diff options
| -rw-r--r-- | jstests/replsets/write_concern_bulkWrite_to_local.js | 69 | ||||
| -rw-r--r-- | src/mongo/db/service_entry_point_mongod.cpp | 11 | ||||
| -rw-r--r-- | src/mongo/s/commands/strategy.cpp | 16 |
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))); |
