diff options
author | James Wahlin <james.wahlin@10gen.com> | 2016-12-02 11:15:23 -0500 |
---|---|---|
committer | James Wahlin <james.wahlin@10gen.com> | 2016-12-06 08:42:52 -0500 |
commit | 62245660d4567096c184befc08267b77c9e3a3bb (patch) | |
tree | 01b10d2585286ff93267fd8d49e6c0cfdbd51e46 /src/mongo | |
parent | 8624eb6c5234abfba31dcf4f8cff4f89c9bcfee6 (diff) | |
download | mongo-62245660d4567096c184befc08267b77c9e3a3bb.tar.gz |
SERVER-27176 Improve performance of command writeConcern parsing
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/dbcommands.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/write_concern.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/write_concern.h | 9 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options.cpp | 11 |
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; } |