diff options
Diffstat (limited to 'src/mongo/rpc')
| -rw-r--r-- | src/mongo/rpc/SConscript | 2 | ||||
| -rw-r--r-- | src/mongo/rpc/metadata/client_metadata.cpp | 9 | ||||
| -rw-r--r-- | src/mongo/rpc/metadata/client_metadata.h | 27 | ||||
| -rw-r--r-- | src/mongo/rpc/metadata/client_metadata_test.cpp | 72 | ||||
| -rw-r--r-- | src/mongo/rpc/op_legacy_integration_test.cpp | 20 | ||||
| -rw-r--r-- | src/mongo/rpc/op_msg.cpp | 2 | ||||
| -rw-r--r-- | src/mongo/rpc/op_msg_test.h | 2 |
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...); } |
