summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames Wahlin <james.wahlin@10gen.com>2016-12-02 11:15:23 -0500
committerJames Wahlin <james.wahlin@10gen.com>2016-12-06 08:42:52 -0500
commit62245660d4567096c184befc08267b77c9e3a3bb (patch)
tree01b10d2585286ff93267fd8d49e6c0cfdbd51e46 /src
parent8624eb6c5234abfba31dcf4f8cff4f89c9bcfee6 (diff)
downloadmongo-62245660d4567096c184befc08267b77c9e3a3bb.tar.gz
SERVER-27176 Improve performance of command writeConcern parsing
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands/dbcommands.cpp25
-rw-r--r--src/mongo/db/write_concern.cpp14
-rw-r--r--src/mongo/db/write_concern.h9
-rw-r--r--src/mongo/db/write_concern_options.cpp11
4 files changed, 38 insertions, 21 deletions
diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp
index 9f52d6a91cf..4333c271f7a 100644
--- a/src/mongo/db/commands/dbcommands.cpp
+++ b/src/mongo/db/commands/dbcommands.cpp
@@ -1521,19 +1521,30 @@ bool Command::run(OperationContext* txn,
replyBuilder->setMetadata(rpc::makeEmptyMetadata());
return result;
}
- auto wcResult = extractWriteConcern(txn, cmd, db, supportsWriteConcern(cmd));
- if (!wcResult.isOK()) {
- auto result = appendCommandStatus(inPlaceReplyBob, wcResult.getStatus());
- inPlaceReplyBob.doneFast();
- replyBuilder->setMetadata(rpc::makeEmptyMetadata());
- return result;
- }
+
std::string errmsg;
bool result;
if (!supportsWriteConcern(cmd)) {
+ if (commandSpecifiesWriteConcern(cmd)) {
+ auto result = appendCommandStatus(
+ inPlaceReplyBob,
+ {ErrorCodes::InvalidOptions, "Command does not support writeConcern"});
+ inPlaceReplyBob.doneFast();
+ replyBuilder->setMetadata(rpc::makeEmptyMetadata());
+ return result;
+ }
+
// TODO: remove queryOptions parameter from command's run method.
result = run(txn, db, cmd, 0, errmsg, inPlaceReplyBob);
} else {
+ auto wcResult = extractWriteConcern(txn, cmd, db);
+ if (!wcResult.isOK()) {
+ auto result = appendCommandStatus(inPlaceReplyBob, wcResult.getStatus());
+ inPlaceReplyBob.doneFast();
+ replyBuilder->setMetadata(rpc::makeEmptyMetadata());
+ return result;
+ }
+
// Change the write concern while running the command.
const auto oldWC = txn->getWriteConcern();
ON_BLOCK_EXIT([&] { txn->setWriteConcern(oldWC); });
diff --git a/src/mongo/db/write_concern.cpp b/src/mongo/db/write_concern.cpp
index f4a30f917f5..6886bed64ca 100644
--- a/src/mongo/db/write_concern.cpp
+++ b/src/mongo/db/write_concern.cpp
@@ -62,10 +62,13 @@ static ServerStatusMetricField<Counter64> gleWtimeoutsDisplay("getLastError.wtim
MONGO_FP_DECLARE(hangBeforeWaitingForWriteConcern);
+bool commandSpecifiesWriteConcern(const BSONObj& cmdObj) {
+ return cmdObj.hasField(WriteConcernOptions::kWriteConcernField);
+}
+
StatusWith<WriteConcernOptions> extractWriteConcern(OperationContext* txn,
const BSONObj& cmdObj,
- const std::string& dbName,
- const bool supportsWriteConcern) {
+ const std::string& dbName) {
// The default write concern if empty is {w:1}. Specifying {w:0} is/was allowed, but is
// interpreted identically to {w:1}.
auto wcResult = WriteConcernOptions::extractWCFromCommand(
@@ -84,16 +87,11 @@ StatusWith<WriteConcernOptions> extractWriteConcern(OperationContext* txn,
writeConcern = {
WriteConcernOptions::kMajority, WriteConcernOptions::SyncMode::UNSET, Seconds(30)};
}
- } else if (supportsWriteConcern) {
- // If it supports writeConcern and does not use the default, validate the writeConcern.
+ } else {
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 {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 9a9720f26ee..13bae072b05 100644
--- a/src/mongo/db/write_concern.h
+++ b/src/mongo/db/write_concern.h
@@ -28,6 +28,7 @@
#pragma once
+#include "mongo/bson/bsonobj.h"
#include "mongo/db/write_concern_options.h"
#include "mongo/util/net/hostandport.h"
@@ -42,14 +43,18 @@ class OpTime;
}
/**
+ * Returns true if 'cmdObj' has a 'writeConcern' field.
+ */
+bool commandSpecifiesWriteConcern(const BSONObj& cmdObj);
+
+/**
* Attempts to extract a writeConcern from cmdObj.
* Verifies that the writeConcern is of type Object (BSON type) and
* that the resulting writeConcern is valid for this particular host.
*/
StatusWith<WriteConcernOptions> extractWriteConcern(OperationContext* txn,
const BSONObj& cmdObj,
- const std::string& dbName,
- const bool supportsWriteConcern);
+ const std::string& dbName);
/**
* Verifies that a WriteConcern is valid for this particular host and database.
diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp
index dd9694dcc61..a2ad573ff25 100644
--- a/src/mongo/db/write_concern_options.cpp
+++ b/src/mongo/db/write_concern_options.cpp
@@ -159,14 +159,17 @@ StatusWith<WriteConcernOptions> WriteConcernOptions::extractWCFromCommand(
writeConcern.wNumNodes = 1;
}
+ // Return the default write concern if no write concern is provided. We check for the existence
+ // of the write concern field up front in order to avoid the expense of constructing an error
+ // status in bsonExtractTypedField() below.
+ if (!cmdObj.hasField(kWriteConcernField)) {
+ return writeConcern;
+ }
+
BSONElement writeConcernElement;
Status wcStatus =
bsonExtractTypedField(cmdObj, kWriteConcernField, Object, &writeConcernElement);
if (!wcStatus.isOK()) {
- if (wcStatus == ErrorCodes::NoSuchKey) {
- // Return default write concern if no write concern is given.
- return writeConcern;
- }
return wcStatus;
}