summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2015-10-22 10:32:47 -0400
committerAdam Midvidy <amidvidy@gmail.com>2015-10-30 15:14:06 -0400
commite62e2e71eff397caf22a0da13ac4669a8546b298 (patch)
treed170510044130c0c8e34950387b4afac957f097b
parentcbc6a790dc4ac537b071626dff77d0073512690c (diff)
downloadmongo-e62e2e71eff397caf22a0da13ac4669a8546b298.tar.gz
SERVER-20609 use getFields instead of calling getField 4x
-rw-r--r--src/mongo/bson/bson_obj_test.cpp27
-rw-r--r--src/mongo/bson/bsonobj.h29
-rw-r--r--src/mongo/db/commands.cpp6
-rw-r--r--src/mongo/db/commands.h4
-rw-r--r--src/mongo/db/dbcommands.cpp33
-rw-r--r--src/mongo/db/pipeline/pipeline.cpp2
-rw-r--r--src/mongo/db/query/lite_parsed_query.cpp6
-rw-r--r--src/mongo/db/query/lite_parsed_query.h9
-rw-r--r--src/mongo/db/s/operation_shard_version.cpp18
-rw-r--r--src/mongo/db/s/operation_shard_version.h3
-rw-r--r--src/mongo/s/client/shard_registry.cpp2
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)) {