diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2015-10-22 10:32:47 -0400 |
---|---|---|
committer | Adam Midvidy <amidvidy@gmail.com> | 2015-10-30 15:14:06 -0400 |
commit | e62e2e71eff397caf22a0da13ac4669a8546b298 (patch) | |
tree | d170510044130c0c8e34950387b4afac957f097b | |
parent | cbc6a790dc4ac537b071626dff77d0073512690c (diff) | |
download | mongo-e62e2e71eff397caf22a0da13ac4669a8546b298.tar.gz |
SERVER-20609 use getFields instead of calling getField 4x
-rw-r--r-- | src/mongo/bson/bson_obj_test.cpp | 27 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.h | 29 | ||||
-rw-r--r-- | src/mongo/db/commands.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/commands.h | 4 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 33 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/lite_parsed_query.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/query/lite_parsed_query.h | 9 | ||||
-rw-r--r-- | src/mongo/db/s/operation_shard_version.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/s/operation_shard_version.h | 3 | ||||
-rw-r--r-- | src/mongo/s/client/shard_registry.cpp | 2 |
11 files changed, 116 insertions, 23 deletions
diff --git a/src/mongo/bson/bson_obj_test.cpp b/src/mongo/bson/bson_obj_test.cpp index 278b344a784..73621671aa4 100644 --- a/src/mongo/bson/bson_obj_test.cpp +++ b/src/mongo/bson/bson_obj_test.cpp @@ -544,4 +544,31 @@ TEST(Looping, Cpp11Auto) { ASSERT_EQUALS(count, 1 + 2 + 3); } +TEST(BSONObj, getFields) { + auto e = BSON("a" << 1 << "b" << 2 << "c" << 3 << "d" << 4 << "e" << 5 << "f" << 6); + std::array<StringData, 3> fieldNames{"c", "d", "f"}; + std::array<BSONElement, 3> fields; + e.getFields(fieldNames, &fields); + ASSERT_EQUALS(fields[0].type(), BSONType::NumberInt); + ASSERT_EQUALS(fields[0].numberInt(), 3); + ASSERT_EQUALS(fields[1].type(), BSONType::NumberInt); + ASSERT_EQUALS(fields[1].numberInt(), 4); + ASSERT_EQUALS(fields[2].type(), BSONType::NumberInt); + ASSERT_EQUALS(fields[2].numberInt(), 6); +} + +TEST(BSONObj, getFieldsWithDuplicates) { + auto e = BSON("a" << 2 << "b" + << "3" + << "a" << 9 << "b" << 10); + std::array<StringData, 2> fieldNames{"a", "b"}; + std::array<BSONElement, 2> fields; + e.getFields(fieldNames, &fields); + ASSERT_EQUALS(fields[0].type(), BSONType::NumberInt); + ASSERT_EQUALS(fields[0].numberInt(), 2); + ASSERT_EQUALS(fields[1].type(), BSONType::String); + ASSERT_EQUALS(fields[1].str(), "3"); +} + + } // unnamed namespace diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h index 28f51e55ec3..dd19526d47a 100644 --- a/src/mongo/bson/bsonobj.h +++ b/src/mongo/bson/bsonobj.h @@ -29,6 +29,7 @@ #pragma once +#include <bitset> #include <list> #include <set> #include <string> @@ -244,8 +245,18 @@ public: @param fields if a field is found its element is stored in its corresponding position in this array. if not found the array element is unchanged. */ + void getFields(unsigned n, const char** fieldNames, BSONElement* fields) const; + /** + * Get several fields at once. This is faster than separate getField() calls as the size of + * elements iterated can then be calculated only once each. + */ + template <size_t N> + void getFields(const std::array<StringData, N>& fieldNames, + std::array<BSONElement, N>* fields) const; + + /** Get the field of the specified name. eoo() is true on the returned element if not found. */ @@ -802,4 +813,22 @@ struct DataType::Handler<BSONObj> { return BSONObj(); } }; + +template <size_t N> +inline void BSONObj::getFields(const std::array<StringData, N>& fieldNames, + std::array<BSONElement, N>* fields) const { + std::bitset<N> foundFields; + auto iter = this->begin(); + while (iter.more() && !foundFields.all()) { + auto el = iter.next(); + auto fieldName = el.fieldNameStringData(); + for (std::size_t i = 0; i < N; ++i) { + if (!foundFields.test(i) && (fieldNames[i] == fieldName)) { + (*fields)[i] = std::move(el); + foundFields.set(i); + break; + } + } + } } +} // namespace mongo diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 05f77c86615..fa601fae613 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -383,10 +383,12 @@ Status Command::_checkAuthorization(Command* c, return status; } -bool Command::isHelpRequest(const rpc::RequestInterface& request) { - return request.getCommandArgs()["help"].trueValue(); +bool Command::isHelpRequest(const BSONElement& helpElem) { + return !helpElem.eoo() && helpElem.trueValue(); } +const char Command::kHelpFieldName[] = "help"; + void Command::generateHelpResponse(OperationContext* txn, const rpc::RequestInterface& request, rpc::ReplyBuilderInterface* replyBuilder, diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index f2daf4fe5b4..e835b73c959 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -393,7 +393,9 @@ public: /** * Returns true if this a request for the 'help' information associated with the command. */ - static bool isHelpRequest(const rpc::RequestInterface& request); + static bool isHelpRequest(const BSONElement& helpElem); + + static const char kHelpFieldName[]; /** * Generates a reply from the 'help' information associated with a command. The state of diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 6019131d55d..d9bba0008ee 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include <array> #include <boost/optional.hpp> #include <time.h> @@ -1161,6 +1162,22 @@ private: bool maintenanceModeSet; }; +namespace { + +// Symbolic names for indexes to make code more readable. +const std::size_t kCmdOptionMaxTimeMSField = 0; +const std::size_t kHelpField = 1; +const std::size_t kShardVersionField = 2; +const std::size_t kQueryOptionMaxTimeMSField = 3; + +// We make an array of the fields we need so we can call getFields once. This saves repeated +// scans over the command object. +const std::array<StringData, 4> neededFieldNames{LiteParsedQuery::cmdOptionMaxTimeMS, + Command::kHelpFieldName, + OperationShardVersion::fieldName(), + LiteParsedQuery::queryOptionMaxTimeMS}; +} // namespace + /** * this handles - auth @@ -1188,7 +1205,12 @@ void Command::execCommand(OperationContext* txn, std::string dbname = request.getDatabase().toString(); unique_ptr<MaintenanceModeSetter> mmSetter; - if (isHelpRequest(request)) { + + std::array<BSONElement, std::tuple_size<decltype(neededFieldNames)>::value> + extractedFields{}; + request.getCommandArgs().getFields(neededFieldNames, &extractedFields); + + if (isHelpRequest(extractedFields[kHelpField])) { CurOp::get(txn)->ensureStarted(); generateHelpResponse(txn, request, replyBuilder, *command); return; @@ -1241,12 +1263,12 @@ void Command::execCommand(OperationContext* txn, } // Handle command option maxTimeMS. - int maxTimeMS = - uassertStatusOK(LiteParsedQuery::parseMaxTimeMSCommand(request.getCommandArgs())); + int maxTimeMS = uassertStatusOK( + LiteParsedQuery::parseMaxTimeMS(extractedFields[kCmdOptionMaxTimeMSField])); uassert(ErrorCodes::InvalidOptions, "no such command option $maxTimeMs; use maxTimeMS instead", - !request.getCommandArgs().hasField("$maxTimeMS")); + extractedFields[kQueryOptionMaxTimeMSField].eoo()); CurOp::get(txn)->setMaxTimeMicros(static_cast<unsigned long long>(maxTimeMS) * 1000); @@ -1259,7 +1281,8 @@ void Command::execCommand(OperationContext* txn, invariant(!operationShardVersion.hasShardVersion()); auto commandNS = NamespaceString(command->parseNs(dbname, request.getCommandArgs())); - operationShardVersion.initializeFromCommand(commandNS, request.getCommandArgs()); + operationShardVersion.initializeFromCommand(commandNS, + extractedFields[kShardVersionField]); auto shardingState = ShardingState::get(txn); if (shardingState->enabled()) { diff --git a/src/mongo/db/pipeline/pipeline.cpp b/src/mongo/db/pipeline/pipeline.cpp index eb6a45b2b75..e237f35a61e 100644 --- a/src/mongo/db/pipeline/pipeline.cpp +++ b/src/mongo/db/pipeline/pipeline.cpp @@ -82,7 +82,7 @@ intrusive_ptr<Pipeline> Pipeline::parseCommand(string& errmsg, } // maxTimeMS is also for the command processor. - if (pFieldName == LiteParsedQuery::cmdOptionMaxTimeMS) { + if (str::equals(pFieldName, LiteParsedQuery::cmdOptionMaxTimeMS)) { continue; } diff --git a/src/mongo/db/query/lite_parsed_query.cpp b/src/mongo/db/query/lite_parsed_query.cpp index 90eed61ff95..b86b0945363 100644 --- a/src/mongo/db/query/lite_parsed_query.cpp +++ b/src/mongo/db/query/lite_parsed_query.cpp @@ -47,8 +47,8 @@ using std::unique_ptr; const std::string LiteParsedQuery::kUnwrappedReadPrefField("$queryOptions"); const std::string LiteParsedQuery::kWrappedReadPrefField("$readPreference"); -const string LiteParsedQuery::cmdOptionMaxTimeMS("maxTimeMS"); -const string LiteParsedQuery::queryOptionMaxTimeMS("$maxTimeMS"); +const char LiteParsedQuery::cmdOptionMaxTimeMS[] = "maxTimeMS"; +const char LiteParsedQuery::queryOptionMaxTimeMS[] = "$maxTimeMS"; const string LiteParsedQuery::metaGeoNearDistance("geoNearDistance"); const string LiteParsedQuery::metaGeoNearPoint("geoNearPoint"); @@ -258,7 +258,7 @@ StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeFromFindCommand(Nam } pq->_maxScan = maxScan; - } else if (str::equals(fieldName, cmdOptionMaxTimeMS.c_str())) { + } else if (str::equals(fieldName, cmdOptionMaxTimeMS)) { StatusWith<int> maxTimeMS = parseMaxTimeMS(el); if (!maxTimeMS.isOK()) { return maxTimeMS.getStatus(); diff --git a/src/mongo/db/query/lite_parsed_query.h b/src/mongo/db/query/lite_parsed_query.h index 1725123e749..af139ef1a7d 100644 --- a/src/mongo/db/query/lite_parsed_query.h +++ b/src/mongo/db/query/lite_parsed_query.h @@ -161,8 +161,9 @@ public: static const std::string kUnwrappedReadPrefField; // Names of the maxTimeMS command and query option. - static const std::string cmdOptionMaxTimeMS; - static const std::string queryOptionMaxTimeMS; + // Char arrays because they are used in static initialization. + static const char cmdOptionMaxTimeMS[]; + static const char queryOptionMaxTimeMS[]; // Names of the $meta projection values. static const std::string metaGeoNearDistance; @@ -297,6 +298,8 @@ public: static StatusWith<std::unique_ptr<LiteParsedQuery>> fromLegacyQueryMessage( const QueryMessage& qm); + static StatusWith<int> parseMaxTimeMS(const BSONElement& maxTimeMSElt); + private: LiteParsedQuery(NamespaceString nss); @@ -315,8 +318,6 @@ private: Status initFullQuery(const BSONObj& top); - static StatusWith<int> parseMaxTimeMS(const BSONElement& maxTimeMSElt); - /** * Updates the projection object with a $meta projection for the returnKey option. */ diff --git a/src/mongo/db/s/operation_shard_version.cpp b/src/mongo/db/s/operation_shard_version.cpp index d51ae7d9cb8..5f47d80ef4f 100644 --- a/src/mongo/db/s/operation_shard_version.cpp +++ b/src/mongo/db/s/operation_shard_version.cpp @@ -39,7 +39,7 @@ namespace { const OperationContext::Decoration<OperationShardVersion> shardingMetadataDecoration = OperationContext::declareDecoration<OperationShardVersion>(); -const char* kShardVersionField = "shardVersion"; +const char kShardVersionField[] = "shardVersion"; const ChunkVersion kUnshardedVersion(ChunkVersion::UNSHARDED()); } // namespace mongo @@ -50,26 +50,32 @@ OperationShardVersion& OperationShardVersion::get(OperationContext* txn) { return shardingMetadataDecoration(txn); } +StringData OperationShardVersion::fieldName() { + return kShardVersionField; +} + void OperationShardVersion::initializeFromCommand(NamespaceString ns, const BSONObj& cmdObj) { + initializeFromCommand(std::move(ns), cmdObj[fieldName()]); +} + +void OperationShardVersion::initializeFromCommand(NamespaceString ns, + const BSONElement& shardVersionElt) { if (ns.isSystemDotIndexes()) { setShardVersion(std::move(ns), ChunkVersion::IGNORED()); return; } - BSONElement versionElt; - Status status = bsonExtractTypedField(cmdObj, kShardVersionField, BSONType::Array, &versionElt); - if (!status.isOK()) { + if (shardVersionElt.eoo() || shardVersionElt.type() != BSONType::Array) { return; } - const BSONArray versionArr(versionElt.Obj()); + const BSONArray versionArr(shardVersionElt.Obj()); bool hasVersion = false; ChunkVersion newVersion = ChunkVersion::fromBSON(versionArr, &hasVersion); if (!hasVersion) { return; } - setShardVersion(std::move(ns), std::move(newVersion)); } diff --git a/src/mongo/db/s/operation_shard_version.h b/src/mongo/db/s/operation_shard_version.h index 33021dcdbae..1ec6e2bc1c1 100644 --- a/src/mongo/db/s/operation_shard_version.h +++ b/src/mongo/db/s/operation_shard_version.h @@ -53,6 +53,8 @@ public: OperationShardVersion(); + static StringData fieldName(); + /** * Retrieves a reference to the shard version decorating the OperationContext, 'txn'. */ @@ -66,6 +68,7 @@ public: * Expects the format { ..., shardVersion: [<version>, <epoch>] }. */ void initializeFromCommand(NamespaceString ns, const BSONObj& cmdObj); + void initializeFromCommand(NamespaceString ns, const BSONElement& shardVersionElement); /** * Returns whether or not there is a shard version associated with this operation. diff --git a/src/mongo/s/client/shard_registry.cpp b/src/mongo/s/client/shard_registry.cpp index d530046cd03..ee43fc4a3b0 100644 --- a/src/mongo/s/client/shard_registry.cpp +++ b/src/mongo/s/client/shard_registry.cpp @@ -100,7 +100,7 @@ BSONObj appendMaxTimeToCmdObj(long long maxTimeMicros, const BSONObj& cmdObj) { BSONObjBuilder updatedCmdBuilder; if (hasTxnMaxTime && hasUserMaxTime) { // Need to remove user provided maxTimeMS. BSONObjIterator cmdObjIter(cmdObj); - const char* maxTimeFieldName = LiteParsedQuery::cmdOptionMaxTimeMS.c_str(); + const char* maxTimeFieldName = LiteParsedQuery::cmdOptionMaxTimeMS; while (cmdObjIter.more()) { BSONElement e = cmdObjIter.next(); if (str::equals(e.fieldName(), maxTimeFieldName)) { |