From acc8128b76c5b0f23d00d390dbd9cacc6e9f8b76 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 May 2022 12:34:24 -0700 Subject: [PATCH] [iwyu] Further reduce metadata_batch.h footprint by moving implementations to .cc file (#29595) * Cleanup * iwyu * fix * Add flag * sweep1 * fixes * speedup * fixes * fix * fix * fix * Cleanup * Automated change: Fix sanity tests * Automated change: Fix sanity tests * fix * fix * fix * fix * fix * fix * x * x * Automated change: Fix sanity tests Co-authored-by: ctiller --- .../ext/transport/chttp2/transport/writing.cc | 1 - src/core/lib/transport/metadata_batch.cc | 258 +++++++++++++ src/core/lib/transport/metadata_batch.h | 344 +++++------------- src/core/lib/transport/parsed_metadata.h | 2 +- 4 files changed, 351 insertions(+), 254 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 2ce3aacaee1..0c0f59460fb 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -49,7 +49,6 @@ #include "src/core/lib/channel/channelz.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/debug/trace.h" -#include "src/core/lib/gprpp/chunked_vector.h" #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/ref_counted.h" diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc index 37c36a39780..15a75f83fce 100644 --- a/src/core/lib/transport/metadata_batch.cc +++ b/src/core/lib/transport/metadata_batch.cc @@ -16,13 +16,271 @@ #include "src/core/lib/transport/metadata_batch.h" +#include + +#include + #include "absl/strings/escaping.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" + +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/transport/timeout_encoding.h" namespace grpc_core { namespace metadata_detail { + void DebugStringBuilder::Add(absl::string_view key, absl::string_view value) { if (!out_.empty()) out_.append(", "); absl::StrAppend(&out_, absl::CEscape(key), ": ", absl::CEscape(value)); } + +void UnknownMap::Append(absl::string_view key, Slice value) { + unknown_.EmplaceBack(Slice::FromCopiedString(key), value.Ref()); +} + +void UnknownMap::Remove(absl::string_view key) { + unknown_.SetEnd(std::remove_if(unknown_.begin(), unknown_.end(), + [key](const std::pair& p) { + return p.first.as_string_view() == key; + })); +} + +absl::optional UnknownMap::GetStringValue( + absl::string_view key, std::string* backing) const { + absl::optional out; + for (const auto& p : unknown_) { + if (p.first.as_string_view() == key) { + if (!out.has_value()) { + out = p.second.as_string_view(); + } else { + out = *backing = absl::StrCat(*out, ",", p.second.as_string_view()); + } + } + } + return out; +} + } // namespace metadata_detail + +ContentTypeMetadata::MementoType ContentTypeMetadata::ParseMemento( + Slice value, MetadataParseErrorFn on_error) { + auto out = kInvalid; + auto value_string = value.as_string_view(); + if (value_string == "application/grpc") { + out = kApplicationGrpc; + } else if (absl::StartsWith(value_string, "application/grpc;")) { + out = kApplicationGrpc; + } else if (absl::StartsWith(value_string, "application/grpc+")) { + out = kApplicationGrpc; + } else if (value_string.empty()) { + out = kEmpty; + } else { + on_error("invalid value", value); + } + return out; +} + +StaticSlice ContentTypeMetadata::Encode(ValueType x) { + switch (x) { + case kEmpty: + return StaticSlice::FromStaticString(""); + case kApplicationGrpc: + return StaticSlice::FromStaticString("application/grpc"); + case kInvalid: + return StaticSlice::FromStaticString("application/grpc+unknown"); + } + GPR_UNREACHABLE_CODE( + return StaticSlice::FromStaticString("unrepresentable value")); +} + +const char* ContentTypeMetadata::DisplayValue(MementoType content_type) { + switch (content_type) { + case ValueType::kApplicationGrpc: + return "application/grpc"; + case ValueType::kEmpty: + return ""; + default: + return ""; + } +} + +GrpcTimeoutMetadata::MementoType GrpcTimeoutMetadata::ParseMemento( + Slice value, MetadataParseErrorFn on_error) { + auto timeout = ParseTimeout(value); + if (!timeout.has_value()) { + on_error("invalid value", value); + return Duration::Infinity(); + } + return *timeout; +} + +GrpcTimeoutMetadata::ValueType GrpcTimeoutMetadata::MementoToValue( + MementoType timeout) { + if (timeout == Duration::Infinity()) { + return Timestamp::InfFuture(); + } + return ExecCtx::Get()->Now() + timeout; +} + +Slice GrpcTimeoutMetadata::Encode(ValueType x) { + return Timeout::FromDuration(x - ExecCtx::Get()->Now()).Encode(); +} + +TeMetadata::MementoType TeMetadata::ParseMemento( + Slice value, MetadataParseErrorFn on_error) { + auto out = kInvalid; + if (value == "trailers") { + out = kTrailers; + } else { + on_error("invalid value", value); + } + return out; +} + +const char* TeMetadata::DisplayValue(MementoType te) { + switch (te) { + case ValueType::kTrailers: + return "trailers"; + default: + return ""; + } +} + +HttpSchemeMetadata::ValueType HttpSchemeMetadata::Parse( + absl::string_view value, MetadataParseErrorFn on_error) { + if (value == "http") { + return kHttp; + } else if (value == "https") { + return kHttps; + } + on_error("invalid value", Slice::FromCopiedBuffer(value)); + return kInvalid; +} + +StaticSlice HttpSchemeMetadata::Encode(ValueType x) { + switch (x) { + case kHttp: + return StaticSlice::FromStaticString("http"); + case kHttps: + return StaticSlice::FromStaticString("https"); + default: + abort(); + } +} + +const char* HttpSchemeMetadata::DisplayValue(MementoType content_type) { + switch (content_type) { + case kHttp: + return "http"; + case kHttps: + return "https"; + default: + return ""; + } +} + +HttpMethodMetadata::MementoType HttpMethodMetadata::ParseMemento( + Slice value, MetadataParseErrorFn on_error) { + auto out = kInvalid; + auto value_string = value.as_string_view(); + if (value_string == "POST") { + out = kPost; + } else if (value_string == "PUT") { + out = kPut; + } else if (value_string == "GET") { + out = kGet; + } else { + on_error("invalid value", value); + } + return out; +} + +StaticSlice HttpMethodMetadata::Encode(ValueType x) { + switch (x) { + case kPost: + return StaticSlice::FromStaticString("POST"); + case kPut: + return StaticSlice::FromStaticString("PUT"); + case kGet: + return StaticSlice::FromStaticString("GET"); + default: + abort(); + } +} + +const char* HttpMethodMetadata::DisplayValue(MementoType content_type) { + switch (content_type) { + case kPost: + return "POST"; + case kGet: + return "GET"; + case kPut: + return "PUT"; + default: + return ""; + } +} + +CompressionAlgorithmBasedMetadata::MementoType +CompressionAlgorithmBasedMetadata::ParseMemento(Slice value, + MetadataParseErrorFn on_error) { + auto algorithm = ParseCompressionAlgorithm(value.as_string_view()); + if (!algorithm.has_value()) { + on_error("invalid value", value); + return GRPC_COMPRESS_NONE; + } + return *algorithm; +} + +Duration GrpcRetryPushbackMsMetadata::ParseMemento( + Slice value, MetadataParseErrorFn on_error) { + int64_t out; + if (!absl::SimpleAtoi(value.as_string_view(), &out)) { + on_error("not an integer", value); + return Duration::NegativeInfinity(); + } + return Duration::Milliseconds(out); +} + +Slice LbCostBinMetadata::Encode(const ValueType& x) { + auto slice = + MutableSlice::CreateUninitialized(sizeof(double) + x.name.length()); + memcpy(slice.data(), &x.cost, sizeof(double)); + memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length()); + return Slice(std::move(slice)); +} + +std::string LbCostBinMetadata::DisplayValue(MementoType x) { + return absl::StrCat(x.name, ":", x.cost); +} + +LbCostBinMetadata::MementoType LbCostBinMetadata::ParseMemento( + Slice value, MetadataParseErrorFn on_error) { + if (value.length() < sizeof(double)) { + on_error("too short", value); + return {0, ""}; + } + MementoType out; + memcpy(&out.cost, value.data(), sizeof(double)); + out.name = + std::string(reinterpret_cast(value.data()) + sizeof(double), + value.length() - sizeof(double)); + return out; +} + +std::string GrpcStreamNetworkState::DisplayValue(ValueType x) { + switch (x) { + case kNotSentOnWire: + return "not sent on wire"; + case kNotSeenByServer: + return "not seen by server"; + } +} + +std::string PeerString::DisplayValue(ValueType x) { return std::string(x); } +const std::string& GrpcStatusContext::DisplayValue(const std::string& x) { + return x; +} + } // namespace grpc_core diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index 529d8283ec7..f05f7af5ed8 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -22,9 +22,7 @@ #include #include -#include -#include #include #include #include @@ -33,9 +31,7 @@ #include "absl/container/inlined_vector.h" #include "absl/functional/function_ref.h" #include "absl/meta/type_traits.h" -#include "absl/strings/match.h" #include "absl/strings/numbers.h" -#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" @@ -47,11 +43,9 @@ #include "src/core/lib/gprpp/chunked_vector.h" #include "src/core/lib/gprpp/table.h" #include "src/core/lib/gprpp/time.h" -#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/transport/parsed_metadata.h" -#include "src/core/lib/transport/timeout_encoding.h" namespace grpc_core { @@ -67,23 +61,9 @@ struct GrpcTimeoutMetadata { using ValueType = Timestamp; using MementoType = Duration; static absl::string_view key() { return "grpc-timeout"; } - static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { - auto timeout = ParseTimeout(value); - if (!timeout.has_value()) { - on_error("invalid value", value); - return Duration::Infinity(); - } - return *timeout; - } - static ValueType MementoToValue(MementoType timeout) { - if (timeout == Duration::Infinity()) { - return Timestamp::InfFuture(); - } - return ExecCtx::Get()->Now() + timeout; - } - static Slice Encode(ValueType x) { - return Timeout::FromDuration(x - ExecCtx::Get()->Now()).Encode(); - } + static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); + static ValueType MementoToValue(MementoType timeout); + static Slice Encode(ValueType x); static std::string DisplayValue(MementoType x) { return x.ToString(); } }; @@ -99,28 +79,13 @@ struct TeMetadata { }; using MementoType = ValueType; static absl::string_view key() { return "te"; } - static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { - auto out = kInvalid; - if (value == "trailers") { - out = kTrailers; - } else { - on_error("invalid value", value); - } - return out; - } + static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); static ValueType MementoToValue(MementoType te) { return te; } static StaticSlice Encode(ValueType x) { GPR_ASSERT(x == kTrailers); return StaticSlice::FromStaticString("trailers"); } - static const char* DisplayValue(MementoType te) { - switch (te) { - case ValueType::kTrailers: - return "trailers"; - default: - return ""; - } - } + static const char* DisplayValue(MementoType te); }; // content-type metadata trait. @@ -136,47 +101,13 @@ struct ContentTypeMetadata { }; using MementoType = ValueType; static absl::string_view key() { return "content-type"; } - static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { - auto out = kInvalid; - auto value_string = value.as_string_view(); - if (value_string == "application/grpc") { - out = kApplicationGrpc; - } else if (absl::StartsWith(value_string, "application/grpc;")) { - out = kApplicationGrpc; - } else if (absl::StartsWith(value_string, "application/grpc+")) { - out = kApplicationGrpc; - } else if (value_string.empty()) { - out = kEmpty; - } else { - on_error("invalid value", value); - } - return out; - } + static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); static ValueType MementoToValue(MementoType content_type) { return content_type; } - static StaticSlice Encode(ValueType x) { - switch (x) { - case kEmpty: - return StaticSlice::FromStaticString(""); - case kApplicationGrpc: - return StaticSlice::FromStaticString("application/grpc"); - case kInvalid: - return StaticSlice::FromStaticString("application/grpc+unknown"); - } - GPR_UNREACHABLE_CODE( - return StaticSlice::FromStaticString("unrepresentable value")); - } - static const char* DisplayValue(MementoType content_type) { - switch (content_type) { - case ValueType::kApplicationGrpc: - return "application/grpc"; - case ValueType::kEmpty: - return ""; - default: - return ""; - } - } + + static StaticSlice Encode(ValueType x); + static const char* DisplayValue(MementoType content_type); }; // scheme metadata trait. @@ -193,38 +124,12 @@ struct HttpSchemeMetadata { return Parse(value.as_string_view(), on_error); } static ValueType Parse(absl::string_view value, - MetadataParseErrorFn on_error) { - if (value == "http") { - return kHttp; - } else if (value == "https") { - return kHttps; - } - on_error("invalid value", Slice::FromCopiedBuffer(value)); - return kInvalid; - } + MetadataParseErrorFn on_error); static ValueType MementoToValue(MementoType content_type) { return content_type; } - static StaticSlice Encode(ValueType x) { - switch (x) { - case kHttp: - return StaticSlice::FromStaticString("http"); - case kHttps: - return StaticSlice::FromStaticString("https"); - default: - abort(); - } - } - static const char* DisplayValue(MementoType content_type) { - switch (content_type) { - case kHttp: - return "http"; - case kHttps: - return "https"; - default: - return ""; - } - } + static StaticSlice Encode(ValueType x); + static const char* DisplayValue(MementoType content_type); }; // method metadata trait. @@ -238,47 +143,12 @@ struct HttpMethodMetadata { }; using MementoType = ValueType; static absl::string_view key() { return ":method"; } - static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { - auto out = kInvalid; - auto value_string = value.as_string_view(); - if (value_string == "POST") { - out = kPost; - } else if (value_string == "PUT") { - out = kPut; - } else if (value_string == "GET") { - out = kGet; - } else { - on_error("invalid value", value); - } - return out; - } + static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); static ValueType MementoToValue(MementoType content_type) { return content_type; } - static StaticSlice Encode(ValueType x) { - switch (x) { - case kPost: - return StaticSlice::FromStaticString("POST"); - case kPut: - return StaticSlice::FromStaticString("PUT"); - case kGet: - return StaticSlice::FromStaticString("GET"); - default: - abort(); - } - } - static const char* DisplayValue(MementoType content_type) { - switch (content_type) { - case kPost: - return "POST"; - case kGet: - return "GET"; - case kPut: - return "PUT"; - default: - return ""; - } - } + static StaticSlice Encode(ValueType x); + static const char* DisplayValue(MementoType content_type); }; // Base type for metadata pertaining to a single compression algorithm @@ -286,14 +156,7 @@ struct HttpMethodMetadata { struct CompressionAlgorithmBasedMetadata { using ValueType = grpc_compression_algorithm; using MementoType = ValueType; - static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { - auto algorithm = ParseCompressionAlgorithm(value.as_string_view()); - if (!algorithm.has_value()) { - on_error("invalid value", value); - return GRPC_COMPRESS_NONE; - } - return *algorithm; - } + static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); static ValueType MementoToValue(MementoType x) { return x; } static Slice Encode(ValueType x) { GPR_ASSERT(x != GRPC_COMPRESS_ALGORITHMS_COUNT); @@ -401,9 +264,9 @@ struct HttpPathMetadata : public SimpleSliceBasedMetadata { static absl::string_view key() { return ":path"; } }; -// We separate SimpleIntBasedMetadata into two pieces: one that does not depend -// on the invalid value, and one that does. This allows the compiler to easily -// see the functions that are shared, and helps reduce code bloat here. +// We separate SimpleIntBasedMetadata into two pieces: one that does not +// depend on the invalid value, and one that does. This allows the compiler to +// easily see the functions that are shared, and helps reduce code bloat here. template struct SimpleIntBasedMetadataBase { using ValueType = Int; @@ -449,14 +312,7 @@ struct GrpcRetryPushbackMsMetadata { static ValueType MementoToValue(MementoType x) { return x; } static Slice Encode(Duration x) { return Slice::FromInt64(x.millis()); } static int64_t DisplayValue(Duration x) { return x.millis(); } - static Duration ParseMemento(Slice value, MetadataParseErrorFn on_error) { - int64_t out; - if (!absl::SimpleAtoi(value.as_string_view(), &out)) { - on_error("not an integer", value); - return Duration::NegativeInfinity(); - } - return Duration::Milliseconds(out); - } + static Duration ParseMemento(Slice value, MetadataParseErrorFn on_error); }; // :status metadata trait. @@ -499,28 +355,9 @@ struct LbCostBinMetadata { }; using MementoType = ValueType; static ValueType MementoToValue(MementoType value) { return value; } - static Slice Encode(const ValueType& x) { - auto slice = - MutableSlice::CreateUninitialized(sizeof(double) + x.name.length()); - memcpy(slice.data(), &x.cost, sizeof(double)); - memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length()); - return Slice(std::move(slice)); - } - static std::string DisplayValue(MementoType x) { - return absl::StrCat(x.name, ":", x.cost); - } - static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { - if (value.length() < sizeof(double)) { - on_error("too short", value); - return {0, ""}; - } - MementoType out; - memcpy(&out.cost, value.data(), sizeof(double)); - out.name = std::string( - reinterpret_cast(value.data()) + sizeof(double), - value.length() - sizeof(double)); - return out; - } + static Slice Encode(const ValueType& x); + static std::string DisplayValue(MementoType x); + static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); }; // Annotation added by a transport to note whether a failed request was never @@ -532,14 +369,7 @@ struct GrpcStreamNetworkState { kNotSentOnWire, kNotSeenByServer, }; - static std::string DisplayValue(ValueType x) { - switch (x) { - case kNotSentOnWire: - return "not sent on wire"; - case kNotSeenByServer: - return "not seen by server"; - } - } + static std::string DisplayValue(ValueType x); }; // Annotation added by a server transport to note the peer making a request. @@ -547,7 +377,7 @@ struct PeerString { static absl::string_view DebugKey() { return "PeerString"; } static constexpr bool kRepeatable = false; using ValueType = absl::string_view; - static std::string DisplayValue(ValueType x) { return std::string(x); } + static std::string DisplayValue(ValueType x); }; // Annotation added by various systems to describe the reason for a failure. @@ -555,7 +385,7 @@ struct GrpcStatusContext { static absl::string_view DebugKey() { return "GrpcStatusContext"; } static constexpr bool kRepeatable = true; using ValueType = std::string; - static const std::string& DisplayValue(const std::string& x) { return x; } + static const std::string& DisplayValue(const std::string& x); }; namespace metadata_detail { @@ -576,11 +406,10 @@ class DebugStringBuilder { std::string out_; }; -// IsEncodable: Given a trait, determine if that trait is encodable, or is just -// a value attached to a MetadataMap. -// We use the presence of the key() static method to determine if a trait is -// encodable or not - encodable traits have string names, and non-encodable -// traits do not. +// IsEncodable: Given a trait, determine if that trait is encodable, or is +// just a value attached to a MetadataMap. We use the presence of the key() +// static method to determine if a trait is encodable or not - encodable +// traits have string names, and non-encodable traits do not. template struct IsEncodableTrait { static const bool value = false; @@ -630,8 +459,8 @@ struct NameLookup { }; // Helper to take a slice to a memento to a value. -// By splitting this part out we can scale code size as the number of (memento, -// value) types, rather than as the number of traits. +// By splitting this part out we can scale code size as the number of +// (memento, value) types, rather than as the number of traits. template struct ParseValue { template @@ -680,8 +509,8 @@ class ParseHelper { }; // This is an "Op" type for NameLookup. -// Used for MetadataMap::Append, its Found/NotFound methods turn a slice into a -// value and add it to a container. +// Used for MetadataMap::Append, its Found/NotFound methods turn a slice into +// a value and add it to a container. template class AppendHelper { public: @@ -698,7 +527,7 @@ class AppendHelper { } GPR_ATTRIBUTE_NOINLINE void NotFound(absl::string_view key) { - container_->AppendUnknown(key, std::move(value_)); + container_->unknown_.Append(key, std::move(value_)); } private: @@ -721,7 +550,7 @@ class RemoveHelper { } GPR_ATTRIBUTE_NOINLINE void NotFound(absl::string_view key) { - container_->RemoveUnknown(key); + container_->unknown_.Remove(key); } private: @@ -729,8 +558,8 @@ class RemoveHelper { }; // This is an "Op" type for NameLookup. -// Used for MetadataMap::GetStringValue, its Found/NotFound methods generated a -// string value from the container. +// Used for MetadataMap::GetStringValue, its Found/NotFound methods generated +// a string value from the container. template class GetStringValueHelper { public: @@ -780,7 +609,7 @@ class GetStringValueHelper { GPR_ATTRIBUTE_NOINLINE absl::optional NotFound( absl::string_view key) { - return container_->GetStringValueUnknown(key, backing_); + return container_->unknown_.GetStringValue(key, backing_); } private: @@ -793,7 +622,17 @@ using LogFn = absl::FunctionRef; template struct AdaptDisplayValueToLog { - static std::string ToString(const T& value) { return absl::StrCat(value); } + static std::string ToString(const T& value) { return std::to_string(value); } +}; + +template <> +struct AdaptDisplayValueToLog { + static std::string ToString(const std::string& value) { return value; } +}; + +template <> +struct AdaptDisplayValueToLog { + static std::string ToString(const std::string& value) { return value; } }; template <> @@ -949,7 +788,7 @@ class CopySink { } void Encode(const Slice& key, const Slice& value) { - dst_->AppendUnknown(key.as_string_view(), value.Ref()); + dst_->unknown_.Append(key.as_string_view(), value.Ref()); } private: @@ -1005,6 +844,31 @@ class TransportSizeEncoder { uint32_t size_ = 0; }; +// Handle unknown (non-trait-based) fields in the metadata map. +class UnknownMap { + public: + explicit UnknownMap(Arena* arena) : unknown_(arena) {} + + using BackingType = ChunkedVector, 10>; + + void Append(absl::string_view key, Slice value); + void Remove(absl::string_view key); + absl::optional GetStringValue(absl::string_view key, + std::string* backing) const; + + BackingType::ConstForwardIterator begin() const { return unknown_.cbegin(); } + BackingType::ConstForwardIterator end() const { return unknown_.cend(); } + + bool empty() const { return unknown_.empty(); } + size_t size() const { return unknown_.size(); } + void Clear() { unknown_.Clear(); } + Arena* arena() const { return unknown_.arena(); } + + private: + // Backing store for added metadata. + ChunkedVector, 10> unknown_; +}; + } // namespace metadata_detail // Helper function for encoders @@ -1065,21 +929,23 @@ MetadataValueAsSlice(typename Which::ValueType value) { // // Parse a memento from a slice // // Takes ownership of value // // Calls fn in the case of an error that should be reported to the user -// static MementoType ParseMemento(Slice value, MementoParseErrorFn fn) { ... +// static MementoType ParseMemento(Slice value, MementoParseErrorFn fn) { +// ... // } // // Convert a memento to a value // static ValueType MementoToValue(MementoType memento) { ... } // // Convert a value to its canonical text wire format (the format that // // ParseMemento will accept!) // static Slice Encode(const ValueType& value); -// // Convert a value to something that can be passed to StrCat and displayed +// // Convert a value to something that can be passed to StrCat and +// displayed // // for debugging // static SomeStrCatableType DisplayValue(MementoType value) { ... } // }; // -// Non-encodable traits are determined by missing the key() method, and have the -// following signature (and by convention omit the Metadata part of the type -// name): +// Non-encodable traits are determined by missing the key() method, and have +// the following signature (and by convention omit the Metadata part of the +// type name): // // Traits for the GrpcXyz field: // struct GrpcXyz { // // The string key that should be used for debug dumps - should not be a @@ -1089,7 +955,8 @@ MetadataValueAsSlice(typename Which::ValueType value) { // static constexpr bool kRepeatable = ...; // // The type that's stored on MetadataBatch // using ValueType = ...; -// // Convert a value to something that can be passed to StrCat and displayed +// // Convert a value to something that can be passed to StrCat and +// displayed // // for debugging // static SomeStrCatableType DisplayValue(ValueType value) { ... } // }; @@ -1102,10 +969,10 @@ MetadataValueAsSlice(typename Which::ValueType value) { // in the compression table. This is what mementos are used for. // // A trait offers the capability to turn a slice into a memento via -// ParseMemento. This is exposed to users of MetadataMap via the Parse() method, -// that returns a ParsedMetadata object. That ParsedMetadata object can in turn -// be used to set the same value on many different MetadataMaps without having -// to reparse. +// ParseMemento. This is exposed to users of MetadataMap via the Parse() +// method, that returns a ParsedMetadata object. That ParsedMetadata object +// can in turn be used to set the same value on many different MetadataMaps +// without having to reparse. // // Implementation wise, ParsedMetadata is a type erased wrapper around // MementoType. When we set a value on MetadataMap, we first turn that memento @@ -1309,36 +1176,9 @@ class MetadataMap { template using Value = metadata_detail::Value; - void AppendUnknown(absl::string_view key, Slice value) { - unknown_.EmplaceBack(Slice::FromCopiedString(key), value.Ref()); - } - - void RemoveUnknown(absl::string_view key) { - unknown_.SetEnd(std::remove_if(unknown_.begin(), unknown_.end(), - [key](const std::pair& p) { - return p.first.as_string_view() == key; - })); - } - - absl::optional GetStringValueUnknown( - absl::string_view key, std::string* backing) const { - absl::optional out; - for (const auto& p : unknown_) { - if (p.first.as_string_view() == key) { - if (!out.has_value()) { - out = p.second.as_string_view(); - } else { - out = *backing = absl::StrCat(*out, ",", p.second.as_string_view()); - } - } - } - return out; - } - // Table of known metadata types. Table...> table_; - // Backing store for added metadata. - ChunkedVector, 10> unknown_; + metadata_detail::UnknownMap unknown_; }; // Ok/not-ok check for metadata maps that contain GrpcStatusMetadata, so that @@ -1356,8 +1196,8 @@ template MetadataMap::MetadataMap(MetadataMap&& other) noexcept : table_(std::move(other.table_)), unknown_(std::move(other.unknown_)) {} -// We never create MetadataMap directly, instead we create Derived, but we want -// to be able to move it without redeclaring this. +// We never create MetadataMap directly, instead we create Derived, but we +// want to be able to move it without redeclaring this. // NOLINTNEXTLINE(misc-unconventional-assign-operator) template Derived& MetadataMap::operator=( diff --git a/src/core/lib/transport/parsed_metadata.h b/src/core/lib/transport/parsed_metadata.h index efc45087aa3..82f13500aeb 100644 --- a/src/core/lib/transport/parsed_metadata.h +++ b/src/core/lib/transport/parsed_metadata.h @@ -378,7 +378,7 @@ ParsedMetadata::KeyValueVTable(absl::string_view key) { }; static const auto set = [](const Buffer& value, MetadataContainer* map) { auto* p = static_cast(value.pointer); - map->AppendUnknown(p->first.as_string_view(), p->second.Ref()); + map->unknown_.Append(p->first.as_string_view(), p->second.Ref()); }; static const auto with_new_value = [](Slice* value, MetadataParseErrorFn, ParsedMetadata* result) {