diff options
-rw-r--r-- | src/mongo/db/dbmessage.cpp | 55 | ||||
-rw-r--r-- | src/mongo/db/dbmessage.h | 37 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops.cpp | 64 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops.h | 7 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops_parsers.h | 9 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops_parsers_test.cpp | 69 | ||||
-rw-r--r-- | src/mongo/rpc/op_legacy_integration_test.cpp | 40 | ||||
-rw-r--r-- | src/mongo/rpc/protocol_fuzzer.cpp | 15 |
8 files changed, 64 insertions, 232 deletions
diff --git a/src/mongo/db/dbmessage.cpp b/src/mongo/db/dbmessage.cpp index b8d94d2f866..5a92832a108 100644 --- a/src/mongo/db/dbmessage.cpp +++ b/src/mongo/db/dbmessage.cpp @@ -138,21 +138,6 @@ T DbMessage::readAndAdvance() { return t; } -namespace { -template <typename Func> -Message makeMessage(NetworkOp op, Func&& bodyBuilder) { - BufBuilder b; - b.skip(sizeof(MSGHEADER::Layout)); - - bodyBuilder(b); - - const int size = b.len(); - auto out = Message(b.release()); - out.header().setOperation(op); - out.header().setLen(size); - return out; -} -} // namespace Message makeDeprecatedQueryMessage(StringData ns, BSONObj query, @@ -186,46 +171,6 @@ Message makeDeprecatedInsertMessage(StringData ns, const BSONObj* objs, size_t c }); } -Message makeDeprecatedUpdateMessage(StringData ns, BSONObj query, BSONObj update, int flags) { - return makeMessage(dbUpdate, [&](BufBuilder& b) { - const int reservedFlags = 0; - b.appendNum(reservedFlags); - b.appendStr(ns); - b.appendNum(flags); - - query.appendSelfToBufBuilder(b); - update.appendSelfToBufBuilder(b); - }); -} - -Message makeDeprecatedRemoveMessage(StringData ns, BSONObj query, int flags) { - return makeMessage(dbDelete, [&](BufBuilder& b) { - const int reservedFlags = 0; - b.appendNum(reservedFlags); - b.appendStr(ns); - b.appendNum(flags); - - query.appendSelfToBufBuilder(b); - }); -} - -Message makeDeprecatedKillCursorsMessage(long long cursorId) { - return makeMessage(dbKillCursors, [&](BufBuilder& b) { - b.appendNum((int)0); // reserved - b.appendNum((int)1); // number - b.appendNum(cursorId); - }); -} - -Message makeDeprecatedGetMoreMessage(StringData ns, long long cursorId, int nToReturn, int flags) { - return makeMessage(dbGetMore, [&](BufBuilder& b) { - b.appendNum(flags); - b.appendStr(ns); - b.appendNum(nToReturn); - b.appendNum(cursorId); - }); -} - DbResponse makeErrorResponseToDeprecatedOpQuery(StringData errorMsg) { BSONObjBuilder err; err.append("$err", errorMsg); diff --git a/src/mongo/db/dbmessage.h b/src/mongo/db/dbmessage.h index 63c78c261cb..822bb29ecee 100644 --- a/src/mongo/db/dbmessage.h +++ b/src/mongo/db/dbmessage.h @@ -384,6 +384,20 @@ public: } }; +template <typename Func> +Message makeMessage(NetworkOp op, Func&& bodyBuilder) { + BufBuilder b; + b.skip(sizeof(MSGHEADER::Layout)); + + bodyBuilder(b); + + const int size = b.len(); + auto out = Message(b.release()); + out.header().setOperation(op); + out.header().setLen(size); + return out; +} + /** * Builds a legacy OP_QUERY message. */ @@ -419,11 +433,6 @@ enum UpdateOptions { UpdateOption_Broadcast = 1 << 2 }; -/** - * Builds a legacy OP_UPDATE message. - */ -Message makeDeprecatedUpdateMessage(StringData ns, BSONObj query, BSONObj update, int flags = 0); - enum RemoveOptions { /** only delete one option */ RemoveOption_JustOne = 1 << 0, @@ -433,24 +442,6 @@ enum RemoveOptions { }; /** - * Builds a legacy OP_REMOVE message. - */ -Message makeDeprecatedRemoveMessage(StringData ns, BSONObj query, int flags = 0); - -/** - * Builds a legacy OP_KILLCURSORS message. - */ -Message makeDeprecatedKillCursorsMessage(long long cursorId); - -/** - * Builds a legacy OP_GET_MORE message. - */ -Message makeDeprecatedGetMoreMessage(StringData ns, - long long cursorId, - int nToReturn, - int flags = 0); - -/** * A response to a DbMessage. * * Order of fields makes DbResponse{funcReturningMessage()} valid. diff --git a/src/mongo/db/ops/write_ops.cpp b/src/mongo/db/ops/write_ops.cpp index aefe6a20a4c..5c60f26fb6c 100644 --- a/src/mongo/db/ops/write_ops.cpp +++ b/src/mongo/db/ops/write_ops.cpp @@ -182,37 +182,6 @@ write_ops::UpdateCommandRequest UpdateOp::parse(const OpMsgRequest& request) { return updateOp; } -write_ops::UpdateCommandRequest UpdateOp::parseLegacy(const Message& msgRaw) { - DbMessage msg(msgRaw); - - UpdateCommandRequest op(NamespaceString(msg.getns())); - - { - write_ops::WriteCommandRequestBase writeCommandBase; - writeCommandBase.setBypassDocumentValidation(false); - writeCommandBase.setOrdered(true); - op.setWriteCommandRequestBase(std::move(writeCommandBase)); - } - - op.setUpdates([&] { - std::vector<write_ops::UpdateOpEntry> updates; - updates.emplace_back(); - - // Legacy updates only allowed one update per operation. Layout is flags, query, update. - auto& singleUpdate = updates.back(); - const int flags = msg.pullInt(); - singleUpdate.setUpsert(flags & UpdateOption_Upsert); - singleUpdate.setMulti(flags & UpdateOption_Multi); - singleUpdate.setQ(msg.nextJsObj()); - singleUpdate.setU( - write_ops::UpdateModification::parseLegacyOpUpdateFromBSON(msg.nextJsObj())); - - return updates; - }()); - - return op; -} - write_ops::UpdateCommandReply UpdateOp::parseResponse(const BSONObj& obj) { uassertStatusOK(getStatusFromCommandResult(obj)); @@ -237,34 +206,6 @@ write_ops::DeleteCommandRequest DeleteOp::parse(const OpMsgRequest& request) { return deleteOp; } -write_ops::DeleteCommandRequest DeleteOp::parseLegacy(const Message& msgRaw) { - DbMessage msg(msgRaw); - - DeleteCommandRequest op(NamespaceString(msg.getns())); - - { - write_ops::WriteCommandRequestBase writeCommandBase; - writeCommandBase.setBypassDocumentValidation(false); - writeCommandBase.setOrdered(true); - op.setWriteCommandRequestBase(std::move(writeCommandBase)); - } - - op.setDeletes([&] { - std::vector<write_ops::DeleteOpEntry> deletes; - deletes.emplace_back(); - - // Legacy deletes only allowed one delete per operation. Layout is flags, query. - auto& singleDelete = deletes.back(); - const int flags = msg.pullInt(); - singleDelete.setMulti(!(flags & RemoveOption_JustOne)); - singleDelete.setQ(msg.nextJsObj()); - - return deletes; - }()); - - return op; -} - void DeleteOp::validate(const DeleteCommandRequest& deleteOp) { checkOpCountForCommand(deleteOp, deleteOp.getDeletes().size()); } @@ -344,11 +285,6 @@ write_ops::UpdateModification write_ops::UpdateModification::parseFromBSON(BSONE return UpdateModification(elem); } -write_ops::UpdateModification write_ops::UpdateModification::parseLegacyOpUpdateFromBSON( - const BSONObj& obj) { - return UpdateModification(obj, ClassicTag{}); -} - int write_ops::UpdateModification::objsize() const { return stdx::visit( visit_helper::Overloaded{ diff --git a/src/mongo/db/ops/write_ops.h b/src/mongo/db/ops/write_ops.h index 5fa6651bad5..5dc73cc0d49 100644 --- a/src/mongo/db/ops/write_ops.h +++ b/src/mongo/db/ops/write_ops.h @@ -38,6 +38,11 @@ namespace mongo { class InsertOp { public: static write_ops::InsertCommandRequest parse(const OpMsgRequest& request); + /** + * This is to parse OP_INSERT legacy request and deprecated and used only to parse legacy insert + * request to know how many documents need to be inserted for the purpose of monitoring. Do not + * call this method any more. + */ static write_ops::InsertCommandRequest parseLegacy(const Message& msg); static void validate(const write_ops::InsertCommandRequest& insertOp); }; @@ -45,7 +50,6 @@ public: class UpdateOp { public: static write_ops::UpdateCommandRequest parse(const OpMsgRequest& request); - static write_ops::UpdateCommandRequest parseLegacy(const Message& msg); static write_ops::UpdateCommandReply parseResponse(const BSONObj& obj); static void validate(const write_ops::UpdateCommandRequest& updateOp); }; @@ -53,7 +57,6 @@ public: class DeleteOp { public: static write_ops::DeleteCommandRequest parse(const OpMsgRequest& request); - static write_ops::DeleteCommandRequest parseLegacy(const Message& msg); static void validate(const write_ops::DeleteCommandRequest& deleteOp); }; diff --git a/src/mongo/db/ops/write_ops_parsers.h b/src/mongo/db/ops/write_ops_parsers.h index 22608793005..788ae259722 100644 --- a/src/mongo/db/ops/write_ops_parsers.h +++ b/src/mongo/db/ops/write_ops_parsers.h @@ -122,15 +122,6 @@ public: */ void serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const; - // When parsing from legacy OP_UPDATE messages, we receive the "u" field as an object. When an - // array is parsed, we receive it as an object with numeric fields names and can't differentiate - // between a user constructed object and an array. For that reason, we don't support pipeline - // style update via OP_UPDATE and 'obj' is assumed to be a classic update. - // - // If a user did send a pipeline-style update via OP_UPDATE, it would fail parsing a field - // representing an aggregation stage, due to the leading '$'' character. - static UpdateModification parseLegacyOpUpdateFromBSON(const BSONObj& obj); - int objsize() const; Type type() const; diff --git a/src/mongo/db/ops/write_ops_parsers_test.cpp b/src/mongo/db/ops/write_ops_parsers_test.cpp index e8abac496fd..7fd55f1ef32 100644 --- a/src/mongo/db/ops/write_ops_parsers_test.cpp +++ b/src/mongo/db/ops/write_ops_parsers_test.cpp @@ -444,75 +444,6 @@ TEST(LegacyWriteOpsParsers, RealMultiInsert) { } } -TEST(LegacyWriteOpsParsers, UpdateCommandRequest) { - const std::string ns = "test.foo"; - const BSONObj query = BSON("x" << 1); - const BSONObj update = BSON("$inc" << BSON("x" << 1)); - for (bool upsert : {false, true}) { - for (bool multi : {false, true}) { - auto message = makeDeprecatedUpdateMessage(ns, - query, - update, - (upsert ? UpdateOption_Upsert : 0) | - (multi ? UpdateOption_Multi : 0)); - const auto op = UpdateOp::parseLegacy(message); - ASSERT_EQ(op.getNamespace().ns(), ns); - ASSERT(!op.getWriteCommandRequestBase().getBypassDocumentValidation()); - ASSERT_EQ(op.getWriteCommandRequestBase().getOrdered(), true); - ASSERT_EQ(op.getUpdates().size(), 1u); - ASSERT_BSONOBJ_EQ(op.getUpdates()[0].getQ(), query); - ASSERT_BSONOBJ_EQ(op.getUpdates()[0].getU().getUpdateClassic(), update); - ASSERT_EQ(op.getUpdates()[0].getUpsert(), upsert); - ASSERT_EQ(op.getUpdates()[0].getMulti(), multi); - } - } -} - -// When parsing from legacy OP_UPDATE messages, we receive the "u" field as an object. When an array -// is parsed, we receive it as an object with numeric fields names and can't differentiate between a -// user constructed object and an array. For that reason, we parse as a classic-style update rather -// than as pipeline-style. -TEST(LegacyWriteOpsParsers, UpdateWithArrayUpdateFieldIsParsedAsReplacementStyleUpdate) { - const std::string ns = "test.foo"; - const BSONObj query = BSON("x" << 1); - const BSONObj update = BSON_ARRAY(BSON("$addFields" << BSON("x" << 1))); - for (bool upsert : {false, true}) { - for (bool multi : {false, true}) { - auto message = makeDeprecatedUpdateMessage(ns, - query, - update, - (upsert ? UpdateOption_Upsert : 0) | - (multi ? UpdateOption_Multi : 0)); - const auto op = UpdateOp::parseLegacy(message); - ASSERT_EQ(op.getNamespace().ns(), ns); - ASSERT(!op.getWriteCommandRequestBase().getBypassDocumentValidation()); - ASSERT_EQ(op.getWriteCommandRequestBase().getOrdered(), true); - ASSERT_EQ(op.getUpdates().size(), 1u); - ASSERT_BSONOBJ_EQ(op.getUpdates()[0].getQ(), query); - ASSERT(op.getUpdates()[0].getU().type() == - write_ops::UpdateModification::Type::kClassic); - ASSERT_BSONOBJ_EQ(op.getUpdates()[0].getU().getUpdateClassic(), update); - ASSERT_EQ(op.getUpdates()[0].getUpsert(), upsert); - ASSERT_EQ(op.getUpdates()[0].getMulti(), multi); - } - } -} - -TEST(LegacyWriteOpsParsers, Remove) { - const std::string ns = "test.foo"; - const BSONObj query = BSON("x" << 1); - for (bool multi : {false, true}) { - auto message = makeDeprecatedRemoveMessage(ns, query, (multi ? 0 : RemoveOption_JustOne)); - const auto op = DeleteOp::parseLegacy(message); - ASSERT_EQ(op.getNamespace().ns(), ns); - ASSERT(!op.getWriteCommandRequestBase().getBypassDocumentValidation()); - ASSERT_EQ(op.getWriteCommandRequestBase().getOrdered(), true); - ASSERT_EQ(op.getDeletes().size(), 1u); - ASSERT_BSONOBJ_EQ(op.getDeletes()[0].getQ(), query); - ASSERT_EQ(op.getDeletes()[0].getMulti(), multi); - } -} - /** * Test OpTime serializer and deserializer when OpTime does not have term initailized. */ diff --git a/src/mongo/rpc/op_legacy_integration_test.cpp b/src/mongo/rpc/op_legacy_integration_test.cpp index 955c681ae68..ec9f64eef36 100644 --- a/src/mongo/rpc/op_legacy_integration_test.cpp +++ b/src/mongo/rpc/op_legacy_integration_test.cpp @@ -54,6 +54,46 @@ long getDeprecatedOpCount(BSONObj serverStatus, const char* opName) { return deprecatedOpcounters ? deprecatedOpcounters[opName].Long() : 0; } +Message makeDeprecatedUpdateMessage(StringData ns, BSONObj query, BSONObj update, int flags) { + return makeMessage(dbUpdate, [&](BufBuilder& b) { + const int reservedFlags = 0; + b.appendNum(reservedFlags); + b.appendStr(ns); + b.appendNum(flags); + + query.appendSelfToBufBuilder(b); + update.appendSelfToBufBuilder(b); + }); +} + +Message makeDeprecatedRemoveMessage(StringData ns, BSONObj query, int flags) { + return makeMessage(dbDelete, [&](BufBuilder& b) { + const int reservedFlags = 0; + b.appendNum(reservedFlags); + b.appendStr(ns); + b.appendNum(flags); + + query.appendSelfToBufBuilder(b); + }); +} + +Message makeDeprecatedKillCursorsMessage(long long cursorId) { + return makeMessage(dbKillCursors, [&](BufBuilder& b) { + b.appendNum((int)0); // reserved + b.appendNum((int)1); // number + b.appendNum(cursorId); + }); +} + +Message makeDeprecatedGetMoreMessage(StringData ns, long long cursorId, int nToReturn, int flags) { + return makeMessage(dbGetMore, [&](BufBuilder& b) { + b.appendNum(flags); + b.appendStr(ns); + b.appendNum(nToReturn); + b.appendNum(cursorId); + }); +} + // Issue a find command request so we can use cursor id from it to test the deprecated getMore // and killCursors ops. int64_t getValidCursorIdFromFindCmd(DBClientBase* conn, const char* collName) { diff --git a/src/mongo/rpc/protocol_fuzzer.cpp b/src/mongo/rpc/protocol_fuzzer.cpp index 19876d0ef47..a9edfba382b 100644 --- a/src/mongo/rpc/protocol_fuzzer.cpp +++ b/src/mongo/rpc/protocol_fuzzer.cpp @@ -75,11 +75,10 @@ void doFuzzing(ConstDataRangeCursor fuzzedData) try { msg = uassertStatusOK(compression.manager.decompressMessage(msg)); } - DbMessage dbMsgObj(msg); switch (msg.operation()) { case dbMsg: { - auto request = rpc::opMsgRequestFromAnyProtocol(msg); + auto request = OpMsgRequest::parseOwned(msg); validateBSON(request.body); for (const auto& docSeq : request.sequences) { for (const auto& doc : docSeq.objs) { @@ -87,22 +86,18 @@ void doFuzzing(ConstDataRangeCursor fuzzedData) try { } } } break; - case dbUpdate: { - auto op = UpdateOp::parseLegacy(msg); - } break; case dbInsert: { auto op = InsertOp::parseLegacy(msg); } break; - case dbDelete: { - auto op = DeleteOp::parseLegacy(msg); - } case dbQuery: { + DbMessage dbMsgObj(msg); QueryMessage q(dbMsgObj); } break; - // TODO these message types don't have discrete parsers. We should move their parsing out - // of the ServiceEntryPointCommon so we can actually + // These message types don't have parsers because they are no longer supported. case dbGetMore: case dbKillCursors: + case dbDelete: + case dbUpdate: break; default: invariant(!isSupportedRequestNetworkOp(msg.operation())); |