From 49516d5099459e4d906b311a712d62e7c2c32644 Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang Date: Mon, 14 Oct 2024 00:36:34 +0800 Subject: [PATCH 1/2] Add NonreflectableMessage See https://github.com/apache/brpc/pull/2722#issuecomment-2272559689 inspired by unreflectable_message of @oathdruid. --- src/brpc/message_helper.h | 32 +++++ src/brpc/nonreflectable_message.h | 200 ++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 src/brpc/message_helper.h create mode 100644 src/brpc/nonreflectable_message.h diff --git a/src/brpc/message_helper.h b/src/brpc/message_helper.h new file mode 100644 index 0000000000..a910890067 --- /dev/null +++ b/src/brpc/message_helper.h @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#ifndef BRPC_MESSAGE_HELPER_H +#define BRPC_MESSAGE_HELPER_H + +#include "brpc/nonreflectable_message.h" + +namespace brpc { + +template +struct MessageHelper { + using BaseType = NonreflectableMessage; +}; + +} // namespace brpc + +#endif // BRPC_MESSAGE_HELPER_H diff --git a/src/brpc/nonreflectable_message.h b/src/brpc/nonreflectable_message.h new file mode 100644 index 0000000000..db69a95f2b --- /dev/null +++ b/src/brpc/nonreflectable_message.h @@ -0,0 +1,200 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#ifndef BRPC_NONREFLECTABLE_MESSAGE_H +#define BRPC_NONREFLECTABLE_MESSAGE_H + +#include + +namespace brpc { + +// +// In bRPC, some non-Protobuf based protocol messages are also designed to implement +// Protobuf Message interfaces, to provide a unified protocol message. +// The API of Protobuf Message changes frequently, and these non-Protobuf based protocol +// messages do not rely on the reflection functionality of Protobuf. +// +// NonreflectableMessage is designed to isolate upstream API changes and +// provides basic implementations to simplify the adaptation process. +// +// Function implementations are kept order with the upstream, +// and use only #if version_check #endif, to make maintenance easier. +// +template +class NonreflectableMessage : public ::google::protobuf::Message { +public: +#if GOOGLE_PROTOBUF_VERSION < 3019000 + Message* New() const override { + return new T(); + } +#endif + +#if GOOGLE_PROTOBUF_VERSION >= 3000000 + Message* New(::google::protobuf::Arena* arena) const override { + return ::google::protobuf::Arena::Create(arena); + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 3021000 + void CopyFrom(const ::google::protobuf::Message& other) override { + if (&other == this) { + return; + } + Clear(); + MergeFrom(other); + } +#endif + + inline void CopyFrom(const NonreflectableMessage& other) { + if (&other == this) { + return; + } + Clear(); + MergeFrom(other); + } + +#if GOOGLE_PROTOBUF_VERSION < 5026000 + void MergeFrom(const ::google::protobuf::Message& other) override { + if (&other == this) { + return; + } + + // Cross-type merging is meaningless, call implementation of subclass +#if GOOGLE_PROTOBUF_VERSION >= 3007000 + const T* same_type_other = ::google::protobuf::DynamicCastToGenerated(&other); +#elif GOOGLE_PROTOBUF_VERSION >= 3000000 + const T* same_type_other = ::google::protobuf::internal::DynamicCastToGenerated(&other); +#endif // GOOGLE_PROTOBUF_VERSION + if (same_type_other != nullptr) { + MergeFrom(*same_type_other); + } else { + Message::MergeFrom(other); + } + } +#endif // member function closure + + virtual void MergeFrom(const T&) = 0; + +#if GOOGLE_PROTOBUF_VERSION > 3019000 && GOOGLE_PROTOBUF_VERSION < 5026000 + // Unsupported by default. + std::string InitializationErrorString() const override { + return "unknown error"; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 3019000 + // Unsupported by default. + void DiscardUnknownFields() override {} +#endif + +#if GOOGLE_PROTOBUF_VERSION < 5026000 + // Unsupported by default. + size_t SpaceUsedLong() const override { + return 0; + } +#endif + + // Unsupported by default. + ::std::string GetTypeName() const override { + return {}; + } + + void Clear() override {} + +#if GOOGLE_PROTOBUF_VERSION < 3010000 + bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream*) override { + return true; + } +#endif + + // Quickly check if all required fields have values set. + // Unsupported by default. + bool IsInitialized() const override { + return true; + } + +#if GOOGLE_PROTOBUF_VERSION >= 3010000 && GOOGLE_PROTOBUF_VERSION <= 5026000 + const char* _InternalParse( + const char* ptr, ::google::protobuf::internal::ParseContext*) override { + return ptr; + } +#endif + + // Size of bytes after serialization. + size_t ByteSizeLong() const override { + return 0; + } + +#if GOOGLE_PROTOBUF_VERSION >= 3007000 && GOOGLE_PROTOBUF_VERSION < 3010000 + void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream*) const override {} +#endif + +#if GOOGLE_PROTOBUF_VERSION >= 3010000 && GOOGLE_PROTOBUF_VERSION < 3011000 + uint8_t* InternalSerializeWithCachedSizesToArray( + uint8_t* ptr, ::google::protobuf::io::EpsCopyOutputStream*) const override { + return ptr; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION >= 3011000 + uint8_t* _InternalSerialize( + uint8_t* ptr, ::google::protobuf::io::EpsCopyOutputStream*) const override { + return ptr; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 4025000 + // Unnecessary for Nonreflectable message. + int GetCachedSize() const override { + return 0; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 4025000 + // Unnecessary for Nonreflectable message. + void SetCachedSize(int) const override {} +#endif + +public: + // Only can be used to determine whether the Types are the same. + ::google::protobuf::Metadata GetMetadata() const override { + ::google::protobuf::Metadata metadata{}; + // can only be used to + metadata.descriptor = reinterpret_cast(&_instance); + metadata.reflection = reinterpret_cast(&_instance); + return metadata; + } + + // Only can be used to determine whether the Types are the same. + inline static const ::google::protobuf::Descriptor* descriptor() noexcept { + return default_instance().GetMetadata().descriptor; + } + + inline static const T& default_instance() noexcept { + return _instance; + } + +private: + static T _instance; +}; + +template +T NonreflectableMessage::_instance; + +} // namespace brpc + +#endif // BRPC_NONREFLECTABLE_MESSAGE_H From fb2a47783dc9804c76b9e4d5b4bc32a95029d916 Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang Date: Mon, 14 Oct 2024 01:10:50 +0800 Subject: [PATCH 2/2] Simplify EspMessage implementation by derived from NonreflectableMessage --- src/brpc/esp_head.h | 2 + src/brpc/esp_message.cpp | 83 ++-------------------------------------- src/brpc/esp_message.h | 45 ++++------------------ 3 files changed, 12 insertions(+), 118 deletions(-) diff --git a/src/brpc/esp_head.h b/src/brpc/esp_head.h index b882ff90c6..c5d9cc1fdf 100644 --- a/src/brpc/esp_head.h +++ b/src/brpc/esp_head.h @@ -18,6 +18,8 @@ #ifndef BRPC_ESP_HEAD_H #define BRPC_ESP_HEAD_H +#include + namespace brpc { #pragma pack(push, r1, 1) diff --git a/src/brpc/esp_message.cpp b/src/brpc/esp_message.cpp index 0c17c181e4..a9e82f8c16 100644 --- a/src/brpc/esp_message.cpp +++ b/src/brpc/esp_message.cpp @@ -17,22 +17,14 @@ #include "esp_message.h" -#include // ReflectionOps::Merge -#include // WireFormatLite::GetTagWireType - +#include "brpc/proto_base.pb.h" #include "butil/logging.h" namespace brpc { EspMessage::EspMessage() - : ::google::protobuf::Message() { - SharedCtor(); -} - -EspMessage::EspMessage(const EspMessage& from) - : ::google::protobuf::Message() { + : MessageHelper::BaseType() { SharedCtor(); - MergeFrom(from); } void EspMessage::SharedCtor() { @@ -50,83 +42,21 @@ const ::google::protobuf::Descriptor* EspMessage::descriptor() { return EspMessageBase::descriptor(); } -EspMessage* EspMessage::New() const { - return new EspMessage; -} - -#if GOOGLE_PROTOBUF_VERSION >= 3006000 -EspMessage* EspMessage::New(::google::protobuf::Arena* arena) const { - return CreateMaybeMessage(arena); -} -#endif - void EspMessage::Clear() { head.body_len = 0; body.clear(); } -bool EspMessage::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false - ::google::protobuf::uint32 tag; - - while ((tag = input->ReadTag()) != 0) { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - return true; - } - } - return true; -#undef DO_ -} - -void EspMessage::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream*) const { -} - -::google::protobuf::uint8* EspMessage::SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* target) const { - return target; -} - -int EspMessage::ByteSize() const { +size_t EspMessage::ByteSizeLong() const { return sizeof(head) + body.size(); } -void EspMessage::MergeFrom(const ::google::protobuf::Message& from) { - CHECK_NE(&from, this); - const EspMessage* source = dynamic_cast(&from); - if (source == NULL) { - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - MergeFrom(*source); - } -} - void EspMessage::MergeFrom(const EspMessage& from) { CHECK_NE(&from, this); head = from.head; body = from.body; } -void EspMessage::CopyFrom(const ::google::protobuf::Message& from) { - if (&from == this) { - return; - } - - Clear(); - MergeFrom(from); -} - -void EspMessage::CopyFrom(const EspMessage& from) { - if (&from == this) { - return; - } - - Clear(); - MergeFrom(from); -} - bool EspMessage::IsInitialized() const { return true; } @@ -140,11 +70,4 @@ void EspMessage::Swap(EspMessage* other) { } } -::google::protobuf::Metadata EspMessage::GetMetadata() const { - ::google::protobuf::Metadata metadata; - metadata.descriptor = EspMessage::descriptor(); - metadata.reflection = NULL; - return metadata; -} - } // namespace brpc diff --git a/src/brpc/esp_message.h b/src/brpc/esp_message.h index aecc837cb8..cf4ab24aa4 100644 --- a/src/brpc/esp_message.h +++ b/src/brpc/esp_message.h @@ -18,64 +18,33 @@ #ifndef BRPC_ESP_MESSAGE_H #define BRPC_ESP_MESSAGE_H -#include - -#include -#include // dynamic_cast_if_available -#include // ReflectionOps::Merge - #include "brpc/esp_head.h" -#include "butil/iobuf.h" -#include "brpc/proto_base.pb.h" -#include "brpc/pb_compat.h" +#include "brpc/message_helper.h" +#include "butil/iobuf.h" namespace brpc { -class EspMessage : public ::google::protobuf::Message { +class EspMessage : public MessageHelper::BaseType { public: EspHead head; butil::IOBuf body; public: EspMessage(); - virtual ~EspMessage(); - - EspMessage(const EspMessage& from); - - inline EspMessage& operator=(const EspMessage& from) { - CopyFrom(from); - return *this; - } + ~EspMessage() override; static const ::google::protobuf::Descriptor* descriptor(); - static const EspMessage& default_instance(); void Swap(EspMessage* other); // implements Message ---------------------------------------------- - EspMessage* New() const PB_319_OVERRIDE; -#if GOOGLE_PROTOBUF_VERSION >= 3006000 - EspMessage* New(::google::protobuf::Arena* arena) const override; -#endif - void CopyFrom(const ::google::protobuf::Message& from) PB_321_OVERRIDE; - void MergeFrom(const ::google::protobuf::Message& from) override; - void CopyFrom(const EspMessage& from); - void MergeFrom(const EspMessage& from); + void MergeFrom(const EspMessage& from) override; void Clear() override; bool IsInitialized() const override; - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) PB_310_OVERRIDE; - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* output) const PB_310_OVERRIDE; - int GetCachedSize() const PB_422_OVERRIDE { return ByteSize(); } - -protected: - ::google::protobuf::Metadata GetMetadata() const override; + size_t ByteSizeLong() const override; + int GetCachedSize() const override { return static_cast(ByteSizeLong()); } private: void SharedCtor();