From e5438767e7040ec5c96c074dd2f7aa70fccbd6c3 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 27 Jul 2023 16:45:13 -0700 Subject: [PATCH] [channel-args] Do not mutate the AVL if there is no change (#33905) Inserts and removals create `O(log(n))` new nodes with a persistent AVL - which is nice - but if there's ultimately no mutation even this is wasteful. Do some extra work in channel args to verify that there is indeed a mutation, otherwise continue to share the same underlying object. --- src/core/lib/channel/channel_args.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc index 1e76d6dca6d..6a74d9b1044 100644 --- a/src/core/lib/channel/channel_args.cc +++ b/src/core/lib/channel/channel_args.cc @@ -191,6 +191,9 @@ ChannelArgs ChannelArgs::Set(absl::string_view name, int value) const { } ChannelArgs ChannelArgs::Set(absl::string_view name, Value value) const { + if (const auto* p = args_.Lookup(name)) { + if (*p == value) return *this; // already have this value for this key + } return ChannelArgs(args_.Add(std::string(name), std::move(value))); } @@ -208,18 +211,17 @@ ChannelArgs ChannelArgs::Set(absl::string_view name, std::string value) const { } ChannelArgs ChannelArgs::Remove(absl::string_view name) const { + if (args_.Lookup(name) == nullptr) return *this; return ChannelArgs(args_.Remove(name)); } ChannelArgs ChannelArgs::RemoveAllKeysWithPrefix( absl::string_view prefix) const { - ChannelArgs result; - args_.ForEach([&](const std::string& key, const Value& value) { - if (!absl::StartsWith(key, prefix)) { - result.args_ = result.args_.Add(key, value); - } + auto args = args_; + args_.ForEach([&args, prefix](const std::string& key, const Value&) { + if (absl::StartsWith(key, prefix)) args = args.Remove(key); }); - return result; + return ChannelArgs(std::move(args)); } absl::optional ChannelArgs::GetInt(absl::string_view name) const {