summaryrefslogtreecommitdiff
path: root/src/mongo/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/rpc')
-rw-r--r--src/mongo/rpc/SConscript2
-rw-r--r--src/mongo/rpc/metadata/client_metadata.cpp9
-rw-r--r--src/mongo/rpc/metadata/client_metadata.h27
-rw-r--r--src/mongo/rpc/metadata/client_metadata_test.cpp72
-rw-r--r--src/mongo/rpc/op_legacy_integration_test.cpp20
-rw-r--r--src/mongo/rpc/op_msg.cpp2
-rw-r--r--src/mongo/rpc/op_msg_test.h2
7 files changed, 119 insertions, 15 deletions
diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript
index 5fa4e0bf85b..10d73388ce1 100644
--- a/src/mongo/rpc/SConscript
+++ b/src/mongo/rpc/SConscript
@@ -40,6 +40,7 @@ protoEnv.Library(
'$BUILD_DIR/mongo/db/wire_version',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/bson/bson_validate',
'$BUILD_DIR/mongo/bson/util/bson_extract',
'$BUILD_DIR/mongo/db/auth/security_token',
'$BUILD_DIR/mongo/db/bson/dotted_path_support',
@@ -64,6 +65,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/bson/bson_validate',
'$BUILD_DIR/mongo/db/dbmessage',
'$BUILD_DIR/mongo/db/server_options_core',
'$BUILD_DIR/mongo/db/stats/counters',
diff --git a/src/mongo/rpc/metadata/client_metadata.cpp b/src/mongo/rpc/metadata/client_metadata.cpp
index 33d3e5836c1..8ac4f4a9d97 100644
--- a/src/mongo/rpc/metadata/client_metadata.cpp
+++ b/src/mongo/rpc/metadata/client_metadata.cpp
@@ -269,6 +269,7 @@ Status ClientMetadata::validateOperatingSystemDocument(const BSONObj& doc) {
void ClientMetadata::setMongoSMetadata(StringData hostAndPort,
StringData mongosClient,
StringData version) {
+ _documentWithoutMongosInfo = _document;
BSONObjBuilder builder;
builder.appendElements(_document);
@@ -381,6 +382,14 @@ const BSONObj& ClientMetadata::getDocument() const {
return _document;
}
+unsigned long ClientMetadata::hashWithoutMongosInfo() const {
+ return _hashWithoutMongos.get(documentWithoutMongosInfo());
+}
+
+const BSONObj& ClientMetadata::documentWithoutMongosInfo() const {
+ return _documentWithoutMongosInfo.get(_document);
+}
+
void ClientMetadata::logClientMetadata(Client* client) const {
if (getDocument().isEmpty()) {
return;
diff --git a/src/mongo/rpc/metadata/client_metadata.h b/src/mongo/rpc/metadata/client_metadata.h
index 30f7643bcae..0c5cabdae7b 100644
--- a/src/mongo/rpc/metadata/client_metadata.h
+++ b/src/mongo/rpc/metadata/client_metadata.h
@@ -36,6 +36,8 @@
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/bson/simple_bsonobj_comparator.h"
+#include "mongo/db/query/util/deferred.h"
namespace mongo {
@@ -287,6 +289,21 @@ public:
const BSONObj& getDocument() const;
/**
+ * A lazily computed (and subsequently cached) copy of the metadata with the mongos info
+ * removed. This is useful for collecting query stats where we want to scrub out this
+ * high-cardinality field, and we don't want to re-do this computation over and over again.
+ */
+ const BSONObj& documentWithoutMongosInfo() const;
+
+ /**
+ * Get the simple hash of the client metadata document (simple meaning no collation).
+ *
+ * The hash is generated on the first call to this method. Future calls will return the cached
+ * hash rather than recomputing.
+ */
+ unsigned long hashWithoutMongosInfo() const;
+
+ /**
* Log client and client metadata information to disk.
*/
void logClientMetadata(Client* client) const;
@@ -337,6 +354,16 @@ private:
// Application Name extracted from the client metadata document.
// May be empty
std::string _appName;
+
+ // See documentWithoutMongosInfo().
+ Deferred<BSONObj, const BSONObj&> _documentWithoutMongosInfo{
+ [](const BSONObj& fullDocument) { return fullDocument.removeField("mongos"); }};
+
+ // See hashWithoutMongosInfo().
+ Deferred<unsigned long, const BSONObj&> _hashWithoutMongos{
+ [](const BSONObj& documentWithoutMongosInfo) {
+ return simpleHash(documentWithoutMongosInfo);
+ }};
};
} // namespace mongo
diff --git a/src/mongo/rpc/metadata/client_metadata_test.cpp b/src/mongo/rpc/metadata/client_metadata_test.cpp
index becb3af5698..4b698aa3a14 100644
--- a/src/mongo/rpc/metadata/client_metadata_test.cpp
+++ b/src/mongo/rpc/metadata/client_metadata_test.cpp
@@ -308,16 +308,17 @@ TEST(ClientMetadataTest, TestMongoSAppend) {
auto obj = builder.obj();
auto swParseStatus = ClientMetadata::parse(obj[kMetadataDoc]);
ASSERT_OK(swParseStatus.getStatus());
- ASSERT_EQUALS("g", swParseStatus.getValue().get().getApplicationName());
+ auto metaObj = swParseStatus.getValue().value();
+ ASSERT_EQUALS("g", metaObj.getApplicationName());
+ auto docBeforeMongos = obj[kMetadataDoc].Obj();
+ ASSERT_BSONOBJ_EQ(metaObj.getDocument(), docBeforeMongos);
- swParseStatus.getValue().get().setMongoSMetadata("h", "i", "j");
- ASSERT_EQUALS("g", swParseStatus.getValue().get().getApplicationName());
+ metaObj.setMongoSMetadata("h", "i", "j");
+ ASSERT_BSONOBJ_NE(metaObj.getDocument(), docBeforeMongos);
+ ASSERT_EQUALS("g", metaObj.getApplicationName());
- auto doc = swParseStatus.getValue().get().getDocument();
-
- constexpr auto kMongos = "mongos"_sd;
- constexpr auto kClient = "client"_sd;
- constexpr auto kHost = "host"_sd;
+ auto docWithMongosInfo = metaObj.getDocument();
+ ASSERT_BSONOBJ_EQ(metaObj.documentWithoutMongosInfo(), docBeforeMongos);
auto pid = ProcessId::getCurrent().toString();
@@ -340,7 +341,60 @@ TEST(ClientMetadataTest, TestMongoSAppend) {
.append(kMongos,
BOB{}.append(kHost, "h").append(kClient, "i").append(kVersion, "j").obj())
.obj();
- ASSERT_BSONOBJ_EQ(doc, outDoc);
+ ASSERT_BSONOBJ_EQ(docWithMongosInfo, outDoc);
+}
+
+// Test that if mongos information is present from the beginning, we can still request the document
+// without the mongos info.
+TEST(ClientMetadataTest, MongosMetaCanBeRemoved) {
+ BSONObjBuilder realBuilder;
+ BSONObjBuilder tmpBuilder;
+ ASSERT_OK(ClientMetadata::serializePrivate("a", "b", "c", "d", "e", "f", "g", &tmpBuilder));
+ auto objWithoutMongosMeta = tmpBuilder.obj();
+ const auto metaBsonNoMongosInfo = objWithoutMongosMeta[kMetadataDoc].Obj();
+ {
+ BSONObjBuilder metaBuilder = realBuilder.subobjStart(kMetadataDoc);
+ metaBuilder.appendElements(metaBsonNoMongosInfo);
+ metaBuilder.append("mongos", BSON(kHost << "h" << kClient << "i" << kVersion << "j"));
+ metaBuilder.doneFast();
+ }
+
+ const auto wrappingMetaBson = realBuilder.obj();
+ const auto metaElt = wrappingMetaBson[kMetadataDoc];
+ // Add this mongos info without calling 'setMongoSMetadata().'
+ ASSERT_BSONOBJ_NE(metaElt.Obj(), metaBsonNoMongosInfo);
+
+ auto swParseStatus = ClientMetadata::parse(metaElt);
+ ASSERT_OK(swParseStatus.getStatus());
+ const auto& metaObj = swParseStatus.getValue().value();
+ // Test the various copy/move constructors.
+ ClientMetadata copyConstructed(metaObj);
+ auto tmpThirdCopy = metaObj;
+ ClientMetadata moveConstructed(std::move(tmpThirdCopy));
+
+ auto tmpFourthCopy = metaObj;
+ auto moveAssigned = metaObj; // copy for now, until next line.
+ moveAssigned = std::move(tmpFourthCopy);
+
+ const auto tmpFifthCopy = metaObj;
+ auto copyAssigned = metaObj; // copy construct.
+ copyAssigned = tmpFifthCopy; // copy assign.
+
+ ASSERT_BSONOBJ_EQ(metaObj.getDocument(), metaElt.Obj());
+ ASSERT_BSONOBJ_EQ(metaObj.documentWithoutMongosInfo(), metaBsonNoMongosInfo);
+ ASSERT_BSONOBJ_EQ(metaObj.documentWithoutMongosInfo(),
+ copyConstructed.documentWithoutMongosInfo());
+ ASSERT_BSONOBJ_EQ(metaObj.documentWithoutMongosInfo(),
+ moveConstructed.documentWithoutMongosInfo());
+ ASSERT_BSONOBJ_EQ(metaObj.documentWithoutMongosInfo(),
+ copyAssigned.documentWithoutMongosInfo());
+ ASSERT_BSONOBJ_EQ(metaObj.documentWithoutMongosInfo(),
+ moveAssigned.documentWithoutMongosInfo());
+
+ ASSERT_EQ(metaObj.hashWithoutMongosInfo(), copyConstructed.hashWithoutMongosInfo());
+ ASSERT_EQ(metaObj.hashWithoutMongosInfo(), moveConstructed.hashWithoutMongosInfo());
+ ASSERT_EQ(metaObj.hashWithoutMongosInfo(), copyAssigned.hashWithoutMongosInfo());
+ ASSERT_EQ(metaObj.hashWithoutMongosInfo(), moveAssigned.hashWithoutMongosInfo());
}
TEST(ClientMetadataTest, TestInvalidDocWhileSettingOpCtxMetadata) {
diff --git a/src/mongo/rpc/op_legacy_integration_test.cpp b/src/mongo/rpc/op_legacy_integration_test.cpp
index 75e56d7abfa..3722c4f1bc4 100644
--- a/src/mongo/rpc/op_legacy_integration_test.cpp
+++ b/src/mongo/rpc/op_legacy_integration_test.cpp
@@ -58,7 +58,7 @@ Message makeUnsupportedOpUpdateMessage(StringData ns, BSONObj query, BSONObj upd
return makeMessage(dbUpdate, [&](BufBuilder& b) {
const int reservedFlags = 0;
b.appendNum(reservedFlags);
- b.appendStr(ns);
+ b.appendCStr(ns);
b.appendNum(flags);
query.appendSelfToBufBuilder(b);
@@ -70,7 +70,7 @@ Message makeUnsupportedOpRemoveMessage(StringData ns, BSONObj query, int flags)
return makeMessage(dbDelete, [&](BufBuilder& b) {
const int reservedFlags = 0;
b.appendNum(reservedFlags);
- b.appendStr(ns);
+ b.appendCStr(ns);
b.appendNum(flags);
query.appendSelfToBufBuilder(b);
@@ -93,7 +93,7 @@ Message makeUnsupportedOpQueryMessage(StringData ns,
int queryOptions) {
return makeMessage(dbQuery, [&](BufBuilder& b) {
b.appendNum(queryOptions);
- b.appendStr(ns);
+ b.appendCStr(ns);
b.appendNum(nToSkip);
b.appendNum(nToReturn);
query.appendSelfToBufBuilder(b);
@@ -108,7 +108,7 @@ Message makeUnsupportedOpGetMoreMessage(StringData ns,
int flags) {
return makeMessage(dbGetMore, [&](BufBuilder& b) {
b.appendNum(flags);
- b.appendStr(ns);
+ b.appendCStr(ns);
b.appendNum(nToReturn);
b.appendNum(cursorId);
});
@@ -383,6 +383,18 @@ TEST(OpLegacy, UnsupportedOpsLogging) {
exerciseUnsupportedOps(conn.get(), "D2" /*expectedSeverity*/);
}
+TEST(OpLegacy, InvalidNs) {
+ auto conn = getIntegrationTestConnection();
+
+ auto msg = makeMessage(dbQuery, [&](BufBuilder& b) {
+ b.appendNum(0);
+ b.appendStrBytes("nonullbyte");
+ });
+ // Since our request is not able to be parsed, we don't receive a response from the server.
+ Message ignore;
+ ASSERT_THROWS(conn->call(msg, ignore), DBException);
+}
+
TEST(OpLegacy, GenericCommandViaOpQuery) {
auto conn = getIntegrationTestConnection();
diff --git a/src/mongo/rpc/op_msg.cpp b/src/mongo/rpc/op_msg.cpp
index d6a91c7a69d..8565c34c6a5 100644
--- a/src/mongo/rpc/op_msg.cpp
+++ b/src/mongo/rpc/op_msg.cpp
@@ -301,7 +301,7 @@ auto OpMsgBuilder::beginDocSequence(StringData name) -> DocSequenceBuilder {
_buf.appendStruct(Section::kDocSequence);
int sizeOffset = _buf.len();
_buf.skip(sizeof(int32_t)); // section size.
- _buf.appendStr(name, true);
+ _buf.appendCStr(name);
return DocSequenceBuilder(this, &_buf, sizeOffset);
}
diff --git a/src/mongo/rpc/op_msg_test.h b/src/mongo/rpc/op_msg_test.h
index 58f25f7417f..0e8ad918997 100644
--- a/src/mongo/rpc/op_msg_test.h
+++ b/src/mongo/rpc/op_msg_test.h
@@ -80,7 +80,7 @@ protected:
template <typename... Rest>
void append(StringData arg, Rest&&... rest) {
- buffer.appendStr(arg, /* null terminate*/ true);
+ buffer.appendCStr(arg);
append(rest...);
}