summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorJudah Schvimer <judah@mongodb.com>2016-04-12 19:11:23 -0400
committerJudah Schvimer <judah@mongodb.com>2016-04-12 19:11:23 -0400
commit7ed530a55304bd9cc2b80c054f379b10d9cea8e2 (patch)
treeff1dac44961da031f3369f0288fb38a347d0d690 /src/mongo/db
parentb0c0acc6767a74ed2e5aa50361ad4474291951f9 (diff)
downloadmongo-7ed530a55304bd9cc2b80c054f379b10d9cea8e2.tar.gz
SERVER-20224 commands that write support writeConcern
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/SConscript12
-rw-r--r--src/mongo/db/auth/sasl_commands.cpp6
-rw-r--r--src/mongo/db/clientlistplugin.cpp4
-rw-r--r--src/mongo/db/commands.cpp13
-rw-r--r--src/mongo/db/commands.h22
-rw-r--r--src/mongo/db/commands/apply_ops_cmd.cpp21
-rw-r--r--src/mongo/db/commands/authentication_commands.cpp6
-rw-r--r--src/mongo/db/commands/authentication_commands.h3
-rw-r--r--src/mongo/db/commands/clone.cpp4
-rw-r--r--src/mongo/db/commands/clone_collection.cpp4
-rw-r--r--src/mongo/db/commands/collection_to_capped.cpp6
-rw-r--r--src/mongo/db/commands/compact.cpp3
-rw-r--r--src/mongo/db/commands/conn_pool_stats.cpp4
-rw-r--r--src/mongo/db/commands/conn_pool_sync.cpp3
-rw-r--r--src/mongo/db/commands/connection_status.cpp3
-rw-r--r--src/mongo/db/commands/copydb.cpp3
-rw-r--r--src/mongo/db/commands/copydb_start_commands.cpp8
-rw-r--r--src/mongo/db/commands/count_cmd.cpp3
-rw-r--r--src/mongo/db/commands/cpuprofile.cpp3
-rw-r--r--src/mongo/db/commands/create_indexes.cpp3
-rw-r--r--src/mongo/db/commands/current_op.cpp4
-rw-r--r--src/mongo/db/commands/dbhash.cpp4
-rw-r--r--src/mongo/db/commands/distinct.cpp3
-rw-r--r--src/mongo/db/commands/drop_indexes.cpp6
-rw-r--r--src/mongo/db/commands/explain_cmd.cpp4
-rw-r--r--src/mongo/db/commands/fail_point_cmd.cpp4
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp24
-rw-r--r--src/mongo/db/commands/find_cmd.cpp4
-rw-r--r--src/mongo/db/commands/fsync.cpp7
-rw-r--r--src/mongo/db/commands/generic.cpp28
-rw-r--r--src/mongo/db/commands/geo_near_cmd.cpp3
-rw-r--r--src/mongo/db/commands/get_last_error.cpp9
-rw-r--r--src/mongo/db/commands/getmore_cmd.cpp4
-rw-r--r--src/mongo/db/commands/group_cmd.cpp4
-rw-r--r--src/mongo/db/commands/hashcmd.cpp3
-rw-r--r--src/mongo/db/commands/index_filter_commands.cpp4
-rw-r--r--src/mongo/db/commands/index_filter_commands.h2
-rw-r--r--src/mongo/db/commands/isself.cpp3
-rw-r--r--src/mongo/db/commands/kill_op.cpp4
-rw-r--r--src/mongo/db/commands/killcursors_common.h4
-rw-r--r--src/mongo/db/commands/list_collections.cpp3
-rw-r--r--src/mongo/db/commands/list_databases.cpp3
-rw-r--r--src/mongo/db/commands/list_indexes.cpp3
-rw-r--r--src/mongo/db/commands/mr.cpp23
-rw-r--r--src/mongo/db/commands/mr.h6
-rw-r--r--src/mongo/db/commands/mr_common.cpp10
-rw-r--r--src/mongo/db/commands/oplog_note.cpp3
-rw-r--r--src/mongo/db/commands/parallel_collection_scan.cpp3
-rw-r--r--src/mongo/db/commands/parameters.cpp6
-rw-r--r--src/mongo/db/commands/pipeline_command.cpp9
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp4
-rw-r--r--src/mongo/db/commands/plan_cache_commands.h2
-rw-r--r--src/mongo/db/commands/rename_collection_cmd.cpp3
-rw-r--r--src/mongo/db/commands/repair_cursor.cpp3
-rw-r--r--src/mongo/db/commands/server_status.cpp3
-rw-r--r--src/mongo/db/commands/shutdown.h3
-rw-r--r--src/mongo/db/commands/snapshot_management.cpp6
-rw-r--r--src/mongo/db/commands/test_commands.cpp13
-rw-r--r--src/mongo/db/commands/top_command.cpp3
-rw-r--r--src/mongo/db/commands/touch.cpp3
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp190
-rw-r--r--src/mongo/db/commands/validate.cpp3
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp53
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp11
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.h2
-rw-r--r--src/mongo/db/dbcommands.cpp79
-rw-r--r--src/mongo/db/dbeval.cpp3
-rw-r--r--src/mongo/db/driverHelpers.cpp3
-rw-r--r--src/mongo/db/exec/stagedebug_cmd.cpp3
-rw-r--r--src/mongo/db/geo/haystack.cpp3
-rw-r--r--src/mongo/db/namespace_string.h3
-rw-r--r--src/mongo/db/ops/update.cpp5
-rw-r--r--src/mongo/db/pipeline/pipeline.cpp20
-rw-r--r--src/mongo/db/pipeline/pipeline.h5
-rw-r--r--src/mongo/db/repl/master_slave.cpp3
-rw-r--r--src/mongo/db/repl/repl_set_command.h3
-rw-r--r--src/mongo/db/repl/replication_info.cpp3
-rw-r--r--src/mongo/db/repl/resync.cpp3
-rw-r--r--src/mongo/db/s/check_sharding_index_command.cpp4
-rw-r--r--src/mongo/db/s/cleanup_orphaned_cmd.cpp3
-rw-r--r--src/mongo/db/s/get_shard_version_command.cpp4
-rw-r--r--src/mongo/db/s/merge_chunks_command.cpp3
-rw-r--r--src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp8
-rw-r--r--src/mongo/db/s/migration_destination_manager_legacy_commands.cpp17
-rw-r--r--src/mongo/db/s/move_chunk_command.cpp4
-rw-r--r--src/mongo/db/s/set_shard_version_command.cpp4
-rw-r--r--src/mongo/db/s/sharding_state_command.cpp4
-rw-r--r--src/mongo/db/s/split_chunk_command.cpp4
-rw-r--r--src/mongo/db/s/split_vector_command.cpp3
-rw-r--r--src/mongo/db/s/unset_sharding_command.cpp4
-rw-r--r--src/mongo/db/storage/mmap_v1/journal_latency_test_cmd.cpp3
-rw-r--r--src/mongo/db/write_concern.cpp48
-rw-r--r--src/mongo/db/write_concern.h3
-rw-r--r--src/mongo/db/write_concern_options.cpp34
-rw-r--r--src/mongo/db/write_concern_options.h12
95 files changed, 771 insertions, 160 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index e530792b0de..2f7a108d72f 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -40,11 +40,11 @@ env.Library(
'field_ref_set.cpp',
'field_parser.cpp',
'keypattern.cpp',
- 'write_concern_options.cpp'
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/index_names',
+ '$BUILD_DIR/mongo/db/write_concern_options',
'$BUILD_DIR/mongo/util/foundation',
]
)
@@ -443,6 +443,16 @@ env.Library(
)
env.Library(
+ target="write_concern_options",
+ source=[
+ "write_concern_options.cpp",
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/bson/util/bson_extract',
+ ],
+)
+
+env.Library(
target='service_context',
source=[
'client.cpp',
diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp
index fe049a988d0..f006cded7d0 100644
--- a/src/mongo/db/auth/sasl_commands.cpp
+++ b/src/mongo/db/auth/sasl_commands.cpp
@@ -81,6 +81,9 @@ public:
BSONObjBuilder& result);
virtual void help(stringstream& help) const;
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
@@ -106,6 +109,9 @@ public:
BSONObjBuilder& result);
virtual void help(stringstream& help) const;
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/clientlistplugin.cpp b/src/mongo/db/clientlistplugin.cpp
index d3636f39099..ccb799571c5 100644
--- a/src/mongo/db/clientlistplugin.cpp
+++ b/src/mongo/db/clientlistplugin.cpp
@@ -141,6 +141,10 @@ public:
CurrentOpContexts() : Command("currentOpCtx") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index dff5e6f91a1..d538800a63a 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -185,11 +185,16 @@ void Command::appendCommandStatus(BSONObjBuilder& result, bool ok, const std::st
}
}
-void Command::appendCommandWCStatus(BSONObjBuilder& result, const Status& status) {
- if (!status.isOK()) {
+void Command::appendCommandWCStatus(BSONObjBuilder& result,
+ const Status& awaitReplicationStatus,
+ const WriteConcernResult& wcResult) {
+ if (!awaitReplicationStatus.isOK() && !result.hasField("writeConcernError")) {
WCErrorDetail wcError;
- wcError.setErrCode(status.code());
- wcError.setErrMessage(status.reason());
+ wcError.setErrCode(awaitReplicationStatus.code());
+ wcError.setErrMessage(awaitReplicationStatus.reason());
+ if (wcResult.wTimedOut) {
+ wcError.setErrInfo(BSON("wtimeout" << true));
+ }
result.append("writeConcernError", wcError.toBSON());
}
}
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index e8bd2591da1..526ba1f89d9 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -40,6 +40,7 @@
#include "mongo/db/commands/server_status_metric.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/query/explain.h"
+#include "mongo/db/write_concern.h"
#include "mongo/rpc/reply_builder_interface.h"
#include "mongo/rpc/request_interface.h"
#include "mongo/util/string_map.h"
@@ -141,6 +142,16 @@ public:
const rpc::RequestInterface& request,
rpc::ReplyBuilderInterface* replyBuilder);
+ /**
+ * supportsWriteConcern returns true if this command should be parsed for a writeConcern
+ * field and wait for that write concern to be satisfied after the command runs.
+ *
+ * @param cmd is a BSONObj representation of the command that is used to determine if the
+ * the command supports a write concern. Ex. aggregate only supports write concern
+ * when $out is provided.
+ */
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const = 0;
+
/* Return true if only the admin ns has privileges to run this command. */
virtual bool adminOnly() const {
return false;
@@ -335,8 +346,17 @@ public:
/**
* Helper for setting a writeConcernError field in the command result object if
* a writeConcern error occurs.
+ *
+ * @param result is the BSONObjBuilder for the command response. This function creates the
+ * writeConcernError field for the response.
+ * @param awaitReplicationStatus is the status received from awaitReplication.
+ * @param wcResult is the writeConcernResult object that holds other write concern information.
+ * This is primarily used for populating errInfo when a timeout occurs, and is populated
+ * by waitForWriteConcern.
*/
- static void appendCommandWCStatus(BSONObjBuilder& result, const Status& status);
+ static void appendCommandWCStatus(BSONObjBuilder& result,
+ const Status& awaitReplicationStatus,
+ const WriteConcernResult& wcResult = WriteConcernResult());
/**
* If true, then testing commands are available. Defaults to false.
diff --git a/src/mongo/db/commands/apply_ops_cmd.cpp b/src/mongo/db/commands/apply_ops_cmd.cpp
index 2301916ef6c..12df18040a9 100644
--- a/src/mongo/db/commands/apply_ops_cmd.cpp
+++ b/src/mongo/db/commands/apply_ops_cmd.cpp
@@ -53,7 +53,6 @@
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/repl_client_info.h"
#include "mongo/db/repl/replication_coordinator_global.h"
-#include "mongo/db/write_concern.h"
#include "mongo/util/log.h"
#include "mongo/util/scopeguard.h"
@@ -72,6 +71,10 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
virtual void help(stringstream& help) const {
help << "internal (sharding)\n{ applyOps : [ ] , preCondition : [ { ns : ... , q : ... , "
"res : ... } ] }";
@@ -112,14 +115,6 @@ public:
}
}
- StatusWith<WriteConcernOptions> wcResult = extractWriteConcern(txn, cmdObj, dbname);
- if (!wcResult.isOK()) {
- return appendCommandStatus(result, wcResult.getStatus());
- }
- txn->setWriteConcern(wcResult.getValue());
- setupSynchronousCommit(txn);
-
-
auto client = txn->getClient();
auto lastOpAtOperationStart = repl::ReplClientInfo::forClient(client).getLastOp();
ScopeGuard lastOpSetterGuard =
@@ -136,14 +131,6 @@ public:
lastOpSetterGuard.Dismiss();
}
- WriteConcernResult res;
- auto waitForWCStatus =
- waitForWriteConcern(txn,
- repl::ReplClientInfo::forClient(txn->getClient()).getLastOp(),
- txn->getWriteConcern(),
- &res);
- appendCommandWCStatus(result, waitForWCStatus);
-
return applyOpsStatus;
}
diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp
index b30a7694417..6fc6268a807 100644
--- a/src/mongo/db/commands/authentication_commands.cpp
+++ b/src/mongo/db/commands/authentication_commands.cpp
@@ -105,6 +105,9 @@ public:
void help(stringstream& h) const {
h << "internal";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
@@ -360,6 +363,9 @@ public:
void help(stringstream& h) const {
h << "de-authenticate";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
CmdLogout() : Command("logout") {}
bool run(OperationContext* txn,
const string& dbname,
diff --git a/src/mongo/db/commands/authentication_commands.h b/src/mongo/db/commands/authentication_commands.h
index d11ae5bc536..4b1caf54913 100644
--- a/src/mongo/db/commands/authentication_commands.h
+++ b/src/mongo/db/commands/authentication_commands.h
@@ -46,6 +46,9 @@ public:
virtual void help(std::stringstream& ss) const {
ss << "internal";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp
index 499b8827a76..9ce858feb3d 100644
--- a/src/mongo/db/commands/clone.cpp
+++ b/src/mongo/db/commands/clone.cpp
@@ -60,6 +60,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
virtual void help(stringstream& help) const {
help << "clone this database from an instance of the db on another host\n";
help << "{clone: \"host13\"[, slaveOk: <bool>]}";
diff --git a/src/mongo/db/commands/clone_collection.cpp b/src/mongo/db/commands/clone_collection.cpp
index efd3500d395..85bd9c6b1ab 100644
--- a/src/mongo/db/commands/clone_collection.cpp
+++ b/src/mongo/db/commands/clone_collection.cpp
@@ -71,6 +71,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
return parseNsFullyQualified(dbname, cmdObj);
}
diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp
index a0b283ebc49..03d8552e2ae 100644
--- a/src/mongo/db/commands/collection_to_capped.cpp
+++ b/src/mongo/db/commands/collection_to_capped.cpp
@@ -56,6 +56,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& help) const {
help << "{ cloneCollectionAsCapped:<fromName>, toCollection:<toName>, size:<sizeInBytes> }";
}
@@ -129,6 +132,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& help) const {
help << "{ convertToCapped:<fromCollectionName>, size:<sizeInBytes> }";
}
diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp
index cff4a4c359b..a87f2167be6 100644
--- a/src/mongo/db/commands/compact.cpp
+++ b/src/mongo/db/commands/compact.cpp
@@ -56,6 +56,9 @@ using std::stringstream;
class CompactCmd : public Command {
public:
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return false;
}
diff --git a/src/mongo/db/commands/conn_pool_stats.cpp b/src/mongo/db/commands/conn_pool_stats.cpp
index ffd0945ed3f..2a3b2881d45 100644
--- a/src/mongo/db/commands/conn_pool_stats.cpp
+++ b/src/mongo/db/commands/conn_pool_stats.cpp
@@ -53,6 +53,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) override {
diff --git a/src/mongo/db/commands/conn_pool_sync.cpp b/src/mongo/db/commands/conn_pool_sync.cpp
index 839e3a045b4..cb9410d7619 100644
--- a/src/mongo/db/commands/conn_pool_sync.cpp
+++ b/src/mongo/db/commands/conn_pool_sync.cpp
@@ -43,6 +43,9 @@ public:
virtual void help(std::stringstream& help) const {
help << "internal";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
diff --git a/src/mongo/db/commands/connection_status.cpp b/src/mongo/db/commands/connection_status.cpp
index 340bc032cdb..8cf1a94ebd6 100644
--- a/src/mongo/db/commands/connection_status.cpp
+++ b/src/mongo/db/commands/connection_status.cpp
@@ -44,6 +44,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp
index a0ad9c46d81..7619c87a20d 100644
--- a/src/mongo/db/commands/copydb.cpp
+++ b/src/mongo/db/commands/copydb.cpp
@@ -98,6 +98,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
diff --git a/src/mongo/db/commands/copydb_start_commands.cpp b/src/mongo/db/commands/copydb_start_commands.cpp
index feb96a9552a..e37695e4181 100644
--- a/src/mongo/db/commands/copydb_start_commands.cpp
+++ b/src/mongo/db/commands/copydb_start_commands.cpp
@@ -80,6 +80,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -149,6 +153,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj) {
diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp
index c292f27c40c..b8367c35642 100644
--- a/src/mongo/db/commands/count_cmd.cpp
+++ b/src/mongo/db/commands/count_cmd.cpp
@@ -55,6 +55,9 @@ using std::stringstream;
class CmdCount : public Command {
public:
CmdCount() : Command("count") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
// ok on --slave setups
return repl::getGlobalReplicationCoordinator()->getSettings().isSlave();
diff --git a/src/mongo/db/commands/cpuprofile.cpp b/src/mongo/db/commands/cpuprofile.cpp
index 2706d44510b..24fbd034b81 100644
--- a/src/mongo/db/commands/cpuprofile.cpp
+++ b/src/mongo/db/commands/cpuprofile.cpp
@@ -91,6 +91,9 @@ public:
// This is an abuse of the global dbmutex. We only really need to
// ensure that only one cpuprofiler command runs at once; it would
// be fine for it to run concurrently with other operations.
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
};
/**
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index cb1f09988d2..d99c74fc1ae 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -62,6 +62,9 @@ class CmdCreateIndex : public Command {
public:
CmdCreateIndex() : Command("createIndexes") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual bool slaveOk() const {
return false;
} // TODO: this could be made true...
diff --git a/src/mongo/db/commands/current_op.cpp b/src/mongo/db/commands/current_op.cpp
index 680a99ced73..fed56b550ad 100644
--- a/src/mongo/db/commands/current_op.cpp
+++ b/src/mongo/db/commands/current_op.cpp
@@ -54,6 +54,10 @@ public:
CurrentOpCommand() : Command("currentOp") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const final {
return true;
}
diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp
index dcb63a5936c..2bc75db0b74 100644
--- a/src/mongo/db/commands/dbhash.cpp
+++ b/src/mongo/db/commands/dbhash.cpp
@@ -64,6 +64,10 @@ class DBHashCmd : public Command {
public:
DBHashCmd() : Command("dbHash", false, "dbhash") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp
index c03f6382fe0..966a7d5b32b 100644
--- a/src/mongo/db/commands/distinct.cpp
+++ b/src/mongo/db/commands/distinct.cpp
@@ -75,6 +75,9 @@ public:
virtual bool slaveOverrideOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
bool supportsReadConcern() const final {
return true;
}
diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp
index cead3ea45c7..950cf437750 100644
--- a/src/mongo/db/commands/drop_indexes.cpp
+++ b/src/mongo/db/commands/drop_indexes.cpp
@@ -70,6 +70,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& help) const {
help << "drop indexes for a collection";
}
@@ -99,6 +102,9 @@ public:
virtual bool slaveOk() const {
return true;
} // can reindex on a secondary
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& help) const {
help << "re-index a collection";
}
diff --git a/src/mongo/db/commands/explain_cmd.cpp b/src/mongo/db/commands/explain_cmd.cpp
index dc467846603..b0c8f1baec3 100644
--- a/src/mongo/db/commands/explain_cmd.cpp
+++ b/src/mongo/db/commands/explain_cmd.cpp
@@ -57,6 +57,10 @@ public:
CmdExplain() : Command("explain") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
/**
* Running an explain on a secondary requires explicitly setting slaveOk.
*/
diff --git a/src/mongo/db/commands/fail_point_cmd.cpp b/src/mongo/db/commands/fail_point_cmd.cpp
index 65ca22d59e0..22de01b1d2c 100644
--- a/src/mongo/db/commands/fail_point_cmd.cpp
+++ b/src/mongo/db/commands/fail_point_cmd.cpp
@@ -70,6 +70,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool adminOnly() const {
return true;
}
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index 32b48d4eb3e..c806e67bdb7 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -63,6 +63,7 @@
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/s/collection_sharding_state.h"
#include "mongo/db/write_concern.h"
+#include "mongo/s/d_state.h"
#include "mongo/util/log.h"
#include "mongo/util/scopeguard.h"
@@ -214,6 +215,9 @@ public:
bool slaveOk() const override {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) override {
@@ -332,13 +336,6 @@ public:
const FindAndModifyRequest& args = parseStatus.getValue();
const NamespaceString& nsString = args.getNamespaceString();
- StatusWith<WriteConcernOptions> wcResult = extractWriteConcern(txn, cmdObj, dbName);
- if (!wcResult.isOK()) {
- return appendCommandStatus(result, wcResult.getStatus());
- }
- txn->setWriteConcern(wcResult.getValue());
- setupSynchronousCommit(txn);
-
boost::optional<DisableDocumentValidation> maybeDisableValidation;
if (shouldBypassDocumentValidationForCommand(cmdObj))
maybeDisableValidation.emplace(txn);
@@ -350,6 +347,11 @@ public:
&repl::ReplClientInfo::setLastOpToSystemLastOpTime,
txn);
+ // If this is the local database, don't set last op.
+ if (dbName == "local") {
+ lastOpSetterGuard.Dismiss();
+ }
+
// Although usually the PlanExecutor handles WCE internally, it will throw WCEs when it is
// executing a findAndModify. This is done to ensure that we can always match, modify, and
// return the document under concurrency, if a matching document exists.
@@ -507,14 +509,6 @@ public:
lastOpSetterGuard.Dismiss();
}
- WriteConcernResult res;
- auto waitForWCStatus =
- waitForWriteConcern(txn,
- repl::ReplClientInfo::forClient(txn->getClient()).getLastOp(),
- txn->getWriteConcern(),
- &res);
- appendCommandWCStatus(result, waitForWCStatus);
-
return true;
}
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 82c63c01cf8..f3a9ea67897 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -72,6 +72,10 @@ public:
FindCmd() : Command("find") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const override {
return false;
}
diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp
index 8bc028c926f..d8545f0853d 100644
--- a/src/mongo/db/commands/fsync.cpp
+++ b/src/mongo/db/commands/fsync.cpp
@@ -103,6 +103,9 @@ public:
locked = false;
pendingUnlock = false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
@@ -185,6 +188,10 @@ public:
FSyncUnlockCommand() : Command("fsyncUnlock") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const override {
return true;
}
diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp
index 9795e7f2b3e..05724e33705 100644
--- a/src/mongo/db/commands/generic.cpp
+++ b/src/mongo/db/commands/generic.cpp
@@ -78,6 +78,9 @@ public:
virtual bool adminOnly() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
@@ -110,6 +113,9 @@ public:
help << "a way to check that the server is alive. responds immediately even if server is "
"in a db lock.";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
@@ -133,6 +139,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
@@ -165,6 +174,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void help(stringstream& help) const {
help << "returns information about the daemon's host";
}
@@ -207,6 +220,9 @@ public:
class LogRotateCmd : public Command {
public:
LogRotateCmd() : Command("logRotate") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
@@ -240,6 +256,9 @@ public:
help << "get a list of all db commands";
}
ListCommandsCmd() : Command("listCommands", false) {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
@@ -341,6 +360,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
@@ -363,6 +385,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return true;
}
@@ -430,6 +455,9 @@ public:
void help(stringstream& h) const {
h << "get argv";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return true;
}
diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp
index 743329370be..080903e2320 100644
--- a/src/mongo/db/commands/geo_near_cmd.cpp
+++ b/src/mongo/db/commands/geo_near_cmd.cpp
@@ -63,6 +63,9 @@ class Geo2dFindNearCmd : public Command {
public:
Geo2dFindNearCmd() : Command("geoNear") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands/get_last_error.cpp b/src/mongo/db/commands/get_last_error.cpp
index 4b026165cb0..98fbdcb9049 100644
--- a/src/mongo/db/commands/get_last_error.cpp
+++ b/src/mongo/db/commands/get_last_error.cpp
@@ -56,6 +56,9 @@ using std::stringstream;
*/
class CmdResetError : public Command {
public:
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
@@ -80,6 +83,9 @@ public:
class CmdGetLastError : public Command {
public:
CmdGetLastError() : Command("getLastError", false, "getlasterror") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
@@ -283,6 +289,9 @@ public:
class CmdGetPrevError : public Command {
public:
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "check for errors since last reseterror commandcal";
}
diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp
index 0d474ed100d..9b7e54b04ca 100644
--- a/src/mongo/db/commands/getmore_cmd.cpp
+++ b/src/mongo/db/commands/getmore_cmd.cpp
@@ -80,6 +80,10 @@ public:
GetMoreCmd() : Command("getMore") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const override {
return true;
}
diff --git a/src/mongo/db/commands/group_cmd.cpp b/src/mongo/db/commands/group_cmd.cpp
index e49a9081b49..25554261b69 100644
--- a/src/mongo/db/commands/group_cmd.cpp
+++ b/src/mongo/db/commands/group_cmd.cpp
@@ -52,6 +52,10 @@ public:
GroupCommand() : Command("group") {}
private:
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool maintenanceOk() const {
return false;
}
diff --git a/src/mongo/db/commands/hashcmd.cpp b/src/mongo/db/commands/hashcmd.cpp
index f65690dddb3..76c1960f804 100644
--- a/src/mongo/db/commands/hashcmd.cpp
+++ b/src/mongo/db/commands/hashcmd.cpp
@@ -53,6 +53,9 @@ using std::stringstream;
class CmdHashElt : public Command {
public:
CmdHashElt() : Command("_hashBSONElement"){};
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp
index 936dab77670..287e7e5950f 100644
--- a/src/mongo/db/commands/index_filter_commands.cpp
+++ b/src/mongo/db/commands/index_filter_commands.cpp
@@ -145,6 +145,10 @@ bool IndexFilterCommand::run(OperationContext* txn,
}
+bool IndexFilterCommand::supportsWriteConcern(const BSONObj& cmd) const {
+ return false;
+}
+
bool IndexFilterCommand::slaveOk() const {
return false;
}
diff --git a/src/mongo/db/commands/index_filter_commands.h b/src/mongo/db/commands/index_filter_commands.h
index ddd2553823a..7ba1157bef7 100644
--- a/src/mongo/db/commands/index_filter_commands.h
+++ b/src/mongo/db/commands/index_filter_commands.h
@@ -70,6 +70,8 @@ public:
std::string& errmsg,
BSONObjBuilder& result);
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override;
+
virtual bool slaveOk() const;
virtual bool slaveOverrideOk() const;
diff --git a/src/mongo/db/commands/isself.cpp b/src/mongo/db/commands/isself.cpp
index a3d8a3af918..0db7ba01440 100644
--- a/src/mongo/db/commands/isself.cpp
+++ b/src/mongo/db/commands/isself.cpp
@@ -45,6 +45,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "{ _isSelf : 1 } INTERNAL ONLY";
}
diff --git a/src/mongo/db/commands/kill_op.cpp b/src/mongo/db/commands/kill_op.cpp
index 753d48b9362..57838d625d1 100644
--- a/src/mongo/db/commands/kill_op.cpp
+++ b/src/mongo/db/commands/kill_op.cpp
@@ -50,6 +50,10 @@ public:
KillOpCommand() : Command("killOp") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const final {
return true;
}
diff --git a/src/mongo/db/commands/killcursors_common.h b/src/mongo/db/commands/killcursors_common.h
index 7d082063858..db92c7ab21b 100644
--- a/src/mongo/db/commands/killcursors_common.h
+++ b/src/mongo/db/commands/killcursors_common.h
@@ -42,6 +42,10 @@ public:
KillCursorsCmdBase() : Command("killCursors") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const final {
return true;
}
diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp
index abd8302434f..0f9876420de 100644
--- a/src/mongo/db/commands/list_collections.cpp
+++ b/src/mongo/db/commands/list_collections.cpp
@@ -149,6 +149,9 @@ public:
virtual bool adminOnly() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "list collections for this db";
diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp
index f7184d7de7d..88978246b19 100644
--- a/src/mongo/db/commands/list_databases.cpp
+++ b/src/mongo/db/commands/list_databases.cpp
@@ -57,6 +57,9 @@ public:
virtual bool adminOnly() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "list databases on this server";
}
diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp
index 5d443e98e4b..f6d144de358 100644
--- a/src/mongo/db/commands/list_indexes.cpp
+++ b/src/mongo/db/commands/list_indexes.cpp
@@ -82,6 +82,9 @@ public:
virtual bool adminOnly() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "list indexes for a collection";
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index 56aedcd16ae..9e5e6259d3e 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -602,7 +602,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* txn,
ScopedTransaction transaction(txn, MODE_X);
Lock::GlobalWrite lock(txn->lockState()); // TODO(erh): why global???
// replace: just rename from temp to final collection name, dropping previous collection
- _db.dropCollection(_config.outputOptions.finalNamespace);
+ _db.dropCollection(_config.outputOptions.finalNamespace, txn->getWriteConcern());
BSONObj info;
if (!_db.runCommand("admin",
@@ -613,7 +613,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* txn,
uasserted(10076, str::stream() << "rename failed: " << info);
}
- _db.dropCollection(_config.tempNamespace);
+ _db.dropCollection(_config.tempNamespace, txn->getWriteConcern());
} else if (_config.outputOptions.outType == Config::MERGE) {
// merge: upsert new docs into old collection
{
@@ -632,7 +632,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* txn,
Helpers::upsert(_txn, _config.outputOptions.finalNamespace, o);
pm.hit();
}
- _db.dropCollection(_config.tempNamespace);
+ _db.dropCollection(_config.tempNamespace, txn->getWriteConcern());
pm.finished();
} else if (_config.outputOptions.outType == Config::REDUCE) {
// reduce: apply reduce op on new result and existing one
@@ -1287,6 +1287,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return mrSupportsWriteConcern(cmd);
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -1301,6 +1305,11 @@ public:
BSONObjBuilder& result) {
Timer t;
+ // Save and reset the write concern so that it doesn't get changed accidentally by
+ // DBDirectClient.
+ auto oldWC = txn->getWriteConcern();
+ ON_BLOCK_EXIT([txn, oldWC] { txn->setWriteConcern(oldWC); });
+
boost::optional<DisableDocumentValidation> maybeDisableValidation;
if (shouldBypassDocumentValidationForCommand(cmd))
maybeDisableValidation.emplace(txn);
@@ -1588,6 +1597,9 @@ public:
virtual bool slaveOverrideOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -1609,6 +1621,11 @@ public:
<< dbname));
}
+ // Save and reset the write concern so that it doesn't get changed accidentally by
+ // DBDirectClient.
+ auto oldWC = txn->getWriteConcern();
+ ON_BLOCK_EXIT([txn, oldWC] { txn->setWriteConcern(oldWC); });
+
boost::optional<DisableDocumentValidation> maybeDisableValidation;
if (shouldBypassDocumentValidationForCommand(cmdObj))
maybeDisableValidation.emplace(txn);
diff --git a/src/mongo/db/commands/mr.h b/src/mongo/db/commands/mr.h
index 04b5f12a661..3d967438179 100644
--- a/src/mongo/db/commands/mr.h
+++ b/src/mongo/db/commands/mr.h
@@ -411,5 +411,11 @@ void addPrivilegesRequiredForMapReduce(Command* commandTemplate,
const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out);
+
+/**
+ * Returns true if the provided mapReduce command has an 'out' parameter.
+ */
+bool mrSupportsWriteConcern(const BSONObj& cmd);
+
} // end mr namespace
}
diff --git a/src/mongo/db/commands/mr_common.cpp b/src/mongo/db/commands/mr_common.cpp
index 4d11661fd2d..d180f276249 100644
--- a/src/mongo/db/commands/mr_common.cpp
+++ b/src/mongo/db/commands/mr_common.cpp
@@ -132,5 +132,15 @@ void addPrivilegesRequiredForMapReduce(Command* commandTemplate,
out->push_back(Privilege(outputResource, outputActions));
}
}
+
+bool mrSupportsWriteConcern(const BSONObj& cmd) {
+ if (!cmd.hasField("out")) {
+ return false;
+ } else if (cmd["out"].type() == Object && cmd["out"].Obj().hasField("inline")) {
+ return false;
+ } else {
+ return true;
+ }
+}
}
}
diff --git a/src/mongo/db/commands/oplog_note.cpp b/src/mongo/db/commands/oplog_note.cpp
index 6c96f0907b8..bebf6d4d13c 100644
--- a/src/mongo/db/commands/oplog_note.cpp
+++ b/src/mongo/db/commands/oplog_note.cpp
@@ -54,6 +54,9 @@ public:
virtual bool adminOnly() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& help) const {
help << "Adds a no-op entry to the oplog";
}
diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp
index 4ca7a131f60..bc280f4b937 100644
--- a/src/mongo/db/commands/parallel_collection_scan.cpp
+++ b/src/mongo/db/commands/parallel_collection_scan.cpp
@@ -58,6 +58,9 @@ public:
ParallelCollectionScanCmd() : Command("parallelCollectionScan") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands/parameters.cpp b/src/mongo/db/commands/parameters.cpp
index 17a85c757b3..c9bc974e040 100644
--- a/src/mongo/db/commands/parameters.cpp
+++ b/src/mongo/db/commands/parameters.cpp
@@ -71,6 +71,9 @@ public:
virtual bool adminOnly() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -118,6 +121,9 @@ public:
virtual bool adminOnly() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp
index b04d6ffe1ef..d8836346c5e 100644
--- a/src/mongo/db/commands/pipeline_command.cpp
+++ b/src/mongo/db/commands/pipeline_command.cpp
@@ -53,6 +53,7 @@
#include "mongo/db/query/get_executor.h"
#include "mongo/db/storage/storage_options.h"
#include "mongo/stdx/memory.h"
+#include "mongo/util/scopeguard.h"
namespace mongo {
@@ -154,6 +155,9 @@ public:
PipelineCommand() : Command(Pipeline::commandName) {} // command is called "aggregate"
// Locks are managed manually, in particular by DocumentSourceCursor.
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return Pipeline::aggSupportsWriteConcern(cmd);
+ }
virtual bool slaveOk() const {
return false;
}
@@ -199,6 +203,11 @@ public:
if (!pPipeline.get())
return false;
+ // Save and reset the write concern so that it doesn't get changed accidentally by
+ // DBDirectClient.
+ auto oldWC = txn->getWriteConcern();
+ ON_BLOCK_EXIT([txn, oldWC] { txn->setWriteConcern(oldWC); });
+
// This is outside of the if block to keep the object alive until the pipeline is finished.
BSONObj parsed;
if (kDebugBuild && !pPipeline->isExplain() && !pCtx->inShard) {
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index 49c25de5514..b7c408f3b3c 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -141,6 +141,10 @@ bool PlanCacheCommand::run(OperationContext* txn,
}
+bool PlanCacheCommand::supportsWriteConcern(const BSONObj& cmd) const {
+ return false;
+}
+
bool PlanCacheCommand::slaveOk() const {
return false;
}
diff --git a/src/mongo/db/commands/plan_cache_commands.h b/src/mongo/db/commands/plan_cache_commands.h
index f419eaed8eb..87316b84178 100644
--- a/src/mongo/db/commands/plan_cache_commands.h
+++ b/src/mongo/db/commands/plan_cache_commands.h
@@ -64,6 +64,8 @@ public:
std::string& errmsg,
BSONObjBuilder& result);
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override;
+
virtual bool slaveOk() const;
virtual bool slaveOverrideOk() const;
diff --git a/src/mongo/db/commands/rename_collection_cmd.cpp b/src/mongo/db/commands/rename_collection_cmd.cpp
index b2b12c5fed3..eb42664c57b 100644
--- a/src/mongo/db/commands/rename_collection_cmd.cpp
+++ b/src/mongo/db/commands/rename_collection_cmd.cpp
@@ -67,6 +67,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj) {
diff --git a/src/mongo/db/commands/repair_cursor.cpp b/src/mongo/db/commands/repair_cursor.cpp
index 8792afe2092..ad8afe526bb 100644
--- a/src/mongo/db/commands/repair_cursor.cpp
+++ b/src/mongo/db/commands/repair_cursor.cpp
@@ -48,6 +48,9 @@ class RepairCursorCmd : public Command {
public:
RepairCursorCmd() : Command("repairCursor") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands/server_status.cpp b/src/mongo/db/commands/server_status.cpp
index e7f15f8e4cb..423991bdbfc 100644
--- a/src/mongo/db/commands/server_status.cpp
+++ b/src/mongo/db/commands/server_status.cpp
@@ -67,6 +67,9 @@ public:
CmdServerStatus()
: Command("serverStatus", true), _started(curTimeMillis64()), _runCalled(false) {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/commands/shutdown.h b/src/mongo/db/commands/shutdown.h
index 2bb71e7373d..f1f55d0668c 100644
--- a/src/mongo/db/commands/shutdown.h
+++ b/src/mongo/db/commands/shutdown.h
@@ -54,6 +54,9 @@ public:
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out);
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
protected:
static void shutdownHelper();
diff --git a/src/mongo/db/commands/snapshot_management.cpp b/src/mongo/db/commands/snapshot_management.cpp
index cb90e41d685..9eec705e4af 100644
--- a/src/mongo/db/commands/snapshot_management.cpp
+++ b/src/mongo/db/commands/snapshot_management.cpp
@@ -45,6 +45,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return true;
}
@@ -92,6 +95,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return true;
}
diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp
index 39b6ef90636..58d554cef84 100644
--- a/src/mongo/db/commands/test_commands.cpp
+++ b/src/mongo/db/commands/test_commands.cpp
@@ -65,6 +65,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
// No auth needed because it only works when enabled via command line.
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
@@ -110,6 +113,10 @@ public:
/* for diagnostic / testing purposes. Enabled via command line. */
class CmdSleep : public Command {
public:
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool adminOnly() const {
return true;
}
@@ -204,6 +211,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
// No auth needed because it only works when enabled via command line.
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
@@ -271,6 +281,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
// No auth needed because it only works when enabled via command line.
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
diff --git a/src/mongo/db/commands/top_command.cpp b/src/mongo/db/commands/top_command.cpp
index 70407d67ea6..e4b788dc711 100644
--- a/src/mongo/db/commands/top_command.cpp
+++ b/src/mongo/db/commands/top_command.cpp
@@ -52,6 +52,9 @@ public:
virtual bool adminOnly() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(std::stringstream& help) const {
help << "usage by collection, in micros ";
}
diff --git a/src/mongo/db/commands/touch.cpp b/src/mongo/db/commands/touch.cpp
index 530d8937588..520f74e64a1 100644
--- a/src/mongo/db/commands/touch.cpp
+++ b/src/mongo/db/commands/touch.cpp
@@ -57,6 +57,9 @@ using std::stringstream;
class TouchCmd : public Command {
public:
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return false;
}
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 5e35694173e..f058a892a9b 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -62,12 +62,18 @@
#include "mongo/db/operation_context.h"
#include "mongo/db/service_context.h"
#include "mongo/platform/unordered_set.h"
+#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/rpc/protocol.h"
+#include "mongo/s/write_ops/batched_command_response.h"
+#include "mongo/s/write_ops/batched_delete_request.h"
+#include "mongo/s/write_ops/batched_insert_request.h"
+#include "mongo/s/write_ops/batched_update_request.h"
#include "mongo/stdx/functional.h"
#include "mongo/stdx/mutex.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/net/ssl_manager.h"
+#include "mongo/util/scopeguard.h"
#include "mongo/util/sequence_util.h"
#include "mongo/util/time_support.h"
@@ -260,24 +266,28 @@ Status insertAuthzDocument(OperationContext* txn,
const NamespaceString& collectionName,
const BSONObj& document,
const BSONObj& writeConcern) {
+ // Save and reset the write concern so that it doesn't get changed accidentally by
+ // DBDirectClient.
+ auto oldWC = txn->getWriteConcern();
+ ON_BLOCK_EXIT([txn, oldWC] { txn->setWriteConcern(oldWC); });
+
try {
DBDirectClient client(txn);
- client.insert(collectionName.ns(), document);
- // Handle write concern
- BSONObjBuilder gleBuilder;
- gleBuilder.append("getLastError", 1);
- gleBuilder.appendElements(writeConcern);
+ BatchedInsertRequest req;
+ req.setNS(collectionName);
+ req.addToDocuments(document);
+
BSONObj res;
- client.runCommand("admin", gleBuilder.done(), res);
- string errstr = client.getLastErrorString(res);
- if (errstr.empty()) {
- return Status::OK();
- }
- if (res.hasField("code") && res["code"].Int() == ASSERT_ID_DUPKEY) {
- return Status(ErrorCodes::DuplicateKey, errstr);
+ client.runCommand(collectionName.db().toString(), req.toBSON(), res);
+
+ BatchedCommandResponse response;
+ std::string errmsg;
+ response.parseBSON(res, &errmsg);
+ if (errmsg != "") {
+ return Status(ErrorCodes::FailedToParse, errmsg);
}
- return Status(ErrorCodes::UnknownError, errstr);
+ return response.toStatus();
} catch (const DBException& e) {
return e.toStatus();
}
@@ -296,23 +306,38 @@ Status updateAuthzDocuments(OperationContext* txn,
bool upsert,
bool multi,
const BSONObj& writeConcern,
- int* nMatched) {
+ long long* nMatched) {
+ // Save and reset the write concern so that it doesn't get changed accidentally by
+ // DBDirectClient.
+ auto oldWC = txn->getWriteConcern();
+ ON_BLOCK_EXIT([txn, oldWC] { txn->setWriteConcern(oldWC); });
+
try {
DBDirectClient client(txn);
- client.update(collectionName.ns(), query, updatePattern, upsert, multi);
- // Handle write concern
- BSONObjBuilder gleBuilder;
- gleBuilder.append("getLastError", 1);
- gleBuilder.appendElements(writeConcern);
+ auto doc = stdx::make_unique<BatchedUpdateDocument>();
+ doc->setQuery(query);
+ doc->setUpdateExpr(updatePattern);
+ doc->setMulti(multi);
+ doc->setUpsert(upsert);
+
+ BatchedUpdateRequest req;
+ req.setNS(collectionName);
+ req.addToUpdates(doc.release());
+
BSONObj res;
- client.runCommand("admin", gleBuilder.done(), res);
- string errstr = client.getLastErrorString(res);
- if (errstr.empty()) {
- *nMatched = res["n"].numberInt();
- return Status::OK();
+ client.runCommand(collectionName.db().toString(), req.toBSON(), res);
+
+ BatchedCommandResponse response;
+ std::string errmsg;
+ response.parseBSON(res, &errmsg);
+ if (errmsg != "") {
+ return Status(ErrorCodes::FailedToParse, errmsg);
}
- return Status(ErrorCodes::UnknownError, errstr);
+ if (response.getOk()) {
+ *nMatched = response.getN();
+ }
+ return response.toStatus();
} catch (const DBException& e) {
return e.toStatus();
}
@@ -336,7 +361,7 @@ Status updateOneAuthzDocument(OperationContext* txn,
const BSONObj& updatePattern,
bool upsert,
const BSONObj& writeConcern) {
- int nMatched;
+ long long nMatched;
Status status = updateAuthzDocuments(
txn, collectionName, query, updatePattern, upsert, false, writeConcern, &nMatched);
if (!status.isOK()) {
@@ -359,23 +384,36 @@ Status removeAuthzDocuments(OperationContext* txn,
const NamespaceString& collectionName,
const BSONObj& query,
const BSONObj& writeConcern,
- int* numRemoved) {
+ long long* numRemoved) {
+ // Save and reset the write concern so that it doesn't get changed accidentally by
+ // DBDirectClient.
+ auto oldWC = txn->getWriteConcern();
+ ON_BLOCK_EXIT([txn, oldWC] { txn->setWriteConcern(oldWC); });
+
try {
DBDirectClient client(txn);
- client.remove(collectionName.ns(), query);
- // Handle write concern
- BSONObjBuilder gleBuilder;
- gleBuilder.append("getLastError", 1);
- gleBuilder.appendElements(writeConcern);
+ auto doc = stdx::make_unique<BatchedDeleteDocument>();
+ doc->setQuery(query);
+ doc->setLimit(0);
+
+ BatchedDeleteRequest req;
+ req.setNS(collectionName);
+ req.addToDeletes(doc.release());
+
BSONObj res;
- client.runCommand("admin", gleBuilder.done(), res);
- string errstr = client.getLastErrorString(res);
- if (errstr.empty()) {
- *numRemoved = res["n"].numberInt();
- return Status::OK();
+ client.runCommand(collectionName.db().toString(), req.toBSON(), res);
+
+ BatchedCommandResponse response;
+ std::string errmsg;
+ response.parseBSON(res, &errmsg);
+ if (errmsg != "") {
+ return Status(ErrorCodes::FailedToParse, errmsg);
}
- return Status(ErrorCodes::UnknownError, errstr);
+ if (response.getOk()) {
+ *numRemoved = response.getN();
+ }
+ return response.toStatus();
} catch (const DBException& e) {
return e.toStatus();
}
@@ -445,7 +483,7 @@ Status updateRoleDocument(OperationContext* txn,
Status removeRoleDocuments(OperationContext* txn,
const BSONObj& query,
const BSONObj& writeConcern,
- int* numRemoved) {
+ long long* numRemoved) {
Status status = removeAuthzDocuments(
txn, AuthorizationManager::rolesCollectionNamespace, query, writeConcern, numRemoved);
if (status.code() == ErrorCodes::UnknownError) {
@@ -518,7 +556,7 @@ Status updatePrivilegeDocument(OperationContext* txn,
Status removePrivilegeDocuments(OperationContext* txn,
const BSONObj& query,
const BSONObj& writeConcern,
- int* numRemoved) {
+ long long* numRemoved) {
Status status = removeAuthzDocuments(
txn, AuthorizationManager::usersCollectionNamespace, query, writeConcern, numRemoved);
if (status.code() == ErrorCodes::UnknownError) {
@@ -608,6 +646,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Adds a user to the system" << endl;
@@ -750,6 +791,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Used to update a user, for example to change its password" << endl;
@@ -864,6 +908,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Drops a single user." << endl;
@@ -899,7 +946,7 @@ public:
audit::logDropUser(ClientBasic::getCurrent(), userName);
- int nMatched;
+ long long nMatched;
status = removePrivilegeDocuments(txn,
BSON(AuthorizationManager::USER_NAME_FIELD_NAME
<< userName.getUser()
@@ -933,6 +980,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Drops all users for a single database." << endl;
@@ -967,7 +1017,7 @@ public:
audit::logDropAllUsersFromDatabase(ClientBasic::getCurrent(), dbname);
- int numRemoved;
+ long long numRemoved;
status = removePrivilegeDocuments(txn,
BSON(AuthorizationManager::USER_DB_FIELD_NAME << dbname),
writeConcern,
@@ -992,6 +1042,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Grants roles to a user." << endl;
@@ -1064,6 +1117,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Revokes roles from a user." << endl;
@@ -1138,6 +1194,9 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
CmdUsersInfo() : Command("usersInfo") {}
@@ -1289,6 +1348,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Adds a role to the system" << endl;
@@ -1400,6 +1462,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Used to update a role" << endl;
@@ -1496,6 +1561,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Grants privileges to a role" << endl;
@@ -1601,6 +1669,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Revokes privileges from a role" << endl;
@@ -1714,6 +1785,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Grants roles to another role." << endl;
@@ -1806,6 +1880,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Revokes roles from another role." << endl;
@@ -1892,6 +1969,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Drops a single role. Before deleting the role completely it must remove it "
@@ -1943,7 +2023,7 @@ public:
}
// Remove this role from all users
- int nMatched;
+ long long nMatched;
status = updateAuthzDocuments(
txn,
AuthorizationManager::usersCollectionNamespace,
@@ -2043,6 +2123,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Drops all roles from the given database. Before deleting the roles completely "
@@ -2080,7 +2163,7 @@ public:
}
// Remove these roles from all users
- int nMatched;
+ long long nMatched;
status = updateAuthzDocuments(
txn,
AuthorizationManager::usersCollectionNamespace,
@@ -2163,6 +2246,9 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
CmdRolesInfo() : Command("rolesInfo") {}
@@ -2235,6 +2321,9 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
CmdInvalidateUserCache() : Command("invalidateUserCache") {}
@@ -2271,6 +2360,9 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
CmdGetCacheGeneration() : Command("_getUserCacheGeneration") {}
@@ -2315,6 +2407,9 @@ public:
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual bool adminOnly() const {
return true;
@@ -2559,7 +2654,7 @@ public:
}
if (drop) {
- int numRemoved;
+ long long numRemoved;
for (unordered_set<UserName>::iterator it = usersToDrop.begin();
it != usersToDrop.end();
++it) {
@@ -2640,7 +2735,7 @@ public:
}
if (drop) {
- int numRemoved;
+ long long numRemoved;
for (unordered_set<RoleName>::iterator it = rolesToDrop.begin();
it != rolesToDrop.end();
++it) {
@@ -2897,6 +2992,9 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& ss) const {
ss << "Upgrades the auth data storage schema";
diff --git a/src/mongo/db/commands/validate.cpp b/src/mongo/db/commands/validate.cpp
index e41374cba6a..1569bf5cdcc 100644
--- a/src/mongo/db/commands/validate.cpp
+++ b/src/mongo/db/commands/validate.cpp
@@ -62,6 +62,9 @@ public:
"Add full:true option to do a more thorough check";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp
index 51b446532a7..bd71a02d6aa 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.cpp
+++ b/src/mongo/db/commands/write_commands/batch_executor.cpp
@@ -121,19 +121,6 @@ private:
std::unique_ptr<WriteErrorDetail> _error;
};
-unique_ptr<WCErrorDetail> toWriteConcernError(const Status& wcStatus,
- const WriteConcernResult& wcResult) {
- auto wcError = stdx::make_unique<WCErrorDetail>();
-
- wcError->setErrCode(wcStatus.code());
- wcError->setErrMessage(wcStatus.reason());
- if (wcResult.wTimedOut) {
- wcError->setErrInfo(BSON("wtimeout" << true));
- }
-
- return wcError;
-}
-
WriteErrorDetail* toWriteError(const Status& status) {
WriteErrorDetail* error = new WriteErrorDetail;
@@ -278,27 +265,6 @@ void WriteBatchExecutor::executeBatch(const BatchedCommandRequest& request,
bulkExecute(request, &upserted, &writeErrors);
//
- // Always try to enforce the write concern, even if everything failed.
- // If something failed, we have already set the lastOp to be the last op to have succeeded
- // and written to the oplog.
-
- {
- stdx::lock_guard<Client> lk(*_txn->getClient());
- CurOp::get(_txn)->setMessage_inlock("waiting for write concern");
- }
-
- unique_ptr<WCErrorDetail> wcError;
- WriteConcernResult res;
- Status status =
- waitForWriteConcern(_txn,
- repl::ReplClientInfo::forClient(_txn->getClient()).getLastOp(),
- _txn->getWriteConcern(),
- &res);
- if (!status.isOK()) {
- wcError = toWriteConcernError(status, res);
- }
-
- //
// Refresh metadata if needed
//
@@ -328,10 +294,6 @@ void WriteBatchExecutor::executeBatch(const BatchedCommandRequest& request,
response->setErrDetails(writeErrors);
}
- if (wcError.get()) {
- response->setWriteConcernError(wcError.release());
- }
-
repl::ReplicationCoordinator* replCoord = repl::getGlobalReplicationCoordinator();
const repl::ReplicationCoordinator::Mode replMode = replCoord->getReplicationMode();
if (replMode != repl::ReplicationCoordinator::modeNone) {
@@ -743,6 +705,11 @@ void WriteBatchExecutor::execInserts(const BatchedCommandRequest& request,
&repl::ReplClientInfo::setLastOpToSystemLastOpTime,
_txn);
+ // If this is the local database, don't set last op.
+ if (request.getNS().isLocal()) {
+ lastOpSetterGuard.Dismiss();
+ }
+
int64_t chunkCount = 0;
int64_t chunkBytes = 0;
const int64_t chunkMaxCount = internalQueryExecYieldIterations / 2;
@@ -1047,6 +1014,11 @@ static void multiUpdate(OperationContext* txn,
&repl::ReplClientInfo::setLastOpToSystemLastOpTime,
txn);
+ // If this is the local database, don't set last op.
+ if (nsString.isLocal()) {
+ lastOpSetterGuard.Dismiss();
+ }
+
int attempt = 0;
bool createCollection = false;
for (int fakeLoop = 0; fakeLoop < 1; fakeLoop++) {
@@ -1226,6 +1198,11 @@ static void multiRemove(OperationContext* txn,
&repl::ReplClientInfo::setLastOpToSystemLastOpTime,
txn);
+ // If this is the local database, don't set last op.
+ if (nss.isLocal()) {
+ lastOpSetterGuard.Dismiss();
+ }
+
int attempt = 1;
while (1) {
try {
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index cd3c13674a1..7e56675ef3c 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -92,6 +92,10 @@ bool WriteCmd::slaveOk() const {
}
+bool WriteCmd::supportsWriteConcern(const BSONObj& cmd) const {
+ return true;
+}
+
Status WriteCmd::checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj) {
@@ -128,13 +132,6 @@ bool WriteCmd::run(OperationContext* txn,
return appendCommandStatus(result, Status(ErrorCodes::FailedToParse, errMsg));
}
- StatusWith<WriteConcernOptions> wcStatus = extractWriteConcern(txn, cmdObj, dbName);
-
- if (!wcStatus.isOK()) {
- return appendCommandStatus(result, wcStatus.getStatus());
- }
- txn->setWriteConcern(wcStatus.getValue());
-
WriteBatchExecutor writeBatchExecutor(
txn, &globalOpCounters, &LastError::get(txn->getClient()));
diff --git a/src/mongo/db/commands/write_commands/write_commands.h b/src/mongo/db/commands/write_commands/write_commands.h
index e8dfaaa9608..e01ade2b2ff 100644
--- a/src/mongo/db/commands/write_commands/write_commands.h
+++ b/src/mongo/db/commands/write_commands/write_commands.h
@@ -63,6 +63,8 @@ protected:
private:
virtual bool slaveOk() const;
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override;
+
virtual Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj);
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 1516a27989a..94e9c05c80e 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -180,6 +180,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
CmdDropDatabase() : Command("dropDatabase") {}
bool run(OperationContext* txn,
@@ -236,6 +240,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -309,6 +317,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj) {
@@ -398,6 +410,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -462,6 +478,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
virtual bool run(OperationContext* txn,
const string& dbname,
BSONObj& cmdObj,
@@ -499,6 +519,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
virtual void help(stringstream& help) const {
help << "create a collection explicitly\n"
"{ create: <ns>[, capped: <bool>, size: <collSizeInBytes>, max: <nDocs>] }";
@@ -554,6 +578,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
std::string collectionName = cmdObj.getStringField("root");
if (collectionName.empty())
@@ -724,6 +752,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "determine data size for a set of data in a certain range"
"\nexample: { dataSize:\"blog.posts\", keyPattern:{x:1}, min:{x:10}, max:{x:55} }"
@@ -869,6 +900,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help
<< "{ collStats:\"blog.posts\" , scale : 1 } scale divides sizes e.g. for KB use 1024\n"
@@ -976,6 +1010,9 @@ public:
virtual bool slaveOk() const {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
virtual void help(stringstream& help) const {
help << "Sets collection options.\n"
"Example: { collMod: 'foo', usePowerOf2Sizes:true }\n"
@@ -1009,6 +1046,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "Get stats on a database. Not instantaneous. Slower for databases with large "
".ns files.\n"
@@ -1096,6 +1136,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void help(stringstream& help) const {
help << "{whatsmyuri:1}";
}
@@ -1120,6 +1163,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj) {
@@ -1459,8 +1505,41 @@ bool Command::run(OperationContext* txn,
// run expects const db std::string (can't bind to temporary)
const std::string db = request.getDatabase().toString();
+ StatusWith<WriteConcernOptions> wcResult =
+ extractWriteConcern(txn, cmd, db, this->supportsWriteConcern(cmd));
+ if (!wcResult.isOK()) {
+ auto result = appendCommandStatus(inPlaceReplyBob, wcResult.getStatus());
+ inPlaceReplyBob.doneFast();
+ replyBuilder->setMetadata(rpc::makeEmptyMetadata());
+ return result;
+ }
+
+ if (this->supportsWriteConcern(cmd)) {
+ txn->setWriteConcern(wcResult.getValue());
+ }
+
// TODO: remove queryOptions parameter from command's run method.
bool result = this->run(txn, db, cmd, 0, errmsg, inPlaceReplyBob);
+
+ if (this->supportsWriteConcern(cmd)) {
+ if (shouldLog(logger::LogSeverity::Debug(1))) {
+ BSONObj oldWC = wcResult.getValue().toBSON();
+ BSONObj newWC = txn->getWriteConcern().toBSON();
+ if (oldWC != newWC) {
+ LOG(1) << "Provided writeConcern was overridden from " << oldWC << " to " << newWC
+ << " for command " << cmd;
+ }
+ }
+
+ WriteConcernResult res;
+ auto waitForWCStatus =
+ waitForWriteConcern(txn,
+ repl::ReplClientInfo::forClient(txn->getClient()).getLastOp(),
+ txn->getWriteConcern(),
+ &res);
+ appendCommandWCStatus(inPlaceReplyBob, waitForWCStatus, res);
+ }
+
appendCommandStatus(inPlaceReplyBob, result, errmsg);
inPlaceReplyBob.doneFast();
diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp
index 6df169bfefd..055c3a2dc68 100644
--- a/src/mongo/db/dbeval.cpp
+++ b/src/mongo/db/dbeval.cpp
@@ -160,6 +160,9 @@ public:
<< "Evaluate javascript at the server.\n"
<< "http://dochub.mongodb.org/core/serversidecodeexecution";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
diff --git a/src/mongo/db/driverHelpers.cpp b/src/mongo/db/driverHelpers.cpp
index 0480050edce..8b6163e678b 100644
--- a/src/mongo/db/driverHelpers.cpp
+++ b/src/mongo/db/driverHelpers.cpp
@@ -56,6 +56,9 @@ class BasicDriverHelper : public Command {
public:
BasicDriverHelper(const char* name) : Command(name) {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp
index 8c012f01862..a56f7417063 100644
--- a/src/mongo/db/exec/stagedebug_cmd.cpp
+++ b/src/mongo/db/exec/stagedebug_cmd.cpp
@@ -119,6 +119,9 @@ class StageDebugCmd : public Command {
public:
StageDebugCmd() : Command("stageDebug") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
bool slaveOk() const {
return false;
}
diff --git a/src/mongo/db/geo/haystack.cpp b/src/mongo/db/geo/haystack.cpp
index 2027dc5dd8c..9fc3a2cccf8 100644
--- a/src/mongo/db/geo/haystack.cpp
+++ b/src/mongo/db/geo/haystack.cpp
@@ -62,6 +62,9 @@ class GeoHaystackSearchCommand : public Command {
public:
GeoHaystackSearchCommand() : Command("geoSearch") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h
index 651c5fc830e..2f9ccc44490 100644
--- a/src/mongo/db/namespace_string.h
+++ b/src/mongo/db/namespace_string.h
@@ -134,6 +134,9 @@ public:
bool isSystem() const {
return coll().startsWith("system.");
}
+ bool isLocal() const {
+ return db() == "local";
+ }
bool isSystemDotIndexes() const {
return coll() == "system.indexes";
}
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index 5580d040fda..df64f72b232 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -74,6 +74,11 @@ UpdateResult update(OperationContext* txn,
const NamespaceString& nsString = request.getNamespaceString();
Collection* collection = db->getCollection(nsString.ns());
+ // If this is the local database, don't set last op.
+ if (db->name() == "local") {
+ lastOpSetterGuard.Dismiss();
+ }
+
// The update stage does not create its own collection. As such, if the update is
// an upsert, create the collection that the update stage inserts into beforehand.
if (!collection && request.isUpsert()) {
diff --git a/src/mongo/db/pipeline/pipeline.cpp b/src/mongo/db/pipeline/pipeline.cpp
index ac861a0f6dd..535c05a4030 100644
--- a/src/mongo/db/pipeline/pipeline.cpp
+++ b/src/mongo/db/pipeline/pipeline.cpp
@@ -96,6 +96,11 @@ intrusive_ptr<Pipeline> Pipeline::parseCommand(string& errmsg,
continue;
}
+ // ignore writeConcern since it's handled externally
+ if (str::equals(pFieldName, "writeConcern")) {
+ continue;
+ }
+
/* look for the aggregation command */
if (!strcmp(pFieldName, commandName)) {
continue;
@@ -254,6 +259,21 @@ Status Pipeline::checkAuthForCommand(ClientBasic* client,
return Status(ErrorCodes::Unauthorized, "unauthorized");
}
+bool Pipeline::aggSupportsWriteConcern(const BSONObj& cmd) {
+ if (cmd.hasField("pipeline") == false) {
+ return false;
+ }
+
+ auto stages = cmd["pipeline"].Array();
+ for (auto stage : stages) {
+ if (stage.Obj().hasField("$out")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void Pipeline::detachFromOperationContext() {
pCtx->opCtx = nullptr;
diff --git a/src/mongo/db/pipeline/pipeline.h b/src/mongo/db/pipeline/pipeline.h
index 0a23cbd88e6..61fab79c347 100644
--- a/src/mongo/db/pipeline/pipeline.h
+++ b/src/mongo/db/pipeline/pipeline.h
@@ -73,6 +73,11 @@ public:
const std::string& dbname,
const BSONObj& cmdObj);
+ /**
+ * Returns true if the provided aggregation command has a $out stage.
+ */
+ static bool aggSupportsWriteConcern(const BSONObj& cmd);
+
const boost::intrusive_ptr<ExpressionContext>& getContext() const {
return pCtx;
}
diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp
index dd60bd07c6f..e716cf58b3e 100644
--- a/src/mongo/db/repl/master_slave.cpp
+++ b/src/mongo/db/repl/master_slave.cpp
@@ -356,6 +356,9 @@ public:
h << "internal";
}
HandshakeCmd() : Command("handshake") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return true;
}
diff --git a/src/mongo/db/repl/repl_set_command.h b/src/mongo/db/repl/repl_set_command.h
index 61e2b9b07f3..03320087835 100644
--- a/src/mongo/db/repl/repl_set_command.h
+++ b/src/mongo/db/repl/repl_set_command.h
@@ -55,6 +55,9 @@ protected:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp
index 02a7a6f8a81..9852803a3b3 100644
--- a/src/mongo/db/repl/replication_info.cpp
+++ b/src/mongo/db/repl/replication_info.cpp
@@ -210,6 +210,9 @@ public:
"--slave in simple master/slave setups.\n";
help << "{ isMaster : 1 }";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
diff --git a/src/mongo/db/repl/resync.cpp b/src/mongo/db/repl/resync.cpp
index 1b53ac4d162..674b43f969a 100644
--- a/src/mongo/db/repl/resync.cpp
+++ b/src/mongo/db/repl/resync.cpp
@@ -49,6 +49,9 @@ public:
virtual bool adminOnly() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
diff --git a/src/mongo/db/s/check_sharding_index_command.cpp b/src/mongo/db/s/check_sharding_index_command.cpp
index aa10e22d433..de1dbf6487c 100644
--- a/src/mongo/db/s/check_sharding_index_command.cpp
+++ b/src/mongo/db/s/check_sharding_index_command.cpp
@@ -58,6 +58,10 @@ public:
help << "Internal command.\n";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool slaveOk() const {
return false;
}
diff --git a/src/mongo/db/s/cleanup_orphaned_cmd.cpp b/src/mongo/db/s/cleanup_orphaned_cmd.cpp
index 9c2a6477186..9421784b28c 100644
--- a/src/mongo/db/s/cleanup_orphaned_cmd.cpp
+++ b/src/mongo/db/s/cleanup_orphaned_cmd.cpp
@@ -188,6 +188,9 @@ public:
return Status::OK();
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
// Input
static BSONField<string> nsField;
diff --git a/src/mongo/db/s/get_shard_version_command.cpp b/src/mongo/db/s/get_shard_version_command.cpp
index 9a41aa5a70b..1331bbde061 100644
--- a/src/mongo/db/s/get_shard_version_command.cpp
+++ b/src/mongo/db/s/get_shard_version_command.cpp
@@ -58,6 +58,10 @@ public:
help << " example: { getShardVersion : 'alleyinsider.foo' } ";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const override {
return false;
}
diff --git a/src/mongo/db/s/merge_chunks_command.cpp b/src/mongo/db/s/merge_chunks_command.cpp
index 0f73ff2c2a9..b65d0931149 100644
--- a/src/mongo/db/s/merge_chunks_command.cpp
+++ b/src/mongo/db/s/merge_chunks_command.cpp
@@ -383,6 +383,9 @@ public:
bool slaveOk() const override {
return false;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
// Required
static BSONField<string> nsField;
diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp
index e414bcc4d8e..eb72772db1e 100644
--- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp
+++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp
@@ -115,6 +115,10 @@ public:
h << "internal";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool slaveOk() const {
return false;
}
@@ -175,6 +179,10 @@ public:
h << "internal";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual bool slaveOk() const {
return false;
}
diff --git a/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp b/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp
index 27bacbca200..3fdc0b7bcb3 100644
--- a/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp
+++ b/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp
@@ -73,6 +73,11 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ // This is required to be true to support moveChunk.
+ return true;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -196,6 +201,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -233,6 +242,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
@@ -275,6 +288,10 @@ public:
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
diff --git a/src/mongo/db/s/move_chunk_command.cpp b/src/mongo/db/s/move_chunk_command.cpp
index 48dc6285345..a3295e974b7 100644
--- a/src/mongo/db/s/move_chunk_command.cpp
+++ b/src/mongo/db/s/move_chunk_command.cpp
@@ -150,6 +150,10 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
+ }
+
Status checkAuthForCommand(ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj) override {
diff --git a/src/mongo/db/s/set_shard_version_command.cpp b/src/mongo/db/s/set_shard_version_command.cpp
index b527679fb35..acdb419538d 100644
--- a/src/mongo/db/s/set_shard_version_command.cpp
+++ b/src/mongo/db/s/set_shard_version_command.cpp
@@ -76,6 +76,10 @@ public:
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) override {
diff --git a/src/mongo/db/s/sharding_state_command.cpp b/src/mongo/db/s/sharding_state_command.cpp
index cbf54e69281..672bb581ba7 100644
--- a/src/mongo/db/s/sharding_state_command.cpp
+++ b/src/mongo/db/s/sharding_state_command.cpp
@@ -47,6 +47,10 @@ class ShardingStateCmd : public Command {
public:
ShardingStateCmd() : Command("shardingState") {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const override {
return false;
}
diff --git a/src/mongo/db/s/split_chunk_command.cpp b/src/mongo/db/s/split_chunk_command.cpp
index a63dd7af121..7e3473299f3 100644
--- a/src/mongo/db/s/split_chunk_command.cpp
+++ b/src/mongo/db/s/split_chunk_command.cpp
@@ -113,6 +113,10 @@ public:
"splitKeys : [ {a:150} , ... ]}";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool slaveOk() const override {
return false;
}
diff --git a/src/mongo/db/s/split_vector_command.cpp b/src/mongo/db/s/split_vector_command.cpp
index d0dcf35dbcc..9c4dccfac96 100644
--- a/src/mongo/db/s/split_vector_command.cpp
+++ b/src/mongo/db/s/split_vector_command.cpp
@@ -69,6 +69,9 @@ BSONObj prettyKey(const BSONObj& keyPattern, const BSONObj& key) {
class SplitVector : public Command {
public:
SplitVector() : Command("splitVector", false) {}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool slaveOk() const {
return false;
}
diff --git a/src/mongo/db/s/unset_sharding_command.cpp b/src/mongo/db/s/unset_sharding_command.cpp
index 35a39c9da9f..9aa63819135 100644
--- a/src/mongo/db/s/unset_sharding_command.cpp
+++ b/src/mongo/db/s/unset_sharding_command.cpp
@@ -52,6 +52,10 @@ public:
help << "internal";
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
bool adminOnly() const override {
return true;
}
diff --git a/src/mongo/db/storage/mmap_v1/journal_latency_test_cmd.cpp b/src/mongo/db/storage/mmap_v1/journal_latency_test_cmd.cpp
index 743d3d9f2dc..a67ecd85f3d 100644
--- a/src/mongo/db/storage/mmap_v1/journal_latency_test_cmd.cpp
+++ b/src/mongo/db/storage/mmap_v1/journal_latency_test_cmd.cpp
@@ -71,6 +71,9 @@ public:
virtual bool slaveOk() const {
return true;
}
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
virtual bool adminOnly() const {
return true;
}
diff --git a/src/mongo/db/write_concern.cpp b/src/mongo/db/write_concern.cpp
index fd65f66862a..b6d23b63aa2 100644
--- a/src/mongo/db/write_concern.cpp
+++ b/src/mongo/db/write_concern.cpp
@@ -74,39 +74,33 @@ const std::string kLocalDB = "local";
StatusWith<WriteConcernOptions> extractWriteConcern(OperationContext* txn,
const BSONObj& cmdObj,
- const std::string& dbName) {
+ const std::string& dbName,
+ const bool supportsWriteConcern) {
// The default write concern if empty is w : 1
// Specifying w : 0 is/was allowed, but is interpreted identically to w : 1
WriteConcernOptions writeConcern =
repl::getGlobalReplicationCoordinator()->getGetLastErrorDefault();
- if (writeConcern.wNumNodes == 0 && writeConcern.wMode.empty()) {
- writeConcern.wNumNodes = 1;
- }
- BSONElement writeConcernElement;
- Status wcStatus = bsonExtractTypedField(cmdObj, "writeConcern", Object, &writeConcernElement);
- if (!wcStatus.isOK()) {
- if (wcStatus == ErrorCodes::NoSuchKey) {
- // Return default write concern if no write concern is given.
- return writeConcern;
- }
- return wcStatus;
+ auto wcResult = WriteConcernOptions::extractWCFromCommand(cmdObj, dbName, writeConcern);
+ if (!wcResult.isOK()) {
+ return wcResult.getStatus();
}
-
- BSONObj writeConcernObj = writeConcernElement.Obj();
- // Empty write concern is interpreted to default.
- if (writeConcernObj.isEmpty()) {
- return writeConcern;
- }
-
- wcStatus = writeConcern.parse(writeConcernObj);
- if (!wcStatus.isOK()) {
- return wcStatus;
- }
-
- wcStatus = validateWriteConcern(txn, writeConcern, dbName);
- if (!wcStatus.isOK()) {
- return wcStatus;
+ writeConcern = wcResult.getValue();
+
+ // We didn't use the default, so the user supplied their own writeConcern.
+ if (!wcResult.getValue().usedDefault) {
+ // If it supports writeConcern and does not use the default, validate the writeConcern.
+ if (supportsWriteConcern) {
+ Status wcStatus = validateWriteConcern(txn, writeConcern, dbName);
+ if (!wcStatus.isOK()) {
+ return wcStatus;
+ }
+ } else {
+ // This command doesn't do writes so it should not be passed a writeConcern.
+ // If we did not use the default writeConcern, one was provided when it shouldn't have
+ // been by the user.
+ return Status(ErrorCodes::InvalidOptions, "Command does not support writeConcern");
+ }
}
return writeConcern;
diff --git a/src/mongo/db/write_concern.h b/src/mongo/db/write_concern.h
index 873e6114af1..653871ffe12 100644
--- a/src/mongo/db/write_concern.h
+++ b/src/mongo/db/write_concern.h
@@ -56,7 +56,8 @@ void setupSynchronousCommit(OperationContext* txn);
*/
StatusWith<WriteConcernOptions> extractWriteConcern(OperationContext* txn,
const BSONObj& cmdObj,
- const std::string& dbName);
+ const std::string& dbName,
+ const bool supportsWriteConcern);
/**
* Verifies that a WriteConcern is valid for this particular host.
diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp
index d0f003fb383..2b0c9abef23 100644
--- a/src/mongo/db/write_concern_options.cpp
+++ b/src/mongo/db/write_concern_options.cpp
@@ -30,6 +30,7 @@
#include "mongo/db/write_concern_options.h"
#include "mongo/base/status.h"
+#include "mongo/bson/util/bson_extract.h"
#include "mongo/db/field_parser.h"
namespace mongo {
@@ -119,6 +120,39 @@ Status WriteConcernOptions::parse(const BSONObj& obj) {
return Status::OK();
}
+StatusWith<WriteConcernOptions> WriteConcernOptions::extractWCFromCommand(
+ const BSONObj& cmdObj, const std::string& dbName, const WriteConcernOptions& defaultWC) {
+ WriteConcernOptions writeConcern = defaultWC;
+ writeConcern.usedDefault = true;
+ if (writeConcern.wNumNodes == 0 && writeConcern.wMode.empty()) {
+ writeConcern.wNumNodes = 1;
+ }
+
+ BSONElement writeConcernElement;
+ Status wcStatus = bsonExtractTypedField(cmdObj, "writeConcern", Object, &writeConcernElement);
+ if (!wcStatus.isOK()) {
+ if (wcStatus == ErrorCodes::NoSuchKey) {
+ // Return default write concern if no write concern is given.
+ return writeConcern;
+ }
+ return wcStatus;
+ }
+
+ BSONObj writeConcernObj = writeConcernElement.Obj();
+ // Empty write concern is interpreted to default.
+ if (writeConcernObj.isEmpty()) {
+ return writeConcern;
+ }
+
+ wcStatus = writeConcern.parse(writeConcernObj);
+ writeConcern.usedDefault = false;
+ if (!wcStatus.isOK()) {
+ return wcStatus;
+ }
+
+ return writeConcern;
+}
+
BSONObj WriteConcernOptions::toBSON() const {
BSONObjBuilder builder;
diff --git a/src/mongo/db/write_concern_options.h b/src/mongo/db/write_concern_options.h
index 0c187ed2887..f969fc08031 100644
--- a/src/mongo/db/write_concern_options.h
+++ b/src/mongo/db/write_concern_options.h
@@ -64,6 +64,15 @@ public:
Status parse(const BSONObj& obj);
/**
+ * Attempts to extract a writeConcern from cmdObj.
+ * Verifies that the writeConcern is of type Object (BSON type).
+ */
+ static StatusWith<WriteConcernOptions> extractWCFromCommand(
+ const BSONObj& cmdObj,
+ const std::string& dbName,
+ const WriteConcernOptions& defaultWC = WriteConcernOptions());
+
+ /**
* Return true if the server needs to wait for other secondary nodes to satisfy this
* write concern setting. Errs on the false positive for non-empty wMode.
*/
@@ -95,6 +104,9 @@ public:
// Timeout in milliseconds.
int wTimeout;
+
+ // True if the default write concern was used.
+ bool usedDefault = false;
};
} // namespace mongo